【Redis】9.持久化
1. 介紹
Redis提供了兩種不同形式的持久化方式:
- RDB (Redis DataBase)
- AOF (Append Only File)
2. RDB (Redis DataBase)
2.1 介紹
在指定的時間間隔內將記憶體中的資料集快照寫入磁碟, 也就是行話講的Snapshot快照,它恢復時是將快照檔案直接讀到記憶體裡。
2.2 RDB備份執行過程
Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到 一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。 整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能。如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的資料可能丟失
2.2.1 Fork
- Fork的作用是複製一個與當前程序一樣的程序。新程序的所有資料(變數、環境變數、程式計數器等) 數值都和原程序一致,但是是一個全新的程序,並作為原程序的子程序
- 在Linux程式中,fork()會產生一個和父程序完全相同的子程序,但子程序在此後多會exec系統呼叫,出於效率考慮,Linux中引入了“寫時複製技術”
- 一般情況父程序和子程序會共用同一段實體記憶體,只有程序空間的各段的內容要發生變化時,才會將父程序的內容複製一份給子程序。
2.2.2 RDB持久化流程
2.3 dump.rdb檔案
在redis.conf中配置檔名稱,預設為dump.rdb
rdb檔案的儲存路徑,也可以修改。預設為Redis啟動時命令列所在的目錄下,dir "/myredis/"
2.4 如何觸發RDB快照:保持策略
2.4.1 配置檔案中預設的快照位置
2.4.2 命令save VS bgsave
-
save :save時只管儲存,其它不管,全部阻塞。手動儲存。不建議。
- 格式:save 秒鐘 寫操作次數
- RDB是整個記憶體的壓縮過的Snapshot,RDB的資料結構,可以配置複合的快照觸發條件,預設是1分鐘內改了1萬次,或5分鐘內改了10次,或15分鐘內改了1次。
- 禁用方式:不設定save指令,或者給save傳入空字串。
-
bgsave:Redis會在後臺非同步進行快照操作, 快照同時還可以響應客戶端請求。
可以通過lastsave 命令獲取最後一次成功執行快照的時間。
2.4.3 flushall命令
執行flushall命令,也會產生dump.rdb檔案,但裡面是空的,無意義
2.4.4 stop-writes-on-bgsave-error
當Redis無法寫入磁碟的話,直接關掉Redis的寫操作。推薦yes.
2.4.5 rdbcompression 壓縮檔案
對於儲存到磁碟中的快照,可以設定是否進行壓縮儲存。如果是的話,redis會採用LZF演算法進行壓縮。如果不想消耗CPU來進行壓縮的話,可以設定為關閉此功能。推薦yes。
2.4.6 rdbchecksum 檢查完整性
在儲存快照後,還可以讓redis使用CRC64演算法來進行資料校驗,但是這樣做會增加大約10%的效能消耗,如果希望獲取到最大的效能提升,可以關閉此功能。推薦yes。
2.4.7 rdb的備份
先通過config get dir 查詢rdb檔案的目錄,將*.rdb的檔案拷貝到別的地方。
rdb的恢復:
- 關閉Redis
- 先把備份的檔案拷貝到工作目錄下 cp dump2.rdb dump.rdb
- 啟動Redis, 備份資料會直接載入
2.5 優勢
- 適合大規模的資料恢復
- 對資料完整性和一致性要求不高更適合使用
- 節省磁碟空間
- 恢復速度快
2.6 劣勢
-
Fork的時候,記憶體中的資料被克隆了一份,大致2倍的膨脹性需要考慮
-
雖然Redis在fork時使用了寫時拷貝技術,但是如果資料龐大時還是比較消耗效能。
-
在備份週期在一定間隔時間做一次備份,所以如果Redis意外down掉的話,就會丟失最後一次快照後的所有修改。
2.7 停止使用RDB
動態停止RDB:redis-cli config set save ""#save後給空值,表示禁用儲存策略
2.8 RDB總結
- RDB是一個非常緊湊的檔案
- RDB在儲存RDB檔案時父程序唯一需要做的就是fork出一個子程序,接下來的工作全部都由子程序來做,父程序不需要再做其他IO操作,所以RDB持久化方式可以最大化redis效能。
- 與AOF相比,在恢復大的資料集的時候RDB方式會快一些。
- 資料丟失風險大。
- RDB需要經常fork子程序來儲存資料集到硬碟上,當資料集比較大的時候,fork的過程是非常耗時的,可能會導致redis無法響應一些毫秒級的客戶端請求。
3. AOF (Append Only File)
3.1 介紹
以日誌的形式來記錄每個寫操作(增量儲存),將Redis執行過的所有寫指令記錄下來(讀操作不記錄), 只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis 重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作。
3.2 AOF備份過程
- 客戶端的請求寫命令會被append追加到AOF緩衝區內;
- AOF緩衝區根據AOF持久化策略[always,everysec,no]將操作sync同步到磁碟的AOF檔案中;
- AOF檔案大小超過重寫策略或手動重寫時,會對AOF檔案rewrite重寫,壓縮AOF檔案容量;
- Redis服務重啟時,會重新load載入AOF檔案中的寫操作達到資料恢復的目的;
3.3 AOF配置
3.3.1 名稱配置
可以在redis.conf中配置檔名稱,預設為 appendonly.aof。AOF檔案的儲存路徑,同RDB的路徑一致。
3.3.2 啟動
將appendonly no改為yes
3.4 AOF和RDB同時開啟
AOF和RDB同時開啟,系統預設取AOF的資料(資料不會存在丟失)。
3.5 AOF啟動/修復/恢復
- AOF的備份機制和效能雖然和RDB不同, 但是備份和恢復的操作同RDB一樣,都是拷貝備份檔案,需要恢復時再拷貝到Redis工作目錄下,啟動系統即載入。
- 正常恢復:
- 修改預設的appendonly no,改為yes
- 將有資料的aof檔案複製一份儲存到對應目錄(檢視目錄:config get dir)
- 恢復:重啟redis然後重新載入
- 異常恢復:
- 修改預設的appendonly no,改為yes
- 如遇到AOF檔案損壞,通過/usr/local/bin/redis-check-aof--fix appendonly.aof進行恢復
- 備份被寫壞的AOF檔案。
- 恢復:重啟redis,然後重新載入。
3.6 AOF同步頻率設定
- appendfsync always
- 始終同步,每次Redis的寫入都會立刻記入日誌;效能較差但資料完整性比較好
- appendfsync everysec
- 每秒同步,每秒記入日誌一次,如果宕機,本秒的資料可能丟失。
- appendfsync no
- redis不主動進行同步,把同步時機交給作業系統。
3.7 rewrite 壓縮
3.7.1 rewrite介紹
AOF採用檔案追加方式,檔案會越來越大為避免出現此種情況,新增了重寫機制, 當AOF檔案的大小超過所設定的閾值時,Redis就會啟動AOF檔案的內容壓縮, 只保留可以恢復資料的最小指令集.可以使用命令bgrewriteaof
3.7.2 rewrite原理
AOF檔案持續增長而過大時,會fork出一條新程序來將檔案重寫(也是先寫臨時檔案最後再rename),redis4.0版本後的重寫,是指上就是把rdb的快照,以二級制的形式附在新的aof頭部,作為已有的歷史資料,替換掉原來的流水賬操作。
3.7.2.1 no-appendfsync-on-rewrite
如果 no-appendfsync-on-rewrite=yes ,不寫入aof檔案只寫入快取,使用者請求不會阻塞,但是在這段時間如果宕機會丟失這段時間的快取資料(降低資料安全性,提高效能)。
如果 no-appendfsync-on-rewrite=no, 還是會把資料往磁盤裡刷,但是遇到重寫操作,可能會發生阻塞。(資料安全,但是效能降低)。
3.7.2.2 觸發機制
Redis會記錄上次重寫時的AOF大小,預設配置是當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發。
重寫雖然可以節約大量磁碟空間,減少恢復時間。但是每次重寫還是有一定的負擔的,因此設定Redis要滿足一定條件才會進行重寫。
- auto-aof-rewrite-percentage:設定重寫的基準值,檔案達到100%時開始重寫(檔案是原來重寫後文件的2倍時觸發)。
- auto-aof-rewrite-min-size:設定重寫的最小值,最小檔案64MB。達到這個值開始重寫。
例如:檔案達到70MB開始重寫,降到50MB,下次什麼時候開始重寫?100MB
系統載入時或者上次重寫完畢時,Redis會記錄此時AOF大小,設為base_size,如果Redis的AOF當前大小>= base_size +base_size*100% (預設)且當前大小>=64mb(預設)的情況下,Redis會對AOF進行重寫。
3.7.3 重寫流程
-
bgrewriteaof觸發重寫,判斷是否當前有bgsave或bgrewriteaof在執行,如果有,則等待該命令結束後再繼續執行。
-
主程序fork出子程序執行重寫操作,保證主程序不會阻塞。
-
子程序遍歷redis記憶體中資料到臨時檔案,客戶端的寫請求同時寫入aof_buf緩衝區和aof_rewrite_buf重寫緩衝區保證原AOF檔案完整以及新AOF檔案生成期間的新的資料修改動作不會丟失。
-
(1) 子程序寫完新的AOF檔案後,向主程序發訊號,父程序更新統計資訊。
(2) 主程序把aof_rewrite_buf中的資料寫入到新的AOF檔案。
-
使用新的AOF檔案覆蓋舊的AOF檔案,完成AOF重寫。
3.8 優勢
- 備份機制更穩健,丟失資料概率更低。
- 可讀的日誌文字,通過操作AOF穩健,可以處理誤操作。
3.9 劣勢
- 比起RDB佔用更多的磁碟空間。
- 恢復備份速度要慢。
- 每次讀寫都同步的話,有一定的效能壓力。
- 存在個別Bug,造成不能恢復。
3.10 AOF總結
- AOF檔案是一個只進行追加的日誌檔案。
- Redis可以在AOF檔案大小變得過大時,自動在後臺對AOF進行重寫。
- AOF檔案有序地儲存了對資料庫執行的所有寫入操作。這些寫入操作以Reids協議的格式儲存,因此AOF檔案的內容非常容易被人讀懂,對檔案進行分析也很輕鬆。
- 對於相同的資料集雷說,AOF檔案的大小通常大於RDB檔案的大小。
- 根據所使用的fsync策略,AOF的速度可能會慢於RDB。
4. 總結
4.1 RDB與AOF對比
官方推薦兩個都啟用。如果對資料不敏感,可以選單獨用RDB。不建議單獨用 AOF,因為可能會出現Bug。如果只是做純記憶體快取,可以都不用。
4.2 官網建議
- RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存。
- AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾。
- Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大。
- 只做快取:如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式。
- 同時開啟兩種持久化方式
- 在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料, 因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整.
- RDB的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案。那要不要只使用AOF呢? 建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份), 快速重啟,而且不會有AOF可能潛在的bug,留著作為一個萬一的手段。
- 效能建議:
- 因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。
- 如果使用AOF,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單,只load自己的AOF檔案就可以了。
- 代價:一是帶來了持續的IO,二是AOF rewrite的最後將rewrite過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。
- 只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。
- 預設超過原大小100%大小時重寫可以改到適當的數值。