Redis兩種持久化方式原理和單機多實例持久化腳本

注意:Linux系統使用redis需要更改系統的內存分配策略,執行sysctl vm.overcommit_memory=1命令,0-2分別代表不加載、加載、允許超額加載

一、RDB

RDB持久化是把當前數據生成二進制快照保存到硬盤的過程。

配置項:

  • dir:保存路徑
  • dbfilename:保存文件名
  • rdbcompression:是否開啓壓縮,默認開啓,可以方便保存到硬盤和發送給從節點

觸發時機:

  • save:阻塞當前Redis服務器,直到RDB過程完成,線上不建議使用
  • bgsave:Redis主進程執行fork操作創建子進程,RDB持久化過程由子進程完成,阻塞只發生在fork階段。
  • 配置save頻率自動觸發:save m n表示m秒內發生n次修改後自動觸發bgsave
  • 從節點執行全量複製,主節點自動執行bgsave生成RDB文件併發送給從節點
  • 執行debug reload命令重新加載Redis時執行save
  • 如果沒有開啓aof,執行shutdown時回執行bgsave

觸發流程:

  1. 執行bgsave命令,如果正在執行bgsave命令則直接返回
  2. 父進程執行fork操作創建子進程,fork操作時會阻塞主進程
  3. 父進程fork完後主進程不再阻塞,可執行其它命令
  4. 子進程創建RDB文件,寫入完成後替換舊文件
  5. 子進程發送信號通知父進程表示完成,父進程更新統計信息

相關統計信息:

  • 上次fork子進程耗費的微秒數:info stats 命令,latest_fork_usec 項
  • 上次生成RDB的時間戳:info persistence 命令,rdb_last_save_time 項

RDB文件:

Redis加載損壞的RDB拒絕啓動會打印日誌Short read or OOM loading DB,使用 redis-check-dump 命令檢測 RDB 文件,並獲取錯誤報告。

二、AOF

記錄每次的寫命令,寫入格式爲Redis文本協議,重啓時再重新執行AOF中的命令來達到恢復數據的目的,所以恢復速度相對 RDB 較慢。

配置項:

  • dir:保存路徑
  • appendonly:是否開啓
  • appendfilename:存儲文件名
  • appendfsync:同步策略,always 每次寫入調用 fsync,everysec 每秒調用 fsync,no 由系統配置決定調用 fsync 時機,一般30s

工作流程:

  1. 執行 AOF 請求,如果正在執行 AOF 重寫或 bgsave 直接返回
  2. 父進程執行 fork 創建子進程,開銷等同 bgsave,使用寫時複製技術,子進程共享 fork 操作時的內存數據,接下來父進程的操作保存到重寫緩衝區(aof_rewrite_buf)中
  3. 子進程批量寫入新 AOF 文件中,每次批量寫入大小由 aof-rewrite-incremental-fsync 配置控制,開啓後每次寫入32M,防止單次刷盤數據過大造成磁盤阻塞
  4. 新 AOF 文件重寫完成後,發送信號給父進程,父進程更新統計信息
  5. 父進程將 aof_rewrite_buf 中的數據寫入到新的 AOF 文件中
  6. 使用新的 AOF 文件替換老文件,重寫完成

由於AOF追加阻塞造成丟失數據:

當策略爲 everysec 時,丟失數據會有以下兩種情況:

  • 如果距離上次同步成功時間(aof_last_rewrite_time_sec)超過2秒,Redis主線程將會阻塞
  • 如果距離上次同步成功時間在2秒內,會直接返回

如果發生上面任一種情況時宕機,會導致最多2秒的數據丟失。

發生阻塞時,會打印如下日誌:

Asynchronous AOF fsync is taking too lang (disk is busy?).

同時會增加 aof_delayed_fsync 統計項次數(通過 info persistence 查看)

重寫機制:

目的:降低AOF文件存儲空間大小,加快重新加載速度

重寫策略:

  • 超時的數據不再寫入
  • 重複的無效的命令以最新的爲準(比如:set why why,set why why1以後者爲準)
  • 多條寫命令合併爲一個(比如:lpush list a、lpush list b、lpush list b,可以合併爲lpush list a b c)

配置項:

  • auto-aof-rewrite-percentage:觸發當前AOF文件大小和上一次重寫後AOF文件大小的最小比值
  • auto-aof-rewrite-min-size:運行AOF重寫時文件最小體積

相關統計信息:

  • aof_current_size:當前aof文件大小,通過info persistence命令查看
  • aof_base_siz:上次重寫後AOF文件大小,通過info persistence命令查看

觸發機制:

  • 手動觸發:調用bgrewriteaof
  • 自動觸發:aof_current_size > auto-aof-rewrite-min-size 並且 (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage 時自動觸發

三、混合持久化方式

由於 AOF 持久化方式在重啓加載數據時效率遠遠不如 RDB 方式,所以 Redis 在4.0版本後引入了混合持久化方式,配置項爲 aof-use-rdb-preamble,yes開啓,策略爲在生成或寫入 AOF 文件時,將 RDB 數據寫在前面,AOF 數據追加到後面,在每次啓動時先加載 RDB,再加載 AOF ,下面爲配置中的說明:

# When rewriting the AOF file, Redis is able to use an RDB preamble in the
# AOF file for faster rewrites and recoveries. When this option is turned
# on the rewritten AOF file is composed of two different stanzas:
#
#   [RDB file][AOF tail]
#
# When loading Redis recognizes that the AOF file starts with the "REDIS"
# string and loads the prefixed RDB file, and continues loading the AOF
# tail.
aof-use-rdb-preamble yes

四、多實例部署

Redis 單線程架構導致無法充分利用多核 CPU 特性,所以可以在一臺機器上部署多個 Redis 實例。但是當多個實例同時開啓 AOF 重寫後,彼此之間會產生對 CPU 和 IO 的競爭,所以可以通過外部程序輪詢,依此控制每個實例的 AOF 重寫操作執行。

我們依賴的相關監控指標如下:

  • rdb_bgsave_in_progress:bgsave 子進程是否正在運行
  • rdb_last_save_time:當前運行 bgsave 的時間,-1表示未運行
  • aof_enabled:是否開啓 AOF 
  • aof_rewrite_in_progress:AOF 重寫子進程是否正在運行
  • aof_rewrite_scheduled:在 bgsave 結束後是否運行 AOF 重寫
  • aof_current_rewrite_time_sec:當前運行 AOF 重寫的時間,-1表示未運行
  • aof_current_size:AOF 文件當前字節數
  • aof_base_size:AOF 上次重寫 rewrite 的字節數

代碼實現:https://github.com/why444216978/php-redis-aof

運行前看一下 aof 文件更新時間:

why@localhost] /usr/local/var/db/redis$ll
total 48
-rw-r--r--  1 why  staff  9295  5  4 15:31 appendonly.aof
-rw-r--r--  1 why  staff  9295  5  4 15:26 dump.rdb

運行後再看一下 aof 文件更新時間:

[why@localhost] /usr/local/var/db/redis$ll
total 48
-rw-r--r--  1 why  staff  9295  5  4 17:19 appendonly.aof
-rw-r--r--  1 why  staff  9295  5  4 15:26 dump.rdb

成功!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章