Redis持久化策略

> 全是乾貨的技術號: > 本文已收錄在github,歡迎 star/fork: > https://github.com/Wasabi1234/Java-Interview-Tutorial

Redis 對外提供數據訪問服務時,使用的是常駐內存的數據。如果僅將數據存在內存,一旦宕機重啓,數據全部丟失。

1 持久化概論

1.1 什麼是持久化

redis所有數據保持在內存中,對數據的更新將異步地保存到磁盤上。持久化主要是做災難恢復、數據恢復,可歸類到高可用。

比如你的Redis宕機,你要做的事情是讓Redis變得可用,儘快變得可用!

重啓Redis,儘快讓它對外提供服務,若你沒做數據備份,即使Redis啓動了,數據都沒了!可用什麼呢?

很可能說,大量的請求過來,緩存全部無法命中,在Redis里根本找不到數據,這個時候就造成緩存雪崩,就會去MySQL數據庫去找,突然MySQL承接高併發,宕機!

MySQL宕機,你都沒法去找數據恢復到Redis裏面去,Redis的數據從哪兒來?就是從MySQL來的!

若你把Redis的持久化做好,備份和恢復方案也做到,那麼即使你的Redis故障,也可通過備份數據,快速恢復,一旦恢復立即對外提供服務

1.2 持久化方式

Redis提供了兩種持久化方式:

Redis RDB - 快照

RDB 按指定時間間隔執行數據集的時間點快照,類似於MySQL Dump。

Redis AOF - 命令日誌

AOF 會記錄服務器接收的每個寫操作,這些操作將在服務器啓動時再次執行,以重建原始數據集。使用與Redis協議本身相同的格式記錄命令,並且僅採用append-only方式。當日志太大時,Redis可以在後臺重寫日誌。類似於MySQL Binlog、Hbase HLog。在Redis重啓時,通過回放日誌中的寫入指令來重構整個數據。

> 如果希望Redis僅作爲純內存的緩存來用,亦可禁用RDB和AOF。 可以在同一實例中同時使用AOF和RDB。這種情況下,當Redis重新啓動時,AOF文件將用於重建原始數據集,因爲它可以保證是最完整的。

最重要的是理解RDB與AOF持久性之間的不同權衡。如果同時使用RDB和AOF兩種持久化機制,那麼在Redis重啓時,會使用AOF來重新構建數據,因爲AOF中的數據更加完整!

2 RDB - 全量寫入

Redis Server在有多db 中存儲的K.V可理解爲Redis的一個狀態。當發生寫操作時,Redis就會從一個狀態切換到另外一個狀態。 基於全量的持久化就是在某個時刻,將Redis的所有數據持久化到硬盤中,形成一個快照。當Redis 重啓時,通過加載最近一個快照數據,可以將 Redis 恢復至最近一次持久化狀態上。

2.1 觸發方式

save 命令

save 可以由客戶端顯示觸發,也可在redis shutdown 時觸發。 save本身是單線程串行方式執行,因此當數據量大時,可能會發生Redis Server的長時間卡頓。但其備份期間不會有其他命令執行,因此備份時期 數據的狀態始終是一致性的。

若存在老的RDB文件,則新的會替換老的,時間複雜度O(N)。

bgsave

bgsave 也可由

  • 客戶端顯式觸發
  • 配置定時任務觸發
  • 主從架構下由從節點觸發

bgsave命令在執行時,會fork一個子進程。子進程提交完成後,會立即給客戶端返回響應,備份操作在後臺異步執行,期間不會影響Redis的正常響應。

對於bgsave來說,當父進程Fork完子進程之後,異步任務會將當前的內存狀態作爲一個版本進行復制 在複製過程中產生的變更,不會反映在這次備份當中。

不用命令,而使用配置

在Redis的默認配置中,當滿足下面任一條件,會自動觸發 bgsave 的執行: | 配置 | seconds | changes | | --- | --- | --- | | save | 900 | 1 | | save | 300 | 10 | | save | 60 | 10000 |

