Redis源码之Hash结构的实现

本文转载自微信公众号「程序员小饭」,作者饭米粒。转载本文请联系程序员小饭公众号。

redis的hash的基本命令暂时先不多说,我们直接步入正文 在redis的hash结构中,存在这样一种现象

127.0.0.1:6379> hset user:001 name john age 25 sex man (integer) 3 127.0.0.1:6379> hgetall user:001 1) "name" 2) "john" 3) "age" 4) "25" 5) "sex" 6) "man" 

我们先给user:001分别设置了name,age,sex属性,然后通过hgetall获取所有属性,这一切看起来还比较正常 但是接下来

127.0.0.1:6379> hset user:002 name john age 25 sex man extra xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (integer) 4 127.0.0.1:6379> hgetall user:002 1) "name" 2) "john" 3) "extra" 4) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 5) "sex" 6) "man" 7) "age" 8) "25" 

我们给user:002多设置了一个extra属性,并且设置的值比较大,然后用hgetall获取所有属性的时候发现返回的顺序不是按照我们设置的时候的属性的顺序了,这是为什么呢?

其实主要原因是:hash数据结构底层实现为一个字典(dict), 恙虫病图片也是redisDb用来存储k-v的数据结构,当数据量比较小,或者单个元素比较小的时候,底层用ziplist存储,数据大小和元素数量阈值可以通过如下参数设置

hash-max-ziplist-entries 512 //ziplist元素个数超过512,将改为hashtable编码 hash-max-ziplist-value 64 //单个元素大小超过64byte时,成功案例将改为hashtable编码 对于上面的例子,主要是因为单个元素大小超过了64byte,所以改为了hashtable编码,导致了hgetall获取属性的时候和设置的顺序不一样

压缩表的结构

其实很多同学也有一个疑问,hash和string类型到底有啥本质的区别?其实我们从源码可以看出来, 对于string类型来说,string类型是基于RedisDb的,如果string的数量不断的变多,就会导致dictht部分不断的rehash

 

而对于hash类型的来说,hash不存在dictht不断rehash的问题

但是其实也是各有利弊,比如hash就没法对某个key设置过期时间,而且redis中有一个很大的忌讳,就是不要让某个key过大,容易阻塞,所以个人还是更推荐string的方式