日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

概覽

redis 本質是 K-V 鍵值對數據庫,底層通過字典 dict 存儲鍵值映射關系,除此之外,dict 還作為 Redis hash 結構底層的實現之一。

討論 Redis 的數據結構,可以從兩個層面出發。

第一個層面從使用者角度出發,即 Redis 暴露給外部調用的 Api:

•string

•list

•hash

•set

•sorted set

第二個層面是 Redis 的內部實現角度出發,是更為底層的數據結構實現:

•dict

•sds

•ziplist

•quicklist

•skiplist

Redis 這么做的目的還是基于高性能的考慮,在不同的場景下使用不同的底層數據結構實現,最大程度提升內存操作的效率。

例如當 sorted set,hash 存儲的數據規模較小時,底層都是通過 ziplist 實現,而當數據規模達到一定量時,sorted set 會轉換成 dict + skiplist 的底層實現,hash 會轉換成 dict 的底層實現。

本文主要討論是 Redis 關于 dict 這一底層數據結構的實現原理。

實現

dict 的實現與 JAVA jdk 中 hashmap 的實現有許多相似之處:

•關于哈希映射,key 的索引計算公式為 hash & (n - 1),其中 hash 為 key 對應的 hash 值(Redis 通過 MurmurHash 算法計算得出),n 為哈希數組的大小•關于哈希沖突,Redis 同樣也是采用鏈地址法解決沖突

dict 在擴縮容的情況下,采用的是漸進式的 rehash 方式,這是它的特殊之處,下文會主要講到。

dict 的數據結構如下:

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

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

•ht[2] 數組中存放了兩張哈希表,只有在 rehash 的過程中,ht[0] ht[1] 才都有效;正常情況下只有 ht[0] 有效,ht[1] 中沒有任何數據

•rehashidx 用來表示 rehash 過程到了哪一個索引位置,正常情況下 rehashidx = -1,表示當前沒有進行 rehash

一文讀懂Redis的dict字典數據結構

 

dictht 的數據結構如下:

•dictEntry 數組,用來存放鍵值對

•size 表示當前 dictEntry 數組的大小

•sizemask,值為 size - 1,在計算 key 的索引位置時用到, index = hash & sizemask

•used 記錄現有 dict 的數據個數

一文讀懂Redis的dict字典數據結構

 

正常情況下,dict 整體的數據結構如下圖所示:

一文讀懂Redis的dict字典數據結構

 

rehash

隨著操作不斷執行,哈希表中的鍵值對會逐漸增加或減少,為了讓哈希表的負載因子(負載因子 = 已保存節點數量/哈希表大?。┚S持在一個合理的范圍內,當哈希表中節點數量過多或者過少時,Redis 會對哈希表進行相應的擴容或縮容,這一過程稱為 rehash。

在 rehash 操作開始前,首先要為哈希表 ht[1] 分配內存,ht[1] 之前一直是空閑狀態,終于要派上用場了,具體內存分配策略如下:

•如果是擴容操作,ht[1]的大小為第一個大于等于ht[0].used*2的2^n(2的n次方冪),舉個例子 ht[0].used = 5,觸發了擴容操作,即 ht[1].size = 5 * 2 = 10,但 10 不符合 2^n 要求,則繼續往下找到第一個符合要求的數 16,即 ht[1].size = 16

•如果是縮容操作,ht[1]的大小為第一個大于等于ht[0].used的2^n(2的n次方冪),舉個例子 ht[0].used = 5,觸發了縮容操作,則 ht[1].size = 8

ht[1] 分配完內存之后,接著進行如下操作:

•將 ht[0] 的中的節點重新計算哈希值和索引值,映射到 ht[1] 上

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

哈希表觸發擴容的時機如下:

•服務器目前沒有在執行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的負載因子大于等于1

•服務器目前正在執行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的負載因子大于等于5,這么做的原因是避免在子進程存在期間進行哈希表擴容操作,從而避免不必要的內存寫入操作,最大限度節省內存

負載因子的計算公式:

一文讀懂Redis的dict字典數據結構

 

當負載因子小于 0.1 時,觸發縮容操作。

漸進式rehash

值得注意的是 rehash 的過程,Redis 并不是一次性將所有元素集中式地 rehash 到 ht[1] 中,而是分多次,漸進式地完成。

這么做的原因是如果當哈希表中存放的鍵值對數量如果是千萬級,甚至億級,一次性完成所有鍵值的 rehash 操作,可能會導致 Redis 一段時間內對外不可用。

以下是漸進式 rehash 的具體步驟:

•為ht[1]分配空間,讓字典同時持有ht[0]和ht[1]兩個哈希表

•在字典中維持一個索引計數器變量rehashidx,并將它的值設置為0,表示rehash工作正式開始

•在rehash進行期間,每次對字典執行添刪改查操作時,程序除了執行指定的操作以外,還會順帶將ht[0]哈希表在rehashidx索引上的所有鍵值對rehash到ht[1],當rehash工作完成之后,程序將rehashidx屬性的值增一

•隨著字典操作的不斷執行,最終在某個時間點上,ht[0]的所有鍵值對都會被rehash至ht[1],這時程序將rehashidx屬性的值設為-1,表示此次rehash操作已完成

下面展示一次完整 rehash 的過程,首先初始化 dict,準備開始 rehash;

一文讀懂Redis的dict字典數據結構

 

rehashidx = 0,rehash 索引0對應的鍵值對,rehashidx + 1;

一文讀懂Redis的dict字典數據結構

 

rehashidx = 1,rehash 索引1對應的鍵值對,rehashidx + 1;

一文讀懂Redis的dict字典數據結構

 

rehashidx = 2,rehash 索引2對應的鍵值對,rehashidx + 1;

一文讀懂Redis的dict字典數據結構

 

最終完成 rehash 過程。

一文讀懂Redis的dict字典數據結構

 

分享到:
標簽:字典 dict
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定