redis对外的数据结构hash的底层是ziplist或者dict。
ziplist是一个经过特殊编码的双向链表,其设计目的就是为了提高存储效率。ziplist可以用于存储字符串或整数,其中整数是按真正的二进制表示进行编码的,而不是编码成字符串序列。
ziplist提高了存储效率,是内存紧缩的列表,多个数据在一起的连续空间,不擅长修改,在两端pop,push快。
hash的底层是ziplist,当数据变的越来越多,会转为dict,每次插入filed和value,ziplist数据项+2。
redis.conf的配置
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
hash-max-ziplist-entries 512,表示当hash项(field,value)数>512即ziplist项>1024的时候转为dict
hash-max-ziplist-value 64,表示当hash中的value长度超过64的时候转为dict。
ziplist的内存结构
hash为什么要转为dict?
Ⅰ,ziplist的数据发生改动,会引发内存realloc,可能导致内存拷贝。
Ⅱ,ziplist里查找需要进行遍历,数据项过多会变慢。
注:
Q:用redis的hash和string哪个结构更省内存?
A:不一定,因为可以先将对象用protocol buffer等方式序列化为字节数组,然后存入redis的string中。而hash随着数据的增大或者value比较大的时候转为dict,存储效率会下降,不过hash在支持的操作命令上比序列化后再存入string的方式还是有优势的:它既支持多个field同时存取(hmset,hmget),也支持按照某个特定的field单独存取(hset,hget)。
总之,ziplist是一个表(list),但不是一个链表(linkedlist)。ziplist将表中每一项存放在前后连续的地址空间内,一个ziplist整体占用一大块内存。而普通的双向链表每一项都占用独立的一块内存,各项之间用指针连接,这样会带来大量内存碎片,而且指针也会占用额外内存。