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的方式