1. 程式人生 > 實用技巧 >[Redis] 雜湊表的Rehash機制

[Redis] 雜湊表的Rehash機制

雜湊表的完整結構 , 因為他是多個雜湊一層層巢狀的 , 所以會是這樣的結構

觸發rehash的時機

字典型別容量變化過程叫做rehash,需要滿足一定的條件才能觸發擴容機制
伺服器當前沒有進行BGWRITEAOF或者BGSAVE命令,且當前鍵值對個數超過一維陣列的大小,才會觸發擴容。

如果當前鍵值對個數超過一維陣列大小的五倍,無論是否在進行BGWRITEAOF或者BGSAVE命令,都會強制擴容。
Hash型別擴容後陣列的長度為原來的二倍


縮容機制:如果當前鍵值對個數少於一維陣列大小的十分之一,則觸發縮容過程。縮容不會考慮當前伺服器是否在進行BGWRITEAOF或者BGSAVE命令

漸進式rehash的過程

利用了兩個雜湊表進行的 , 有點類似資料庫的遷移 , 讀的時候先讀舊庫 , 讀不到讀新庫 , 寫的時候只寫新庫 ; 其他舊資料一點點的往新庫上搬

當觸發擴容的時候,Redis會首先為ht[1] 分配一塊記憶體空間。如果當前字典是一個比較大的字典,那麼整個擴容過程的時間複雜度為O(n),直接完整進行擴容機制可能會導致Redis一段時間內停止服務。為了避免停止服務的情況,Redis的設計團隊採用了漸進式rehash的策略,每次只對原雜湊表中的一小部分進行搬遷,這樣漸進式的進行,直到全部鍵值對都遷移到新的雜湊表中。

首先,對於key的查詢,我們需要到原來的雜湊表中進行查詢,如果找到對應的value,直接返回就可以了。如果沒有找到,那麼只有兩種可能,一個是這個鍵值對已經搬遷到新的雜湊表了,另外一種可能是根本就不存在這個鍵值對,無論是哪種可能,我們都需要再去新雜湊表中對他進行查詢,如果找到了就返回,如果找不到說明這個鍵值對不存在。

步驟如下:
1.為字典的備用雜湊表分配空間:
如果執行的是擴充套件操作,那麼備用雜湊表的大小為第一個大於等於(已用節點個數)*2的2n(2的n次方冪)
如果執行的是收縮操作,那麼備用雜湊表的大小為第一個大於等於(已用節點個數)的2n
2.在字典中維持一個索引計數器變數rehashidx,並將它的值設定為0,表示rehash工作正式開始(為-1時表示沒有進行rehash)。
3.rehash進行期間,每次對字典執行新增、刪除、查詢或者更新操作時,程式除了執行指定的操作以外,還會順帶將ht[0]雜湊表在rehashidx索引上的所有鍵值對rehash到ht[1],當一次rehash工作完成之後,程式將rehashidx屬性的值+1
。同時在serverCron中呼叫rehash相關函式,在1ms的時間內,進行rehash處理,每次僅處理少量的轉移任務(100個元素)。 隨著字典操作的不斷執行,最終在某個時間點上,ht[0]的所有鍵值對都會被rehash至ht[1],這時程式將rehashidx屬性的值設為-1,表示rehash操作已完成。

初始化ht[1] 0-7 , ht[0]是舊的有資料 0-3

開始搬遷 , 把就ht[0] 0上的資料 , 搬到了新的ht[1] 的4的部分

rehash完成 , 把ht[0]上的全都搬到ht[1]上了