​​​​​​bgsave相對於save的優勢是異步執行,不影響後續命令執行。但Fork子進程,涉及父進程的內存複製,會增加服務器內存開銷。當內存開銷高到使用虛擬內存時,bgsave的Fork子進程會阻塞運行,可能會造成秒級不可用。因此使用bgsave需要保證服務器空閒內存足夠。

命令 save bgsave
IO類型 同步 異步
是否阻塞 阻塞 非阻塞(在fork時阻塞)
複雜度 O(N) O(N)
優點 不會消耗額外內存 不阻塞客戶端命令
缺點 阻塞客戶端命令 需要fork子進程,內存開銷大

RDB 最佳配置

關閉自動RDB:

dbfilename dump-${port}.rdb
dir /redisDataPath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

需要注意的觸發時機

  • 主從複製時機的全量複製,master節點會執行bgsave
  • debug reload
  • shutdown
  • flushDB 、 flushAll

RDB性質

  1. RDB是Redis內存到硬盤的快照,用於持久化
  2. save通常會阻塞Redis
  3. bgsave不會阻塞Redis,但會fork新進程
  4. save自動配置滿足任一就會被執行

RDB 優點

  • RDB會生成多個數據文件,每個文件都代表了某時刻Redis中的所有數據,這種方式非常適合做冷備,可將這種完整數據文件發送到雲服務器存儲,比如ODPS分佈式存儲,以預定好的備份策略來定期備份Redis中的數據
  • RDB對Redis對外提供的讀寫服務,影響非常小,可讓Redis保持高性能,因爲Redis主進程只要fork一個子進程,讓子進程執行RDB
  • 相對於AOF,直接基於RDB文件重啓和恢復Redis進程,更加快速

RDB缺點

  • 耗時,O(n)
  • fork():耗內存,copy-on-write策略 RDB每次在fork子進程來執行RDB快照數據文件生成的時候,如果數據文件特別大,可能會導致對客戶端提供的服務暫停數毫秒,或者甚至數秒
  • 不可控,容易丟失數據 一般RDB每隔5分鐘,或者更長時間生成一次,若過程中Redis宕機,就會丟失最近未持久化的數據

2.2 恢復流程

當Redis重新啓動時,會從本地磁盤加載之前持久化的文件。當恢復完成之後,再受理後續的請求操作。

3 AOF(append only file)- 增量模式

RDB記錄的是每個狀態的全量數據,AOF記錄的則是每條寫命令的記錄,通過所有寫命令的執行,最後恢復出最終的數據狀態。

  • 其文件的生成如下:

3.1 寫入流程

AOF的三種策略

always

  • 每次刷新緩衝區,都會同步觸發同步操作。因爲每次的寫操作都會觸發同步,所以該策略會降低Redis的吞吐量,但該 模式會擁有最高的容錯能力。

every second

  • 每秒異步的觸發同步操作,爲Redis的默認配置

no

  • 由操作系統決定何時同步,該方式下Redis無法決定何時落地,因此不可控。

對比

命令 always everysec no
優點 不丟失數據 每秒1次fsync,丟1秒數據 無需設置
缺點 IO開銷大,一般的STAT盤只有幾百TPS 丟1秒數據 不可控

3.2 回放流程

AOF的回放時機也是在機器啓動時一旦存在AOF,Redis就會選擇增量回放

因爲增量持久化是持續的寫盤,相比於全量持久化,數據更加完整。回放過程就是將AOF中存放的命令,重新執行一遍。完成後再繼續接收客戶端新命令。

AOF模式的優化重寫

隨着Redis 持續的運行,會有大量的增量數據append 到AOF 文件中。爲了減小硬盤存儲和加快恢復速度,Redis 通過rewrite 機制合併歷史AOF 記錄。如下所示:

原生 AOF

set hello world
set hello java
set hello hehe
incr counter
incr counter
rpush mylist a
rpush mylist b
rpush mylist c
過期數據

AOF 重寫

set hello hehe
set counter 2 
rpush mylist a b c

