Redis源碼之Hash結(jié)構(gòu)的實現(xiàn)
本文轉(zhuǎn)載自微信公眾號「程序員小飯」,作者飯米粒。轉(zhuǎn)載本文請聯(lián)系程序員小飯公眾號。
redis的hash的基本命令暫時先不多說,我們直接步入正文 在redis的hash結(jié)構(gòu)中,存在這樣一種現(xiàn)象
- 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分別設(shè)置了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多設(shè)置了一個extra屬性,并且設(shè)置的值比較大,然后用hgetall獲取所有屬性的時候發(fā)現(xiàn)返回的順序不是按照我們設(shè)置的時候的屬性的順序了,這是為什么呢?
其實主要原因是:hash數(shù)據(jù)結(jié)構(gòu)底層實現(xiàn)為一個字典(dict),也是redisDb用來存儲k-v的數(shù)據(jù)結(jié)構(gòu),當數(shù)據(jù)量比較小,或者單個元素比較小的時候,底層用ziplist存儲,數(shù)據(jù)大小和元素數(shù)量閾值可以通過如下參數(shù)設(shè)置
hash-max-ziplist-entries 512 //ziplist元素個數(shù)超過512,將改為hashtable編碼 hash-max-ziplist-value 64 //單個元素大小超過64byte時,將改為hashtable編碼 對于上面的例子,主要是因為單個元素大小超過了64byte,所以改為了hashtable編碼,導(dǎo)致了hgetall獲取屬性的時候和設(shè)置的順序不一樣
壓縮表的結(jié)構(gòu)
其實很多同學也有一個疑問,hash和string類型到底有啥本質(zhì)的區(qū)別?其實我們從源碼可以看出來, 對于string類型來說,string類型是基于RedisDb的,如果string的數(shù)量不斷的變多,就會導(dǎo)致dictht部分不斷的rehash
而對于hash類型的來說,hash不存在dictht不斷rehash的問題
但是其實也是各有利弊,比如hash就沒法對某個key設(shè)置過期時間,而且redis中有一個很大的忌諱,就是不要讓某個key過大,容易阻塞,所以個人還是更推薦string的方式