Redis持久化
Java大猿帥成長手冊,GitHub JavaEgg ,N線互聯網開發必備技能兵器譜
Redis 的數據全部在內存里,如果突然宕機,數據就會全部丟失,因此必須有一種機制來保證 Redis 的數據不會因為故障而丟失,這種機制就是 Redis 的持久化機制。
Redis有兩種持久化的方式:快照(RDB
文件)和追加式文件(AOF
文件)
RDB(Redis DataBase)
是什么
在指定的時間間隔內將內存中的數據集快照寫入磁盤,也就是行話講的Snapshot快照,它恢復時是將快照文件直接讀到內存里。
Redis會單獨創建(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。整個過程中,主進程是不進行任何IO操作的,這就確保了極高的性能,如果需要進行大規模數據的恢復,且對於數據恢復的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB的缺點是最后一次持久化后的數據可能丟失。
? What ? Redis 不是單進程的嗎?
Redis 使用操作系統的多進程 COW(Copy On Write) 機制來實現快照持久化, fork是類Unix操作系統上創建進程的主要方法。COW(Copy On Write)是計算機編程中使用的一種優化策略。
Fork
fork 的作用是復制一個與當前進程一樣的進程。新進程的所有數據(變量、環境變量、程序計數器等)數值都和原進程一致,但是是一個全新的進程,並作為原進程的子進程。 子進程讀取數據,然后序列化寫到磁盤中
rdb 默認保存的是dump.rdb文件
你可以對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動保存一次數據集。
你也可以通過調用 SAVE 或者 BGSAVE , 手動讓 Redis 進行數據集保存操作。
比如說, 以下設置會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動保存一次數據集:
save 60 1000
這種持久化方式被稱為快照(snapshot)。
配置位置: SNAPSHOTTING
如何觸發RDB快照
-
配置文件中默認的快照配置
冷拷貝后重新使用 可以
cp dump.rdb dump_new.rdb
-
命令save或者是bgsave
- Save:save時只管保存,其它不管,全部阻塞
- BGSAVE:Redis會在后台異步進行快照操作,快照同時還可以響應客戶端請求。可以通過lastsave命令獲取最后一次成功執行快照的時間
- 執行flushall命令,也會產生dump.rdb文件,但里面是空的,無意義
快照的運作方式
當 Redis 需要保存 dump.rdb 文件時, 服務器執行以下操作:
- Redis 調用 fork() ,產生一個子進程,此時同時擁有父進程和子進程。
- 子進程將數據集寫入到一個臨時 RDB 文件中。
- 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。
如何恢復
將備份文件 (dump.rdb) 移動到 redis 安裝目錄並啟動服務即可(CONFIG GET dir獲取目錄)
優勢
- 一旦采用該方式,那么你的整個Redis數據庫將只包含一個文件,這對於文件備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的數據,同時還要每天歸檔一次最近30天的數據。通過這樣的備份策略,一旦系統出現災難性故障,我們可以非常容易的進行恢復。適合大規模的數據恢復
- 對於災難恢復而言,RDB是非常不錯的選擇。因為我們可以非常輕松的將一個單獨的文件壓縮后再轉移到其它存儲介質上。
- 性能最大化。對於Redis的服務進程而言,在開始持久化時,它唯一需要做的只是fork出子進程,之后再由子進程完成這些持久化的工作,這樣就可以極大的避免服務進程執行IO操作了。
- 相比於AOF機制,如果數據集很大,RDB的啟動效率會更高。
劣勢
- 如果你想保證數據的高可用性,即最大限度的避免數據丟失,那么RDB將不是一個很好的選擇。因為系統一旦在定時持久化之前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失(丟失最后一次快照后的所有修改)。
- 由於RDB是通過fork子進程來協助完成數據持久化工作的,內存中的數據被克隆了一份,大致2倍的膨脹性需要考慮,因此,如果當數據集較大時,可能會導致整個服務器停止服務幾百毫秒,甚至是1秒鍾。
如何停止
動態停止RDB保存規則的方法:redis-cli config set save ""
總結
-
RDB是一個非常緊湊的文件
-
RDB在保存RDB文件時父進程唯一需要做的就是fork出一個子進程,接下來的工作全部由子進程來做,父進程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能
-
與AOF相比,在恢復大的數據集的時候,RDB方式會更快一些
-
數據丟失風險大
-
RDB需要經常fork子進程來保存數據集到硬盤上,當數據集比較大的時候,fork的過程是非常耗時的,可能會導致redis在一些毫秒級不能響應客戶端的請求
AOF(Append Only File)
是什么
以日志的形式來記錄每個寫操作,將 Redis 執行過的所有寫指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis 啟動之初會讀取該文件重新構建數據,也就是「重放」。換言之,redis 重啟的話就根據日志文件的內容將寫指令從前到后執行一次以完成數據的恢復工作。
AOF 默認保存的是 **appendonly.aof ** 文件
配置位置: APPEND ONLY MODE
AOF啟動/修復/恢復
-
正常恢復
- 啟動:設置Yes 修改默認的appendonly no,改為yes
- 將有數據的 aof 文件復制一份保存到對應目錄(config get dir)
- 恢復:重啟redis然后重新加載
-
異常恢復
- 啟動:設置Yes 修改默認的appendonly no,改為yes
- 備份被寫壞的AOF文件
- 修復:redis-check-aof --fix進行修復 + AOF文件
- 恢復:重啟redis然后重新加載
rewrite(AOF 重寫)
- 是什么:AOF采用文件追加方式,文件會越來越大為避免出現此種情況,新增了重寫機制,當 AOF 文件的大小超過所設定的閾值時,Redis就會啟動 AOF 文件的內容壓縮,只保留可以恢復數據的最小指令集,可以使用命令
bgrewriteaof
- 重寫原理:AOF 文件持續增長而過大時,會 fork 出一條新進程來將文件重寫(也是先寫臨時文件最后再rename),遍歷新進程的內存中數據,每條記錄有一條的 Set 語句。重寫 aof 文件的操作,並沒有讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的 aof 文件,這點和快照有點類似
- 觸發機制:Redis 會記錄上次重寫時的 AOF 大小,默認配置是當 AOF 文件大小是上次 rewrite 后大小的一倍且文件大於64M 時觸發
AOF耐久性
你可以配置 Redis 多久才將數據 fsync 到磁盤一次。
有三個選項:
- 每次有新命令追加到 AOF 文件時就執行一次 fsync :非常慢,也非常安全。
- 每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鍾的數據。
- 從不 fsync :將數據交給操作系統來處理。更快,也更不安全的選擇。
推薦(並且也是默認)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
總是 fsync 的策略在實際使用中非常慢,頻繁調用 fsync 注定了這種策略不可能快得起來。
如果 AOF 文件出錯了,怎么辦?
服務器可能在程序正在對 AOF 文件進行寫入時停機, 如果停機造成了 AOF 文件出錯(corrupt), 那么 Redis 在重啟時會拒絕載入這個 AOF 文件, 從而確保數據的一致性不會被破壞。
當發生這種情況時, 可以用以下方法來修復出錯的 AOF 文件:
- 為現有的 AOF 文件創建一個備份。
- 使用 Redis 附帶的 redis-check-aof 程序,對原來的 AOF 文件進行修復。
$ redis-check-aof --fix
- (可選)使用 diff -u 對比修復后的 AOF 文件和原始 AOF 文件的備份,查看兩個文件之間的不同之處。
- 重啟 Redis 服務器,等待服務器載入修復后的 AOF 文件,並進行數據恢復。
AOF運作方式
AOF 重寫和 RDB 創建快照一樣,都巧妙地利用了寫時復制機制。
以下是 AOF 重寫的執行步驟:
- Redis 執行 fork() ,現在同時擁有父進程和子進程。
- 子進程開始將新 AOF 文件的內容寫入到臨時文件。
- 對於所有新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有 AOF 文件的末尾: 這樣即使在重寫的中途發生停機,現有的 AOF 文件也還是安全的。
- 當子進程完成重寫工作時,它給父進程發送一個信號,父進程在接收到信號之后,將內存緩存中的所有數據追加到新 AOF 文件的末尾。
- 搞定!現在 Redis 原子地用新文件替換舊文件,之后所有命令都會直接追加到新 AOF 文件的末尾。
優勢
- 該機制可以帶來更高的數據安全性,即數據持久性。Redis中提供了3種同步策略,即每秒同步、每修改同步和不同步。事實上,每秒同步也是異步完成的,其效率也是非常高的,所差的是一旦系統出現宕機現象,那么這一秒鍾之內修改的數據將會丟失。而每修改同步,我們可以將其視為同步持久化,即每次發生的數據變化都會被立即記錄到磁盤中。可以預見,這種方式在效率上是最低的。至於無同步,無需多言,我想大家都能正確的理解它。
- 由於該機制對日志文件的寫入操作采用的是append模式,因此在寫入過程中即使出現宕機現象,也不會破壞日志文件中已經存在的內容。然而如果我們本次操作只是寫入了一半數據就出現了系統崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決數據一致性的問題。
- 如果日志過大,Redis可以自動啟用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會創建一個新的文件用於記錄此期間有哪些修改命令被執行。因此在進行rewrite切換時可以更好的保證數據安全性。
- AOF 包含一個格式清晰、易於理解的日志文件用於記錄所有的修改操作。事實上,我們也可以通過該文件完成數據的重建。因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。 導出(export) AOF 文件也非常簡單: 舉個例子, 如果你不小心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那么只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啟 Redis , 就可以將數據集恢復到 FLUSHALL 執行之前的狀態。
劣勢
- 對於相同數量的數據集而言,AOF文件通常要大於RDB文件。恢復速度慢於rdb。
- 根據同步策略的不同,AOF在運行效率上往往會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。
總結
- AOF 文件是一個只進行追加的日志文件
- Redis 可以在 AOF 文件體積變得過大時,自動在后台對 AOF 進行重寫
- AOF文件有序的保存了對數據庫執行的所有寫入操作,這些寫入操作以Redis協議的格式保存,因此AOF文件的內容非常容易被人讀懂,對文件進行分析也很輕松
- 對於相同的數據集來說,AOF 文件的體積通常需要大於 RDB 文件的體積
- 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB
怎么從 RDB 持久化切換到 AOF 持久化
在 Redis 2.2 或以上版本,可以在不重啟的情況下,從 RDB 切換到 AOF :
- 為最新的 dump.rdb 文件創建一個備份。
- 將備份放到一個安全的地方。
- 執行以下兩條命令:
redis-cli> CONFIG SET appendonly yes
redis-cli> CONFIG SET save ""
- 確保命令執行之后,數據庫的鍵的數量沒有改變。
- 確保寫命令會被正確地追加到 AOF 文件的末尾。
步驟 3 執行的第一條命令開啟了 AOF 功能: Redis 會阻塞直到初始 AOF 文件創建完成為止, 之后 Redis 會繼續處理命令請求, 並開始將寫入命令追加到 AOF 文件末尾。
步驟 3 執行的第二條命令用於關閉 RDB 功能。 這一步是可選的, 如果你願意的話, 也可以同時使用 RDB 和 AOF 這兩種持久化功能。
別忘了在 redis.conf 中打開 AOF 功能! 否則的話, 服務器重啟之后, 之前通過 CONFIG SET 設置的配置就會被遺忘, 程序會按原來的配置來啟動服務器。
Which one
-
RDB 持久化方式能夠在指定的時間間隔能對你的數據進行快照存儲
-
AOF 持久化方式記錄每次對服務器寫的操作,當服務器重啟的時候會重新執行這些命令來恢復原始的數據,AOF命令以 redis 協議追加保存每次寫的操作到文件末尾。Redis還能對AOF文件進行后台重寫(bgrewriteaof),使得 AOF 文件的體積不至於過大
-
只做緩存:如果你只希望你的數據在服務器運行的時候存在,你也可以不使用任何持久化方式。
-
同時開啟兩種持久化方式
- 在這種情況下,當 redis 重啟的時候會優先載入 AOF 文件來恢復原始的數據,因為在通常情況下 AOF 文件保存的數據集要比 RDB 文件保存的數據集要完整。
- RDB 的數據不實時,同時使用兩者時服務器重啟也只會找 AOF 文件。那要不要只使用AOF 呢?建議不要,因為 RDB 更適合用於備份數據庫(AOF 在不斷變化不好備份),快速重啟,而且不會有 AOF 可能潛在的bug,留着作為一個萬一的手段。
性能建議
- 因為 RDB 文件只用作后備用途,建議只在 Slave上持久化 RDB 文件,而且只要15分鍾備份一次就夠了,只保留save 900 1這條規則。
- 如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒數據,啟動腳本較簡單只load自己的 AOF 文件就可以了。代價一是帶來了持續的 IO,二是 AOF rewrite 的最后將 rewrite 過程中產生的新數據寫到新文件造成的阻塞幾乎是不可避免的。只要硬盤許可,應該盡量減少 AOF rewrite 的頻率,AOF 重寫的基礎大小默認值64M太小了,可以設到5G以上。默認超過原大小100%大小時重寫可以改到適當的數值。
- 如果不 Enable AOF ,僅靠 Master-Slave Replication 實現高可用性也可以。能省掉一大筆 IO ,也減少了rewrite 時帶來的系統波動。代價是如果 Master/Slav e同時宕掉,會丟失十幾分鍾的數據,啟動腳本也要比較兩個Master/Slave中的RDB文件,載入較新的那個。
某免費教學視頻