Redis和Memcached的区别( 三 )


请点击输入图片描述
当Memcached接收到客户端发送过来的数据时首先会根据收到数据的大小选择一个最合适的Slab Class,然后通过查询Memcached保存着的该Slab Class内空闲Chunk的列表就可以找到一个可用于存储数据的Chunk 。当一条数据库过期或者丢弃时,该记录所占用的Chunk就可以回收,重新添加到空闲列表中 。从以上过程我们可以看出Memcached的内存管理制效率高,而且不会造成内存碎片,但是它最大的缺点就是会导致空间浪费 。因为每个Chunk都分配了特定长度的内存空间,所以变长数据无法充分利用这些空间 。如图 所示,将100个字节的数据缓存到128个字节的Chunk中,剩余的28个字节就浪费掉了 。
请点击输入图片描述
Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的 。Redis为了方便内存的管理,在分配一块内存之后,会将这块内存的大小存入内存块的头部 。如图所示,real_ptr是redis调用malloc后返回的指针 。redis将内存块的大小size存入头部,size所占据的内存大小是已知的,为size_t类型的长度,然后返回ret_ptr 。当需要释放内存的时候,ret_ptr被传给内存管理程序 。通过ret_ptr,程序可以很容易的算出real_ptr的值,然后将real_ptr传给free释放内存 。
请点击输入图片描述
Redis通过定义一个数组来记录所有的内存分配情况,这个数组的长度为ZMALLOC_MAX_ALLOC_STAT 。数组的每一个元素代表当前程序所分配的内存块的个数,且内存块的大小为该元素的下标 。在源码中,这个数组为zmalloc_allocations 。zmalloc_allocations[16]代表已经分配的长度为16bytes的内存块的个数 。zmalloc.c中有一个静态变量used_memory用来记录当前分配的内存总大小 。所以,总的来看,Redis采用的是包装的mallc/free,相较于Memcached的内存管理方法来说,要简单很多 。
3、数据持久化支持
Redis虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB快照和AOF日志 。而memcached是不支持数据持久化操作的 。
1)RDB快照
Redis支持将当前数据的快照存成一个数据文件的持久化机制,即RDB快照 。但是一个持续写入的数据库如何生成快照呢?Redis借助了fork命令的copy on write机制 。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件 。我们可以通过Redis的save指令来配置RDB快照生成的时机,比如配置10分钟就生成快照,也可以配置有1000次写入就生成快照,也可以多个规则一起实施 。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis 。
Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的 。同时,Redis的RDB文件也是Redis主从同步内部实现中的一环 。RDB有他的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了 。在某些业务下,这是可以忍受的 。
2)AOF日志
AOF日志的全称是append only file,它是一个追加写入的日志文件 。与一般数据库的binlog不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令 。只有那些会导致数据发生修改的命令才会追加到AOF文件 。每一条修改数据的命令都生成一条日志,AOF文件会越来越大,所以Redis又提供了一个功能,叫做AOF rewrite 。其功能就是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作 。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件 。在写入新文件的过程中,所有的写操作日志还是会写到原来老的AOF文件中,同时还会记录在内存缓冲区中 。当重完操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中 。然后调用原子性的rename命令用新的AOF文件取代老的AOF文件 。

推荐阅读