鏈表
首先Redis中存在的抽象結構爲List,而鏈表是其一種實現方式,當list元素較多或者元素都爲比較長的字符串時,採用鏈表作爲底層實現。此外,鏈表還用在Redis服務器保存客戶端狀態、發佈與訂閱功能等等。
在Redis中,鏈表是雙向鏈表,其Node結構定義如左圖,List的定義如右圖:
觀察得知,Redis中鏈表的特點如下
- 無環(頭節點的pre指向null,尾節點的next也指向null)
- 具有頭指針和尾指針,找表頭和表尾的時間複雜度都是O(1)
- 雙端
- 多態(由於多態的存在,使得鏈表可以保存不同類型的值並正常處理)
- 帶有鏈表長度len
字典
Key-value鍵值對,key獨一無二,Redis的數據庫就是用這種數據結構實現的,使用哈希表來實現,其中哈希表節點定義如左圖所示,哈希表整個的定義如右圖所示:
Hash節點的next指針用來鏈接同一個hash值的元素(鏈地址法解決衝突,添加到表頭O(1))
下圖是整個字典的實現,其中type用於指示鍵值對的類型,是爲了創建多態字典,Redis爲用途不同的字典配置不同的類型函數,具體如右圖所示:
Redis採用MurmurHash2算法來計算hash值
Rehash操作
- 爲hash[1]表分配空間:
- 如果執行擴展操作,則分配爲超過hash[0].used*2的最小2^n;
- 如果執行收縮操作,則分配爲超過hash[0].used的最小2^n;
- 將hash[0]上所有元素rehash到hash[1]上
- 釋放hash[0],將hash[1]置爲hash[0],在hash[1]上新建一個空白表
那麼到底啥時候進行Rehash擴容呢?
- 服務器目前沒在BGSAVE 或則BVGEWRITEAOF,且hash表的負載因子>=1;
- 服務器目前在BGSAVE 或則BVGEWRITEAOF,且hash表的負載因子>=5;
- 縮容是負載因子<0.1時
漸進式Hash
在字典中維護一個rehashIdx屬性,在rehash期間,每次進行更新、刪除、查找、添加時,除了進行原有操作外,額外還將hash[0]中的rehashIdx對應的項rehash到hash[1]中去,然後將rehashIdx+1;直到所有都移動完畢,rehashIdx恢復-1。
注意,在rehash期間,所有的添加操作都在hash[1]上進行,查找、更新、刪除則要從兩個表都進行。