你肯定不來了解一下Redis中 Hash的原理嗎

前言

本章接着上一節繼續介紹 Redis 的基礎數據結構中的Hash字典.java

基本介紹

Hash 也能夠用來存儲用戶信息,和 String 不一樣的是 Hash 能夠對用戶信息的每一個字段單獨存儲,String 則須要序列化用戶的全部字段後存儲.而且 String 須要以整個字符串的形式獲取用戶,而 hash能夠只獲取部分數據,從而節約網絡流量.不過 hash 內存佔用要大於 String,這是 hash 的缺點.golang

> hset books java "Effective java"
(integer) 1
> hset books golang "concurrency in go"
(integer) 1
> hget books java
"Effective java"
> hset user age 17
(integer) 1
>hincrby user age 1	#單個 key 能夠進行計數 和 incr 命令基本一致
(integer) 18
複製代碼

Redis 中的 Hash和 Java的 HashMap 更加類似,都是數組+鏈表的結構.當發生 hash 碰撞時將會把元素追加到鏈表上.值得注意的是在 Redis 的 Hash 中 value 只能是字符串.數組

內部原理

看完基本介紹以後,咱們先來了解下 hash 的內部結構.第一維是數組,第二維是鏈表.組成一個 hashtable.bash

部分源碼:網絡

struct dictht {
    dictEntry **table;	        //entry 數組
    long size;			//數組長度
    long used			//數組中的元素個數
    ...
}
struct dictEntry{
    void *key;		        //hash 的 key
    void *val;		    	//hash 的 value
    dictEntry *next;	        //下一個dictEntry 鏈表結構
}
複製代碼

在 Java 中 HashMap 擴容是個很耗時的操做,須要去申請新的數組,爲了追求高性能,Redis 採用了漸進式 rehash 策略.這也是 hash 中最重要的部分.數據結構

漸進式 rehash

在 hash 的內部包含了兩個hashtable,通常狀況下只是用一個.如圖所示:性能

在擴容的時候 rehash 策略會保留新舊兩個 hashtable 結構,查詢時也會同時查詢兩個 hashtable.Redis會將舊 hashtable 中的內容一點一點的遷移到新的 hashtable 中,當遷移完成時,就會用新的 hashtable 取代以前的.當 hashtable 移除了最後一個元素以後,這個數據結構將會被刪除.如圖所示:ui

數據搬遷的操做放在 hash 的後續指令中,也就是來自客戶端對 hash 的指令操做.一旦客戶端後續沒有指令操做這個 hash.Redis就會使用定時任務對數據主動搬遷.spa

正常狀況下,當 hashtable 中元素的個數等於數組的長度時,就會開始擴容,擴容的新數組是原數組大小的 2 倍.若是 Redis 正在作 bgsave(持久化) 時,可能不會去擴容,由於要減小內存頁的過多分離(Copy On Write).可是若是 hashtable 已經很是滿了,元素的個數達到了數組長度的 5 倍時,Redis 會強制擴容.3d

當hashtable 中元素逐漸變少時,Redis 會進行縮容來減小空間佔用,而且縮容不會受 bgsave 的影響,縮容條件是元素個數少於數組長度的 10%.

相關文章
相關標籤/搜索