Redis資料結構原理
Redis沒有直接使用C語言傳統的字串表示,而使自己構建了一種名為簡單動態字串的抽象SDS
C 字串 | SDS |
---|---|
獲取字串長度的複雜度為 O(N) 。 | 獲取字串長度的複雜度為 O(1) 。 |
API 是不安全的,可能會造成緩衝區溢位。 | API 是安全的,不會造成緩衝區溢位。 |
修改字串長度 N 次必然需要執行 N 次記憶體重分配。 |
修改字串長度 N 次最多需要執行 N 次記憶體重分配。 |
只能儲存文字資料。 | 可以儲存文字或者二進位制資料。 |
可以使用所有 庫中的函式。 | 可以使用一部分 庫中的函式。 |
Redis 的連結串列實現的特性可以總結如下:
-
雙端: 連結串列節點帶有
prev
和next
指標, 獲取某個節點的前置節點和後置節點的複雜度都是 O(1) 。 -
無環: 表頭節點的
prev
指標和表尾節點的next
指標都指向NULL
, 對連結串列的訪問以NULL
為終點。 -
帶表頭指標和表尾指標: 通過
list
結構的head
指標和tail
指標, 程式獲取連結串列的表頭節點和表尾節點的複雜度為 O(1) 。 -
帶連結串列長度計數器: 程式使用
list
len
屬性來對list
持有的連結串列節點進行計數, 程式獲取連結串列中節點數量的複雜度為 O(1) 。 -
多型: 連結串列節點使用
void*
指標來儲存節點值, 並且可以通過list
結構的dup
、free
、match
三個屬性為節點值設定型別特定函式, 所以連結串列可以用於儲存各種不同型別的值。
字典dict
rehash
一般字典都會有ht[0] ht[1]兩個字典,而ht1就是rehash時用的
步驟:
-
判斷是收縮還是擴容,確定ht1的size
-
將ht0的資料遷移到ht1
-
釋放ht0,ht1成為ht0,新建ht1
當滿足以下條件時,雜湊表會進行擴充套件和收縮
-
伺服器目前沒有執行BGSIVE或者BGREWRITEAOF命令,並且雜湊表的負載因子>=1
-
伺服器目前正在執行這兩條命令之一,且負載因子>=5
-
負載因子=ht[0].used / ht[0].size
-
負載因子小於0.1 進行收縮
原因:處於對執行BGSIVE或者BGREWRITEAOF命令時期時,redis會建立伺服器程序的子程序,一般採用寫時複製的策略優化子程序效率,所以子程序存在時會盡量避免rehash,因此提高了此時所需的負載因子
其次:rehash是漸進rehash
也就是說redis實際執行rehash時是採用每次對字典增刪改查時順便rehash,一些操作過後,字典rehash完成。當然了,在此期間,比如對字典的查詢是在ht0和ht1上都進行查詢
跳躍表
跳躍表是一種有序資料結構,支援Ologn的查詢,最壞On。還可以通過順序性操作批量處理節點
-
header | tail 頭尾指標
-
level 跳躍表層數最大的節點(排除表頭節點)
-
每層 記錄了這一跳的前進指標以及跨度這兩個屬性,顯然層數越多跳躍表的查詢遍歷就越快,跨度用來統計走過的距離,方便統計Rank
-
後退製作backward BW標記了向前一個結點的倒退指標,以實現表尾到表頭的遍歷操作
-
分值和物件,value從小到大構成跳躍表,物件儲存一個SDS,value相同時按SDS字典序排
遍歷時從高層往下查,碰到的前進指標跨度是1是往下走,知道碰到null證明到頭了
整數集合
整數集合是集合間的底層實現之一,當set只有整數元素並且數量不多時,會採用整數集合
升級,但不支援降級
每當新新增的整數型別比現有型別長時,會進行升級操作,這樣的動態策略可以節省記憶體
壓縮列表
列表鍵和雜湊鍵的底層實現之一
AOF
與rdb儲存資料庫鍵值對不同,AOF持久化通過儲存Redis執行的寫命令持久化
AOF持久化的實現
可以分為命令 追加append 檔案寫入 檔案同步sync三個步驟
命令追加
比如SET KEY VALUE執行後,這條命令會最佳到伺服器狀態的aof_buf
緩衝區的末尾
AOF檔案的寫入與同步以及appendfsync選項
Redis 伺服器程序就是一個時間迴圈,這個迴圈中的檔案事件負責接收客戶端的命令請求,以及向客戶端傳送命令回覆,而時間事件負責執行serverCron函式這樣需要定時執行的函式,
fsync和fdatasync同步函式
現代作業系統中使用者呼叫write函式,通常先把資料放到記憶體緩衝區中,等到緩衝區滿了或到了指定時間才會寫入,這樣雖然提高效率但也有停機時的不安全性,使用這兩個同步函式強制作業系統將緩衝區的資料寫入磁碟
appendfsync選項的值得效果
always時,最安全但也最慢,他最多隻丟失一個事件迴圈中的命令資料
everysec時,每秒都有負責這個的子執行緒進行同步,夠快且最多丟失一秒的追加命令
no時,同樣每個事件迴圈都把緩衝區資料寫到aof,但aof檔案的同步由作業系統決定,因為一般不需要同步,所以這種模式的aof檔案寫入速度很快,但一旦發生丟失資料則會丟失上次同步aof後的所有資料
AOF重寫
利用命令的合併和覆蓋,建立一個新的aof檔案替代原有的aof,新的aof只執行持久化必須的一部分的命令體積小很多
重寫虛擬碼p150