AOF重寫的作用

  • 減少硬盤佔用量
  • 加速恢復速度

3.3 AOF重寫實現兩種方式

bgrewriteaof

AOF 重寫配置

配置項

  • AOF文件增長率 / AOF文件重寫需要的大小
  • AOF當前尺寸(單位:字節)
  • aof_base_size AOF 上次啓動和重寫的大小(單位:字節)

自動觸發配置

aof_current_size > auto-aof-rewrite-min-size
aof_current_size - aof_base_size/aof_base_size > auto-aof-rewrite-percentage

3.4 AOF 重寫流程

AOF 重寫配置

修改配置文件

appendonly yes
appendfilename "appendonly-$(port).aof"
appendfsync everysec
dir /opt/soft/redis/data
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
no-appendfsync-on-rewrite yes

AOF的優點

  • 更好避免數據丟失 一般AOF每隔1s,通過子進程執行一次fsync,最多丟1s數據
  • append-only模式追加寫 所以沒有任何磁盤尋址的開銷,寫入性能高,且文件不易破損,即使文件尾部破損,也易修復
  • 日誌文件即使過大,出現後臺重寫操作,也不會影響客戶端的讀寫 因爲在rewrite log時,會壓縮其中的指令,創建出一份需要恢復數據的最小日誌。在創建新日誌時,舊日誌文件還是照常寫入。當新的merge後的日誌文件準備好時,再交換新舊日誌文件即可!
  • 命令通過非常可讀的方式記錄 該特性非常適合做災難性誤刪除操作的緊急恢復。 比如某人不小心用flushall命令清空了所有數據,只要這個時候後臺rewrite還沒有發生,可立即拷貝AOF文件,將最後一條flushall命令給刪了,然後再將該AOF文件放回去,就可通過恢復機制,自動恢復所有數據

2.2.2 AOF的缺點

  • 對於同一份數據,AOF日誌一般比RDB快照更大
  • AOF開啓後,寫QPS會比RDB的低,因爲AOF一般會配置成每s fsync一次日誌文件,當然,每s一次fsync,性能也還是很高的
  • 以前AOF發生過bug,就是通過AOF記錄的日誌,進行數據恢復的時候,沒有恢復一模一樣的數據出來 類似AOF這種較爲複雜的基於命令日誌/merge/回放的方式,比基於RDB的每次持久化一份完整的數據快照方式相比更加脆弱一些,易產生bug 不過AOF就是爲了避免rewrite過程導致的bug,因此每次rewrite並不是基於舊的指令日誌進行merge的,而是基於當時內存中的數據進行指令的重新構建,這樣健壯性會更好

4 選型及最佳實踐

命令 RDB AOF
啓動優先級
體積
恢復速度
數據安全性 丟數據 根據策略決定
量級 重量級 輕量級

4.1 RDB最佳策略

  • 關閉
  • 集中手動管理RDB操作
  • 在從節點打開自動執行配置,但是不宜頻繁執行RDB

4.2 AOF最佳策略

  • 建議打開,但是如果只是純作爲緩存使用可不開
  • AOF重寫集中管理
  • everysec

4.3 抉擇RDB & AOF

  1. 不要僅使用RDB,因爲那樣會導致你丟失很多數據
  2. 也不要僅使用AOF,因爲那樣有兩個問題
    • 你通過AOF做冷備,沒有RDB做冷備,來的恢復速度更快
    • RDB每次簡單粗暴生成數據快照,更加健壯,可以避免AOF這種複雜的備份和恢復機制的bug
  3. 綜合使用AOF和RDB
    • 用AOF保證數據不丟失,作爲數據恢復的第一選擇
    • 用RDB做不同程度的冷備,在AOF文件都丟失或損壞不可用時,還可使用RDB快速實現數據恢復

4.4 一些最佳實踐

  • 小分片 例如設置maxmemory參數設置每個redis只存儲4個G的空間,這樣各種操作都不會太慢
  • 監控(硬盤、內存、負載、網絡)
  • 足夠的內存

參考

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