Redis雜湊表的實現要點

發表於2016-03-30

Redis雜湊表的實現要點

雜湊演算法的選擇

針對不同的key使用不同的hash演算法,如對整型、字串以及大小寫敏感的字串分別使用不同的hash演算法;

整型的Hash演算法使用的是Thomas Wang’s 32 Bit / 64 Bit Mix Function ,這是一種基於位移運算的雜湊方法。基於移位的雜湊是使用Key值進行移位操作。通常是結合左移和右移。每個移位過程的結果進行累加,最後移位的結果作為最終結果。這種方法的好處是避免了乘法運算,從而提高Hash函式本身的效能。

字串使用的MurmurHash演算法,MurmurHash演算法具有高運算效能,低碰撞率的特點,由Austin Appleby建立於2008年,現已應用到Hadoop、libstdc++、nginx、libmemcached等開源系統。2011年Appleby被Google僱傭,隨後Google推出其變種的CityHash演算法。

murmur是 multiply and rotate的意思,因為演算法的核心就是不斷的乘和移位(x *= m; k ^= k >> r;)

一個好的hash演算法需要滿足兩個條件:

1) 效能高,運算足夠快;

2) 相鄰的資料hash後分布廣;即使輸入的鍵是有規律的,演算法仍然能給出一個很好的隨機分佈性;

比如:murmur計算”abc”是1118836419,”abd”是413429783。而使用Horner演算法,”abc”是96354, “abd”就比它多1(96355);

rehash

負載因子 = 當前結點數/桶的大小,超過1表示肯定有碰撞了;碰撞的結點,通過連結串列拉鍊起來;

所有雜湊表的初始桶的大小為4,根據負載因子的變化進行rehash,重新分配空間(擴充套件或收縮)

當hash表的負載因子超過1後,進行擴充套件(小於0.01時,進行收縮);

所謂擴充套件,就是新建一個hash表2,將桶的數量增大(具體增大為:第一個大於等於usedSize的2的n次冥);然後將hash表1中結點都轉移到hash表2中;

rehash的觸發條件:

當做BGSAVE或BGREWRITEEOF時,負載因子超過5時觸發rehash,

沒有BGSAVE或BGREWRITEEOF時,負載因子超過1時觸發rehash;

在BGSAVE或BGREWRITEEOF時,使用到Linux的寫時複製,如果這時候做rehash,將會好用更多的記憶體空間(沒有變化的結點用一份,變化的結點複製一份)

漸進式rehash

一個hash表中的資料可能有幾百上千萬,不可能一次rehash轉移完,需要分批逐漸轉移;

在rehash的過程中,對redis的查詢、更新操作首先會在hash0中查詢,沒有找到,然後轉到hash1中操作;

對於插入操作,直接插入到hash1中;最終目標是將hash表1變為空表,rehash完成;

value的儲存

鍵值對的實現,value 是一個union,對整型和字串使用不同的儲存物件;

ref:
《Hash 函式概覽》http://www.oschina.net/translate/state-of-hash-functions

《redis設計與實現》

相關文章