Redis 持久化機制(快照、AOF)
Redis 是 內存數據庫,但是它也能夠將存儲的數據保存在硬盤上,這是由於它的持久化機制。
Redis 官方提供了兩種不同的持久化方法來將數據存儲到硬盤裏面分別是:
- 快照 (Snapshot)
- AOF (Append Only File) 只追加日誌文件
快照 (Snapshot)
這種方式可以將某一時刻的所有數據都寫入硬盤中,這也是Redis 的默認開啓持久化方式,保存的文件是以 .rdb
形式結尾的文件,因此這種方式也稱之爲 RDB方式。
快照生成方式:
- 客戶端方式:
BGSAVE
和SAVE
指令 - 服務器配置自動觸發
- 服務器
SHUTDOWN
自動觸發
1. 客戶端方式之 BGSAVE(多線程執行)
客戶端可以使用 BGSAVE
命令來創建一個快照,當接收到客戶端的 BGSAVE
命令時,Redis 會調用 fork
來創建一個子進程,然後子進程負責將快照寫入磁盤中,而父進程則繼續處理命令請求。
fork:當一個進程創建子進程的時候,底層的操作系統會創建該進程的一個副本,在類unix系統中創建子進程的操作會進行優化:在剛開始的時候,父子進程共享相同內存,直到父進程或子進程對內存進行了寫之後,對被寫入的內存的共享纔會結束服務。
2. 客戶端方式之 SAVE(單線程執行)
客戶端還可以使用 SAVE
命令來創建一個快照,接收到 SAVE
命令的 Redis服務器在快照創建完畢之前將不再響應任何其他的命令;
注意:SAVE
命令並不常用,使用 SAVE
命令在快照創建完畢之前,Redis處於阻塞狀態,無法對外服務。
3. 服務器配置方式之 配置快照觸發條件
如果用戶在 redis.conf 中設置了 save 配置選項,Redis 會在 save 選項條件滿足之後自動觸發一次 BGSAVE
命令;如果設置多個 save 配置選項,當任意一個 save 配置選項條件滿足,Redis 也會觸發一次 BGSAVE
命令。
save 900 1 表示 900s 內,執行了 1次 數據庫操作則自動創建快照,以此類推。
4. 服務器接收客戶端 SHUTDOWN 指令
當 Redis 通過 SHUTDOWN
指令接收到關閉服務器的請求時,會執行一個 SAVE
命令,阻塞所有的客戶端,不再執行客戶端執行發送的任何命令,並且在 SAVE
命令執行完畢之後關閉服務器。
配置文件中配置生成快照名稱和位置
配置文件中可以修改生成快照名稱以及快照保存位置:
# 生成快照名字, 默認爲 dump.rdb
dbfilename dump.rdb
# 快照保存位置, 默認保存在 redis-cli 同級目錄
dir ./
只追加日誌文件 AOF (Append Only File)
在 Redis 的默認配置中 AOF持久化機制是沒有開啓的,需要在配置中開啓;
# 開啓 AOF持久化
appendonly yes
# 生成的日誌文件名稱
appendfilename "appendonly.aof"
# aof日誌文件路徑與快照保存位置設置的是同一個
dir ./
AOF 有 3 種 日誌追加頻率:
- always 【謹慎使用】
- everysec 【推薦】
- no【不推薦】
1.always【謹慎使用】
- 說明:每個 redis寫命令 都要同步寫入硬盤,嚴重降低 redis 速度;
- 解釋:如果用戶使用了 always 選項,那麼每個 redis 寫命令都會被寫入硬盤,從而將發生系統崩潰時出現的數據丟失減到最少;遺憾的是,因爲這種同步策略需要對硬盤進行大量的寫入操作,所以 redis 處理命令的速度會受到硬盤性能的限制;
- 注意:轉盤式硬盤(機械硬盤)在這種頻率下200左右個命令/s;固態硬盤(SSD) 幾百萬個命令/s;
- 警告:使用SSD用戶請謹慎使用 always 選項,這種模式不斷寫入少量數據的做法有可能會引發嚴重的 寫入放大 問題,導致將固態硬盤的壽命從原來的幾年降低爲幾個月。
2.everysec【推薦】
- 說明:每秒 執行一次同步顯式的將多個寫命令同步到磁盤;
- 解釋:爲了兼顧數據安全和寫入性能,可以使用 everysec 選項,讓 redis 每秒一次的頻率對AOF文件進行同步;redis 每秒同步一次AOF文件時性能和不使用任何持久化特性時的性能相差無幾,而通過每秒同步一次AOF文件,redis可以保證,即使系統崩潰,用戶最多丟失一秒之內產生的數據。
3.no【不推薦】
- 說明:由操作系統決定何時同步;
- 解釋:使用 no 選項,將完全有操作系統決定什麼時候同步AOF日誌文件,這個選項不會對 redis 性能帶來影響,但是系統崩潰時,會丟失不定數量的數據,另外如果用戶硬盤處理寫入操作不夠快的話,當緩衝區被等待寫入硬盤數據填滿時,redis 會處於阻塞狀態,並導致 redis 的處理命令請求的速度變慢。
配置文件中修改同步頻率
# appendfsync always
appendfsync everysec
# appendfsync no
AOF文件重寫機制
AOF帶來的問題
AOF的方式也同時帶來了另一個問題:持久化文件會變的越來越大。
例如我們調用 incr test
命令 100 次,文件中必須保存全部的 100 條命令,其實有 99 條都是多餘的,因爲要恢復數據庫的狀態其實文件中保存一條 set test 100
就夠了。爲了壓縮 AOF 的持久化文件,Redis 提供了 AOF重寫(ReWriter)機制。
AOF 重寫機制 在一定程度下減少 aof 文件的體積。
觸發重寫方式有兩種:
1. 客戶端方式 觸發重寫
執行 BGREWRITEAOF
命令,這種方式不會阻塞 redis 的服務;
2. 服務器配置方式 自動觸發
配置 redis.conf 中的 auto-aof-rewrite-percentage 選項:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
如果開啓了 AOF持久化,以上配置代表:當AOF文件體積大於 64M,並且AOF文件的體積比上一次重寫之後體積大了 100%(1倍) 時,自動觸發重寫。 如果重寫過於頻繁,可以考慮將 auto-aof-rewrite-percentage 設置的更大。
重寫原理
注意:重寫 aof文件 的操作,並沒有讀取舊的 aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的 aof文件,替換原有的文件,這點和快照有點類似。
重寫流程:
- redis 調用
fork
,現在有父子兩個進程,子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令; - 父進程繼續處理 client 請求,除了把寫命令寫入到原來的 aof文件 中,同時 把收到的寫命令緩存起來,這樣就能保證如果子進程重寫失敗的話並不會出問題。
- 當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程,然後父進程把緩存的寫命令也寫入到臨時文件。
- 現在父進程可以使用臨時文件替換老的 aof文件,並重命名,後面收到的寫命令也開始往新的 aof文件 中追加。
Redis 持久化總結
兩種持久化方案既可以同時使用,又可以單獨使用,在某種情況下也可以都不使用,具體使用那種持久化方案取決於用戶的數據和應用決定。
無論使用 AOF 還是 快照機制持久化,將數據持久化到硬盤都是有必要的,除了持久化外,用戶還應該對持久化的文件進行備份(最好備份在多個不同地方)。