位元位計數 動態規劃
本篇部落格是對《Redis設計與實現》的學習和總結
日期:2020-12-15
Redis版本:3.0.6
Redis持久化的方式
RDB持久化
RDB持久化將資料庫資料寫入到RDB檔案中,在Redis重新啟動的時候會自動解析RDB檔案,恢復資料庫資料到記憶體中。
- RDB持久化的相關命令
save
save命令會阻塞Redi直到RDB檔案寫入完成,在阻塞期間Redis不能處理任何命令
bgsave
Redis執行fork建立一個子程序,由子程序來執行RBD檔案的寫入,而父程序可以繼續處理命令。Redis內部所有涉及RDB的操作都採用 bgsave 的方式。
子程序並不會有父程序的記憶體複製,也就是說bgsave
bgsave
的子程序不會寫記憶體,所以只有在父程序寫記憶體的時候才會複製被寫入的記憶體。
- 自動執行持久化
save seconds changes
如果在 seconds 秒內發生了 changes 次修改的話,就執行一次bgsave。用偽程式碼表示如下:
lastSaveTime # 上一次執行 save 或 bgsave 的時間戳 current # 現在的時間戳 currentChanges # 從lastSaveTime 到 current 期間內的修改次數 if (currentChanges >= changes && (current - lastSaveTime) > seconds) { # 執行 bgsave }
這裡的修改次數並不是被修改的鍵的個數,比如, set aaa 111
算作一次修改,但是lpush list 111 222 333
算作 3 次修改。
如果配置多個 save 配置項,只要滿足其中任何一個,就會執行 bgsave。以下是 Redis 的預設配置:
save 900 1 # 15分鐘內有至少1次修改
save 300 10 # 5分鐘內有至少10次修改
save 60 10000 # 1分鐘內有至少1萬次修改
AOF持久化
AOF(append only file)持久化是將Redis的寫命令全部追加到檔案中,在重啟恢復資料庫的資料時,只要重新執行這些寫命令就可以了。
- AOF持久化的步驟
AOF持久化功能可以分為三步:
- 命令追加:在執行完一個寫命令之後,將這個命令新增到AOF緩衝區
- 檔案寫入:在執行完命令之後,如果AOF緩衝區中有有內容,將其寫入到AOF檔案中
- 檔案同步:根據配置項
appendfsync
的配置決定是否進行同步
檔案寫入和檔案同步的區別:檔案寫入就是呼叫 write
函式試圖將資料寫入到檔案中,但是作業系統為了提高效率,會先將資料儲存在一個緩衝區裡面,等到緩衝區被填滿或者超過時限,才真正將緩衝區裡的資料寫入到磁碟中。檔案同步就是強制作業系統將緩衝區的內容立即寫入磁碟中,作業系統提供 fsync
和fdatasync
函式進行檔案同步。
appendfsync
配置項的可選值:
- always:每一次執行寫命令都會進行檔案同步,同步完成後才會返回
- everysec:每秒進行一次同步,檔案寫入後就會返回,有專門執行緒每秒進行一次同步
- no:不強制進行同步,讓作業系統決定什麼時候同步
- AOF檔案重寫
AOF檔案不斷追加命令會越來越龐大,比如對於一個列表鍵可能會儲存以下命令:
rpush list 111
rpush list 222
rpush list 333
lpop list
那麼最終這個列表鍵的內容是
1) "222"
2) "333"
對於恢復資料庫資料來說,只要rpush list 222 333
命令就可以達到相同的效果,而且佔用更少的磁碟空間,恢復資料時也執行更少的命令。
bgrewriteaof
命令就是將記憶體中的所有資料都寫成新增命令存到AOF檔案中,這樣就可以讓AOF檔案變小。
bgrewriteaof
命令執行流程如下如所示:
(1) bgrewriteaof
也是由子程序去執行,父程序繼續處理命令。
(2) 子程序會建立一個新的AOF檔案,將資料庫中的資料寫成新增命令寫入這個新的AOF檔案。
(3) 父程序繼續處理命令,仍然將修改命令新增到舊的AOF檔案中,除此之外還會將重寫期間內的修改命令新增到重寫緩衝區中。
(4) 子程序重寫完成後,父程序將重寫緩衝區中的內容寫入到新AOF檔案中
(5) 對檔案改名使用新AOF檔案覆蓋舊AOF檔案,完成AOF重寫。
在子程序執行期間,因為父程序還在執行命令,所以如果沒有重寫緩衝區,新的AOF檔案將缺少子程序執行期間內的修改操作。而且在子程序執行期間,父程序也會將寫命令寫入到舊AOF檔案中,如果這期間發生事故也可以用舊AOF檔案恢復。
bgrewriteaof
也可以通過配置項自動觸發,配置項和其預設值如下:
auto-aof-rewrite-percentage 100 # 當前AOF檔案大小和上一次重寫後AOF檔案大小的增長百分比
auto-aof-rewrite-min-size 64mb # 觸發bgrewriteaof最小的AOF檔案大小
觸發條件虛擬碼如下:
aof_current_size # 當前AOF檔案大小
aof_base_size # 上一次重寫後AOF檔案大小
if ( (aof_current_size > auto-aof-rewrite-min-size)
&& (aof_current_size - aof_base_size) * 100 / aof_base_size >= auto-aof-rewrite-percentage) ) {
}
RDB與AOF
- RDB檔案更加緊湊體積要比AOF檔案小,使用RDB檔案恢復資料也比AOF檔案要快,Redis的主從複製功能就傳輸的是RDB檔案
- 如果發生事故RDB會比AOF丟失更多資料,RDB持久化根據
save
配置隔一段時間執行一次(不能過於頻繁而影響效能),而AOF持久化每一個修改命令都會寫入AOF檔案,如果appendfsync
配置為 everysec,最多丟失1秒的資料 - RDB檔案一旦被建立就不會再被修改了,所以很容易對RDB檔案進行復制來備份資料
- AOF檔案中存的是Redis命令(以Redis協議的格式),所以人很容易看懂
- 如果RDB持久化和AOF持久化都被開啟,Redis啟動時會優先使用AOF檔案進行資料恢復,因為AOF檔案儲存的資料更加完整
參考資料
- 《Redis設計與實現》
- 《Redis開發與運維》
- Redis中文文件