BLOG
Enjoy when you can, and endure when you must.
DEC 18, 2013/数据库
Redis压缩列表

压缩列表(ziplist)是由一系列特殊编码的内存块构成的列表,它对于Redis的数据存储优化有着非常重要的作用。

为了更好的理解为什么压缩列表更为高效,我们需要从链表谈起。对于一个典型的双向链表,它的每个数据结点中都有两个指针,分别指向直接后继直接前驱。另外还有一个指针指向该节点的字符串。每一个字符串又实际分为三个部分:一个代表该字符串长度的整数,一个代表剩余字节的整数以及以“\0”结尾的字符串本身。以下是一个示例:

忽略其余细节,除字符串本身和空余的字节外,三个指针和两个整数都会占用额外的空间。而压缩列表转为存储上一个结点长度当前结点长度以及字符串本身。如果存储指向上一个链表结点和指向下一个链表结点的指针需要8个字节,通过这样的“压缩”后在最好的情况下只需2个字节。也就是说,压缩列表大大节省了链表指针的存储。

那接下来,我们看一下如何确保正在使用压缩列表。

Redis有两个配置针对压缩链表:

list-max-ziplist-entries 512
list-max-ziplist-value 64

list-max-ziplist-entries指定最大的元素个数,而list-max-ziplist-value指定字符串的最大长度。

也就是说,当LIST的元素个数小于配置值list-max-ziplist-entries且元素值字符串的长度小于配置值list-max-ziplist-value,则该LIST可以采用压缩列表数据结构存储数据。

在实际操作中,对于Redis2.6而言,可以利用debug_object命令来检测一个LIST对象从而确定它当前是否采用ziplist。

>>> import redis
>>> conn = redis.Redis()
>>> conn.rpush('test', 'a', 'b', 'c', 'd')
4L
>>> conn.debug_object('test')
{'encoding': 'ziplist', 'refcount': 1, 'lru_seconds_idle': 10, 'lru': 317696, 'at': '004ea964', 'serializedlength': 24, 'type': 'Value'}
>>> conn.rpush('test', 65*'a')
5L
>>> conn.debug_object('test')
{'encoding': 'linkedlist', 'refcount': 1, 'lru_seconds_idle': 10, 'lru': 317697, 'at': '004ea964', 'serializedlength': 22, 'type': 'Value'}
>>> conn.rpop('test')
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> conn.debug_object('test')
{'encoding': 'linkedlist', 'refcount': 1, 'lru_seconds_idle': 0, 'lru': 317699, 'at': '004ea964', 'serializedlength': 9, 'type': 'Value'}

从以上示例可以验证刚才所说的,并且可以发现,当一个LIST由ziplist转为linkedlist后,即使之后它再次满足了采用压缩列表数据结构存储数据的条件,也不会再转回来。

一些参考资料值得去更多的研究一下:

压缩列表

Redis ziplist内部结构分析

RECOMMENDS
COMMENTS
14/08From DeBin Zhang

GREAT!

14/08From DeBin Zhang

Great!

LEAVE COMMNT