redis字典的底層實現hashTable


Redis的字典使用哈希表作為底層實現。一個哈希表里面可以有多個哈希表節點,而每個哈希表節點就保存了字典中的一個鍵值對

哈希表的數據結構為

 

table屬性是一個數組,數組中的每個元素都是指向dictEntry結構的指針,每個dictEntry結構保存着一個鍵值對,size屬性記錄了table的大小 used哈希表目前已有的節點sizemask屬性的值總是等於size-1\

dictEntry的數據結構為

key 屬性保存着鍵值對中的鍵、而v屬性保存着鍵值對中的值,其中鍵值對中的值可以為指針 、無符號64位整數 64位整數 val指針可以指向 字符串、列表、字典、集合

next 屬性指向另一個哈希表節點的指針(next 是為了解決哈希沖突,將多個哈希值相同的鍵值對鏈接在一起)

 

典的數據結構

type屬性和privdata屬性是針對不同類型的鍵值對,為創建多態字典而設置的

type屬性是指向dictType結構的指針,每個dictType結構保存了用於操作特定類型鍵值對的函數,redis會為用途不同的字典設置不同的類型特定函數

privdata屬性則保存了需要傳給那些類型特定函數的可選參數

ht屬性是一個包含兩個項的數組,數組中的每個項都是一個dictht哈希表字典只使用ht[0]哈希表,ht[1]哈希表只會在對ht[0]哈希表進行rehash時使用

除了ht[1]之外另一個和rehash有關的屬性就是rehashidx它記錄了rehash目前的進度,如果目前沒有進行rehash那么它的值為-1

 

dictType的數據結構為

 

主要用到hashFunction來計算哈希值然后和dict->ht[0]->sizemask求&計算出所在table的下標

 

解決hash沖突:

當有兩個或以上數量的鍵被分配到了哈希表數組的同一個索引上面我們稱這些鍵發生了沖突Redis的哈希表使用拉鏈發來解決沖突,每個哈希表節點都有一個next指針

多個哈希表節點可以用next指針構成一個單向鏈表,被分配到同一個索引上的多個節點可以用這個單向鏈表鏈接起來,新節點總是插在鏈表的表頭

 

rehash:

隨着操作的不斷執行,哈希表保存的鍵值對會逐漸地增多或減少,為了讓哈希表的負載因子維持在一個合理的

范圍內當哈希表保存的鍵值對數量太多或者太少時程序需要對哈希表的大小進行相應的擴展或者收縮

redis對字典的哈希表執行rehash的步驟如下;

為字典ht[1]哈希表分配空間,這個哈希表的空間大小取決於要執行的操作以及ht[0]當前包含的鍵值對數量(ht[0].used)

如果執行的是擴展操作,那么ht[1]的大小為第一個大於等於ht[0].used*2的n次冪

如果執行的是收縮操作,那么ht[1]的大小為第一個大於等於ht[0].used的2的n次冪

將保存在ht[0]中的所有鍵值對rehash到ht[1]上面rehash指的是重新計算鍵的哈希值和索引值,然后將鍵值對放置到ht[1]哈希表的指定位置上

當ht[0]包含的所有鍵值對都遷移到了ht[1]之后釋放ht[0]將ht[1]設置為ht[0],並在ht[1]新創鍵一個空白哈希表為下一次rehash做准備

為了避免rehash對服務器性能造成影響,服務器不是一次性將ht[0]里面的所有鍵值對全部rehash到ht[1]而是分多次將ht[0]里面的鍵值對慢慢地rehash到ht[1]

在進行漸進式rehash的過程中,字典會同時使用ht[0] ht[1]兩個哈希表所以在漸進式rehash進行期間字典的刪除 查找 更新等操作會在兩個哈希表上進行 新添加到字典的鍵值對一律會保存到ht[1]里面則

ht[0]不再進行任何添加操作

 

 

哈希表的擴展和收縮

當以下條件中的任意一個被滿足時,程序會自動開始對哈希表執行擴展操作

1:服務器目前沒有在執行bgsave命令或者bgrewriteaof命令、並且哈希表的負載因子大於等於1

2:服務器目前正在執行bgsave命令或者bgrewriteaof命令並且哈希表的負載因子大於等於5

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM