Redis的基本數據結構,總體來說都是按照key-value的形式,熟悉后端的朋友可以感受到其實他的使用就像JAVA中的HashMap<K,V>和C#中的Dictionary<K,V>,只不過區別在於Redis只有一層,而事實上,Redis的Key的存儲也就是按照這樣的結構來的,一個HashMap。
作為一個HashMap,他的總體索引結構是一個數組,而每個索引下標對應的則是一個鏈表,如下圖所示,一個hashmap就是一個【數組+鏈表】組合的二位數據結構。
當需要去查詢一個key時,首先利用預設的哈希計算出key的數組位置,然后找到數組的位置,再去鏈表中遍歷中尋找到相關的節點進行返回,它的節點存儲結構大致如下:
從上述的數據結構中可以看出,在使用hashmap的時候,需要數組大小和鏈表的長度平衡,理論上來說,應當做到盡量少的哈希碰撞(hash每個下標對應的鏈表長度小),當碰撞較多到一定的閾值的時候,我們應當對HashMap進行擴容,擴容的原理時通過增大hash產生的數組長度來達到平衡存儲和哈希碰撞的目的,最理想則是沒有哈希碰撞,具體前后變化如下所示:
在JAVA的策略中,hashmap擴容時,會將hashmap一次性轉換為新的數組結構,但是當我們在使用一個較大的hashmap時,這樣的操作會讓線程處於卡頓狀態,這種問題可以通過在初始化hashmap的時候傳入一個預計使用的長度來減少hashmap擴容的可能性,以【空間】換【時間】,但是Redis是一個難以像在使用編程代碼時能夠預計到初始化容量的“動態HashMap”,所以Redis的擴容在數據量急速增大的時候會自動出現,對此Redis給出的策略時“漸進式rehash”,這種方法,會同時保留舊數組和新數組,在后台任務和新的hash指令中,無感應的去將舊的元素遷移到新的數組中,等到遷移完畢舊的數組則不存在了。但是這種方式意味着會存在兩個數組,所以在我們訪問一個key的時候,將會同時在舊和新兩個數組中進行查詢。