可以看到,String 類型的底層實現只有一種數據結構,也就是簡單動態字符串。而 List、Hash、Set 和 Sorted Set 這四種數據類型,都有兩種底層實現結構。通常情況下,我們會把這四種類型稱爲集合類型,它們的特點是一個鍵對應了一個集合的數據。redis 3.2後引入了quicklist結構
Redis 使用了一個哈希表來保存所有鍵值對。
一個哈希表,其實就是一個數組,數組的每個元素稱爲一個哈希桶。所以,我們常說,一個哈希表是由多個哈希桶組成的,每個哈希桶中保存了鍵值對數據。
哈希桶中的元素保存的並不是值本身,而是指向具體值的指針。
潛在的風險點:
當哈希衝突變多後,將哈希遍歷退化成鏈表遍歷,導致查詢變慢,這時需要rehash來重建哈希表。
Redis 會對哈希表做 rehash 操作, 爲了使 rehash 操作更高效,Redis 默認使用了兩個全局哈希表:
一開始,當你剛插入數據時,默認使用哈希表 1,此時的哈希表 2 並沒有被分配空間。隨着數據逐步增多,Redis 開始執行 rehash,這個過程分爲三步:
簡單來說就是在第二步拷貝數據時,Redis 仍然正常處理客戶端請求,每處理一個請求時,從哈希表 1 中的第一個索引位置開始,順帶着將這個索引位置上的所有 entries 拷貝到哈希表 2 中;等處理下一個請求時,再順帶拷貝哈希表 1 中的下一個索引位置的 entries。如下圖所示:
集合類型的底層數據結構主要有 5 種:
壓縮列表實際上類似於一個數組,數組中的每一個元素都對應保存一個數據。和數組不同的是,壓縮列表在表頭有三個字段 zlbytes、zltail 和 zllen,分別表示列表長度、列表尾的偏移量和列表中的 entry 個數;壓縮列表在表尾還有一個 zlend,表示列表結束。
跳錶在鏈表的基礎上,增加了多級索引,通過索引位置的幾個跳轉,實現數據的快速定位,如下圖所示
集合常見操作的複雜度:
Redis 之所以能快速操作鍵值對,一方面是因爲 O(1) 複雜度的哈希表被廣泛使用,包括 String、Hash 和 Set,它們的操作複雜度基本由哈希表決定,另一方面,Sorted Set 也採用了 O(logN) 複雜度的跳錶。不過,集合類型的範圍操作,因爲要遍歷底層數據結構,複雜度通常是 O(N)。這裏,我的建議是:用其他命令來替代,例如可以用 SCAN 來代替,避免在 Redis 內部產生費時的全集合遍歷操作。