Redis_字典,redis字典

來源:互聯網
上載者:User

Redis_字典,redis字典
閱讀本文之前要瞭解的兩件事情,第一,Redis是一種Key-Value資料庫,第二,字典是一種儲存鍵值對的抽象資料結構。所以不難猜出字典在Redis中應用一定非常廣泛,實際上,Redis資料庫的底層實現就是字典,對資料庫的增刪查改也是構建在對字典的操作上,那麼想要深入理解Redis,字典的解密是必不可少的,接下來,就讓我們一層一層解開指點的面紗,看看它的真面目。
首先看看Redis中有哪些地方使用到了字典
一, 資料庫鍵空間
Redis是一個鍵值對資料庫伺服器,伺服器中的每個資料庫都是一個RedisDB結構,其中RedisDb結構的dict字典儲存了資料庫中的所有鍵值對,我們將這個字典稱為鍵空間(key space),鍵空間和使用者直接所見的資料庫是直接對應的
二, Expires字典
Redis資料庫結構是一個RedisDb結構,有一個屬性expires也是字典,這個字典中儲存了資料庫中所有鍵的到期時間,我們稱這個字典叫做到期字典
下面貼出RedisDb的資料結構,加深了理解。
三, 字典是Hash類型的底層實現之一
這裡之所以說是之一,是應為Hash類型的實現可以是多種類型,在不同的情境下可以是不同的類型,但一個雜湊鍵中包含的鍵值對比較多,有或者是鍵值對中元素都是比較長的字串的時候,就會使用字典作為底層實現,否則就是壓縮列表作為底層實現。
【注意】鍵空間中的鍵和到期字典中的鍵都指向都一個鍵對象,所以不會出現任何重複對象,也不會浪費記憶體空間。
然後我們來瞭解一下在Redis中字典是如何?的。

字典的定義在dict.h/dict中給出了,如下:

typedef struct dict {    dictType *type;    void *privdata;    dictht ht[2];    long rehashidx; /* rehashing not in progress if rehashidx == -1 */    int iterators; /* number of iterators currently running */} dict;


這是一個雜湊表,table數組中的每個元素都是指向一個dictEntry結構的指標,size是雜湊表的大小,也就是table數組的大小,sizemask屬性總是等於size-1 ,sizemask和雜湊值一起決定將一個鍵應該被放到那個數組上,used表示目前雜湊表有多少個節點,used/size 是一個雜湊表的負載因子,這個因子決定了什麼時候後對雜湊表進行擴充和收縮。
typedef struct dictht {    dictEntry **table;    unsigned long size;    unsigned long sizemask;    unsigned long used;} dictht;


下面是一個雜湊表節點,每個dictEntry結構都保持著一個鍵值對,其中next指標可以將多個雜湊值相同的鍵值對串連在一起,一次來解決鍵衝突的問題(這裡可以引申出雜湊函數以及雜湊衝突解決方案,Redis中使用的解決方案是鏈地址法,就是,如果多個值通過雜湊函數得到的雜湊值是相同的,那麼就連結到這個地址後,還有一種解決雜湊衝突的方案,就是尋地址法,就是當出現雜湊衝突的時候,對鍵值對在進行一個雜湊函數,得到一個沒有被佔用的地址為止,這兩種方案各有利弊,鏈地址法可能會退化成一個鏈表,尋地址法可能在後期插入時,全是衝突)

typedef struct dictEntry {    void *key;    union {        void *val;        uint64_t u64;        int64_t s64;        double d;    } v;    struct dictEntry *next;} dictEntry;

還有一個需要說的地方,就是雜湊表的rehash

隨著操作的不斷執行,一個雜湊表中儲存的鍵值對會越來越多或者是越來越少,雜湊表中鍵值對數量過多或者過少都是不好的,過多,就會相當於是多個鏈表,過少也不好,尋找的命中率也會很低,將雜湊表的負載因子(used/size)維持在一個範圍之類是最好的,所以,當雜湊表的數量過大或者過小的時候,程式會對雜湊表進行擴充或者收縮,

擴充好理解,如果size=4 ,但是used=8,相當於每個鍵的後面都有個鏈,這樣尋找起來是費勁的,這個時候可以通過Rehash來進行完成,注意dict資料結構中的那個

dictht ht[2],這裡是兩個dictht,其中ht[1]是閒置,在進行擴充的時候現將ht[1]擴充成ht[0]的兩倍,然後將ht[0]中的鍵值對一個一個雜湊到ht[1]中去,最後將ht[1]設定為ht[0]

這裡需要注意的是rehash的時機,一般是負載因子大於5的時候擴充,負載因子小於0.1的時候收縮,還有一個問題是字典中有個屬性是rehashidx,這個屬性標誌rehash的狀態,如果是0,表示rehash正式開始,然後沒rehash一個鍵值對,就將這個值加一,當ht[0]的值全部被轉移到ht[1]的時候,就將這個值設定成-1,表示rehash操作完成。

其實還有很多要說的,比如漸進式rehash,漸進式就說說rehash過程不是一次性完成的,而是分多次,漸進式完成的,在rehash過程中,所有的刪除,尋找,更新都會在兩個雜湊表中進行,例如,如果尋找一個元素,ht[0]中沒有,那麼就去ht[1]中尋找,新添加的一律都是添加到ht[1]中,ht[0]中不再進行任何添加操作




著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.