Redis源码解析4 - 数据类型之 String & List

STRING

(转载请注明出处:http://www.cnblogs.com/curve/archive/2012/09/18/2689132.html

string类型的数据在Redis中有两种编码方式:

1. RAW
    这表示一个原始字符串对象,robj中的ptr指针指向一个sds类型的内存块
    sds是一个带长度信息的内存块,用于存储二进制安全的字符串

2. INT
    这表示一个编码为整数的字符串对象,robj中的ptr指针被强行转化为一个long型变量以存储整数
    数字类型的字符串,比如“123456”,都会被编码为整型
    这样做的目的就一点,节省内存。就以字符串“123456”为例,
    (1) 存为RAW类型,共消耗内存为:sizeof(robj) + sizeof(sdshdr) + strlen("123456")
         32位系统为26字节,64位系统下为30字节
    (2) 存为INT类型,共消耗内存为:sizeof(robj)
         32位系统为12字节,64位系统下为16字节

    可以看出,节省的内存还是挺多的
    如果字符串更长一些,比如“123456789”,节省的内存就可观了

    一点小提示,在Redis中,64位的bigint,是按RAW格式存储的
    之所以这么做,完全是为了兼容不同的系统
    在实际使用中,如果你确定你的机器都是64位的(MS现在很少32位机了),可以改改源代码,多节省一些内存
 


 

再加一幅图,更直观的说明一下

   

OK,在Redis中,String是最基本的类型,也很简单,从上图可以较清晰的看出String的组织方式了

题外话,不知道有同学注意到没有,robj中的ptr居然是指向sdshdr内存块的中间部分,而不是指向内存头

从这一点看,Redis的代码也挺“野”的


 

LIST

list数据有两种编码方式:

 

1. linked_list
   
这就是一个传统的双向链表,带头尾指针,其头尾操作都只有O(1)的复杂度
    

 

2. ziplist
    这是一种压缩编码的链表,它将所有的链表数据全部整合进一整块内存中,相比传统的链表,节省很多内存

 

简要说明一下上图:

(1) ziplist使用一整块连续的内存,这块内存由三部分组成:
     (a) head块,链表的头信息,包括有 totalsize(链表总长度)、tailoffset(尾部最后一个元素的偏移字节数)、entrycount(entry个数)
     (b) entry块,由一系列的 entry node 组成。node之间紧凑排列
          每个node有 prevsize字段,表示前一个node的长度,用以反方向索引
          有selfsize字段,表示当前node的长度
          以及data字段,存放当前node的实际数据
          这些字段都按一种特殊的形式编码,具体参考上图,已经比较清晰了
     (c) tail块,链表的尾部。只有一个字节,是一个填充码。

(2) 向ziplist中增删元素时,有较频繁的内存重分配操作,以及较复杂的数值运算
     所以,当链表长度增加时,整个数据结构就会不堪重负

(3) redis用两个阀值来控制 ziplist 与 linked_list 之间的转换
     (a) list_max_ziplist_entries:当链表元素的个数超过该值,自动转化为 linked_list,该值默认512
     (b) list_max_ziplist_value:当链表中某个字符串元素的长度超过该值,自动转化为 linked_list,该值默认64
     (c) 以上两值均可通过配置文件修改

posted on 2012-09-18 17:44  curve  阅读(1271)  评论(1编辑  收藏  举报

导航