Redis是一個包含了很多Key-Value對的大字典,這個字典支援的Value非常豐富,可以為字串、雜湊表、列表、集合和有序集,基於這些類型豐富的value,擴充出了功能強大的操作,例如hmset、lpush、sadd等
1、字典
字典是Redis最基礎的資料結構,一個字典即一個DB,Redis支援多DB
Redis字典採用Hash表實現,針對碰撞問題,其採用的方法為“鏈地址法”,即將多個雜湊值相同的節點串聯在一起, 從而解決衝突問題。
“鏈地址法”的問題在於當碰撞劇烈時,效能退化嚴重,例如:當有n個資料,m個槽位,如果m=1,則整個Hash表退化為鏈表,查詢複雜度O(n)
為了避免Hash碰撞攻擊,Redis隨機化了Hash表種子
Redis的方案是“雙buffer”,正常流程使用一個buffer,當發現碰撞劇烈(判斷依據為當前槽位元和Key數的對比),分配一個更大的buffer,然後逐步將資料從老的buffer遷移到新的buffer。
2、Redis中的雜湊表
前面提到Redis是個key/value儲存系統,學過資料結構的人都知道,key/value最簡單的資料結果就是雜湊表(當然,還有其他方式,如B-樹,二叉平衡樹等),hash表的效能取決於兩個因素:hash表的大小和解決衝突的方法。這兩個是矛盾的:hash表大,則衝突少,但是用記憶體過大;而hash表小,則記憶體使用量少,但衝突多,效能低。一個好的hash表會權衡這兩個因素,使記憶體使用量量和效能均儘可能低。在Redis中,雜湊表是所有其他資料結構的基礎,對於其他所有資料結構,如:string,set,sortedset,均是儲存到hash表中的value中的,這個可以很容易的通過設定value的類型為void*做到。本文詳細介紹了Redis中hash表的設計思想和實現方法。
3、Redis雜湊表的設計思想
下圖是從淘寶《Redis記憶體儲存結構分析》中摘得的圖片,主要描述Redis中hash表的組織方式。
在Redis中,hash表被稱為字典(dictionary),採用了典型的鏈式解決衝突方法,即:當有多個key/value的key的映射值(每對key/value儲存之前,會先通過類似HASH(key) MOD N的方法計算一個值,以便確定其對應的hash table的位置)相同時,會將這些value以單鏈表的形式儲存;同時為了控制雜湊表所佔記憶體大小,redis採用了雙雜湊表(ht[2])結構,並逐步擴大雜湊表容量(桶的大小)的策略,即:剛開始,雜湊表ht[0]的桶大小為4,雜湊表ht[1]的桶大小為0,待衝突嚴重(redis有一定的判斷條件)後,ht[1]中桶的大小增為ht[0]的兩倍,並逐步(注意這個詞:”逐步”)將雜湊表ht[0]中元素遷移(稱為“再次Hash”)到ht[1],待ht[0]中所有元素全部遷移到ht[1]後,再將ht[1]交給ht[0](這裡僅僅是C語言地址交換),之後重複上面的過程。
Redis字典結構如下:
[cpp] view plain copy typedef struct dict { dictType *type; void *privdata; dictht ht[2]; //雙buffer int rehashidx; int iterators; } dict; typedef struct dictht { dictEntry **table; //hash鏈表 unsigned long size; unsigned long sizemask; unsigned long used; } dictht; //資料節點<K,V> typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; } v; struct dictEntry *next; } dictEntry; redisObject是真正儲存redis各種類型的結構,其內容如下:
[cpp] view plain copy typedef struct redisObject { unsigned type:4; //邏輯類型 unsigned notused:2; /* Not used */ unsigned encoding:4; //實體儲存體類型 unsigned lru:22; /* lru time (relative to server.lruclock) */ int refcount; void *ptr; //具體資料 } robj; 其中type即redis支援的邏輯類型,包括:
[cpp] view plain copy #define REDIS_STRING 0 #define REDIS_LIST 1 #define REDIS_SET 2 #define REDIS_ZSET 3 #define REDIS_HASH 4 enconding為實體儲存體方式,一種邏輯類型可以使用不同的儲存方式,包括: