Redis 基礎數據結構(四)

這一節我們介紹Hash(字典)數據類型

一、hash(字典)簡單介紹

1、Redis的hash相當於java語言裏面的HashMap,內部存儲了很多鍵值對,實現結構也和HashMap是類似的,都是基於數組+鏈表實現的二維結構。

2、不同的是Redis的字典結構只能存儲字符串。

3、Redis的rehash操作採用了漸進式resha策略,漸進式rehash會在rehash操作時,保留新舊兩個hash結構,查詢時會同時查詢兩個hash結構,在後續的定時任務以及hash指令操作時,漸進地將舊的數據遷移到新的hash結構中。

4、hash結構也可以用來存儲用戶信息,與字符串需要一次性全部序列化整個對象不同,hash可以對用戶結構中每個單獨的字段進行存儲。這樣當我們需要獲取用戶信息時,可以部分獲取,避免浪費網絡流量。

5、hash結構的存儲消耗要高於單個字符串,所以在使用hash存儲還是使用字符串存儲時,要注意權衡。

6、hash結構中單個的key也可以進行計數操作,對應的指令是hincrby,和incr的使用方法基本一致。

com.xiaozhameng.aliyun:6379> hset books java 'think in java' python 'python cookbook'
(integer) 2
com.xiaozhameng.aliyun:6379> hset books golang 'learning go programming'
(integer) 1
com.xiaozhameng.aliyun:6379> hgetall books
1) "java"
2) "think in java"
3) "python"
4) "python cookbook"
5) "golang"
6) "learning go programming"
com.xiaozhameng.aliyun:6379> hlen books
(integer) 3
com.xiaozhameng.aliyun:6379> hget books java
"think in java"
com.xiaozhameng.aliyun:6379> hset user-zhameng age 26
(integer) 1
com.xiaozhameng.aliyun:6379> hincrby user-zhameng age 1
(integer) 27
com.xiaozhameng.aliyun:6379> 

二、字典(hash)內部實現

1、字典是Redis中使用較爲頻繁的複合數據結構,除了hash結構會用到字典外,整個redis數據庫的所有key和value也組成了一個全局字典。帶有過期時間的key的集合也是一個字典,zset集合中存儲value和score值的映射關係也是通過字典結構來實現的。

struct RedisDb {
	dict* dict;		// all keys key => value
	dict* expires;	// all expired keys key=>long(timestamp)
}

struct zset {
	dict *dict;		// all values values=>score
	zskiplist *zsl;
}

2、字典結構的內部包含了兩個hashtable,通常情況下只有一個hashtable有值,但是在字典擴容縮容時,需要分配新的hashtable,然後進行漸進式搬遷。這時候兩個hashtable存儲的分別是舊的hashtable和新的hashtable,搬遷結束後,舊的hashtable被刪除,新的hashtable取而代之。

3、字典數據類型的hashtable結構和java的HashMap 幾乎是一樣的,都是通過一維數組加上二維鏈表實現的,採用分桶的方式解決hash衝突。

4、漸進式rehash,大字典的擴容是比較耗時的,需要重新申請數組,然後將舊字典中所有鏈表中的元素重新搬遷到新的數組下面,這是一個O(n)時間複雜度的操作,所以redis使用了漸進式rehash,雖然搬遷的過程變長了,但是肯定能搬完。你可能有疑問,既然redis的搬遷操作是在後續的hash操作中發生的,那麼當客戶端閒下來的時候,沒有指令觸發搬遷,redis的搬遷就停止了嗎? 當然不是的,redis設計了定時任務對字典進行主動搬遷。

5、查找過程也是類似java中的查找。這裏不做贅述。

6、擴容條件,正常情況下,當hash表中的元素個數等於一維數組的長度時,就會觸發擴容,擴容新數組的長度是原來容量的二倍。不過如果redis正在做bgsave,爲了減少內存頁的過多分離(Copy On Write),redis儘量不去擴容,但是如果hash表已經非常滿了,元素的個數已經達到了一維數組長度的5倍,這個時候就會強制擴容。

7、縮容,縮容的條件是元素個數低於數組長度的10%,縮容不會考慮redis的bgsave操作。

8、Redis Bgsave 命令用於在後臺異步保存當前數據庫的數據到磁盤的操作。BGSAVE 命令執行之後立即返回 ,然後 Redis fork 出一個新子進程,原來的 Redis 進程(父進程)繼續處理客戶端請求,而子進程則負責將數據保存到磁盤,然後退出。

 

參考博客:https://www.jianshu.com/p/658365f0abfc

參考書籍:redis深度歷險-核心原理與應用實戰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章