網路知識 | 《圖解TCP/IP》讀書筆記(下)
RDB快照(snapshot)
在預設情況下, Redis 將記憶體資料庫快照儲存在名字為 dump.rdb 的二進位制檔案中。
你可以對 Redis 進行設定, 讓它在“ N 秒內資料集至少有 M 個改動”這一條件被滿足時, 自動儲存一次資料集。
比如說, 以下設定會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動儲存一次資料集:
# save 60 1000
關閉RDB只需要將所有的save儲存策略註釋掉即可
還可以手動執行命令生成RDB快照,進入redis客戶端執行命令save或bgsave可以生成dump.rdb檔案,每次命令執行都會將所有redis記憶體快照到一個新的rdb檔案裡,並覆蓋原有rdb快照檔案。
save是同步命令,bgsave是非同步命令,bgsave會從redis主程序fork(fork()是linux函式)出一個子程序專門用來生成rdb快照檔案
save與bgsave對比:
命令 | save | bgsave |
---|---|---|
IO型別 | 同步 | 非同步 |
是否阻塞redis其它命令 | 是 | 否(在生成子程序執行呼叫fork函式時會有短暫阻塞) |
複雜度 | O(n) | O(n) |
優點 | 不會消耗額外記憶體 | 不阻塞客戶端命令 |
缺點 | 阻塞客戶端命令 | 需要fork子程序,消耗記憶體 |
RDB檔案存放位置:
檢視存放的檔案:
是否開啟壓縮模式:
RDB常用配置總結
下面是RDB常用的配置項,以及預設值(前面介紹過的這裡不再詳細介紹):
- save m n:bgsave自動觸發的條件;如果沒有save m n配置,相當於自動的RDB持久化關閉,不過此時仍可以通過其他方式觸發。
- stop-writes-on-bgsave-error yes:當bgsave出現錯誤時,Redis是否停止執行寫命令;設定為yes,則當硬碟出現問題時,可以及時發現,避免資料的大量丟失;設定為no,則Redis無視bgsave的錯誤繼續執行寫命令,當對Redis伺服器的系統(尤其是硬碟)使用了監控時,該選項考慮設定為no。
- rdbcompression yes:是否開啟RDB檔案壓縮。
- rdbchecksum yes:是否開啟RDB檔案的校驗,在寫入檔案和讀取檔案時都起作用;關閉checksum在寫入檔案和啟動檔案時大約能帶來10%的效能提升,但是資料損壞時無法發現。
- dbfilename dump.rdb:RDB檔名。
- dir ./:RDB檔案和AOF檔案所在目錄。
配置自動生成rdb檔案後臺使用的是bgsave方式。
AOF(append-only file)
快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器將丟失最近寫入、且仍未儲存到快照中的那些資料。從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化,將修改的每一條指令記錄進檔案appendonly.aof中
你可以通過修改配置檔案來開啟 AOF 功能:
# appendonly yes
從現在開始, 每當 Redis 執行一個改變資料集的命令時(比如 SET), 這個命令就會被追加到 AOF 檔案的末尾。
這樣的話, 當 Redis 重新啟動時, 程式就可以通過重新執行 AOF 檔案中的命令來達到重建資料集的目的。
你可以配置 Redis 多久才將資料 fsync 到磁碟一次。
有三個選項:
- appendfsync always:每次有新命令追加到 AOF 檔案時就執行一次 fsync ,非常慢,也非常安全。
- appendfsync everysec:每秒 fsync 一次,足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鐘的資料。
- appendfsync no:從不 fsync ,將資料交給作業系統來處理。更快,也更不安全的選擇。
推薦(並且也是預設)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
AOF重寫
AOF檔案裡可能有太多沒用指令,所以AOF會定期根據記憶體的最新資料生成aof檔案
例如,執行了如下幾條命令:
127.0.0.1:6379> incr readcount (integer) 1 127.0.0.1:6379> incr readcount (integer) 2 127.0.0.1:6379> incr readcount (integer) 3 127.0.0.1:6379> incr readcount (integer) 4 127.0.0.1:6379> incr readcount (integer) 5
重寫後AOF檔案裡變成
*3 $3 SET $2 readcount $1 5
如下兩個配置可以控制AOF自動重寫頻率
# auto-aof-rewrite-min-size 64mb //aof檔案至少要達到64M才會自動重寫,檔案太小恢復速度本來就很快,重寫的意義不大
# auto-aof-rewrite-percentage 100 //aof檔案自上一次重寫後文件大小增長了100%則再次觸發重寫
當然AOF還可以手動重寫,進入redis客戶端執行命令bgrewriteaof重寫AOF
注意,AOF重寫redis會fork出一個子程序去做,不會對redis正常命令處理有太多影響
RDB 和 AOF ,我應該用哪一個?
命令 | RDB | AOF |
---|---|---|
啟動優先順序 | 低 | 高 |
體積 | 小 | 大 |
恢復速度 | 快 | 慢 |
資料安全性 | 容易丟資料 | 根據策略決定 |
redis啟動時如果既有rdb檔案又有aof檔案則優先選擇aof檔案恢復資料,因為aof一般來說資料更全一點。
檔案重寫的觸發
檔案重寫的觸發,分為手動觸發和自動觸發:
- 手動觸發:直接呼叫bgrewriteaof命令,該命令的執行與bgsave有些類似:都是fork子程序進行具體的工作,且都只有在fork時阻塞。
此時伺服器執行日誌如下:
- 自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數,以及aof_current_size和aof_base_size狀態確定觸發時機。
- auto-aof-rewrite-min-size:執行AOF重寫時,檔案的最小體積,預設值為64MB。
- auto-aof-rewrite-percentage:執行AOF重寫時,當前AOF大小(即aof_current_size)和上一次重寫時AOF大小(aof_base_size)的比值。
其中,引數可以通過config get命令檢視:
狀態可以通過info persistence檢視:
只有當auto-aof-rewrite-min-size和auto-aof-rewrite-percentage兩個引數同時滿足時,才會自動觸發AOF重寫,即bgrewriteaof操作。
自動觸發bgrewriteaof時,可以看到伺服器日誌如下:
檔案重寫的流程
檔案重寫流程如下圖所示:
圖片來源:http://www.cnblogs.com/yangmingxianshen/p/8373205.html
關於檔案重寫的流程,有兩點需要特別注意:
- 重寫由父程序fork子程序進行;
- 重寫期間Redis執行的寫命令,需要追加到新的AOF檔案中,為此Redis引入了aof_rewrite_buf快取。
對照上圖,檔案重寫的流程如下:
-
Redis父程序首先判斷當前是否存在正在執行 bgsave/bgrewriteaof的子程序,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執行完成後再執行。前面曾介紹過,這個主要是基於效能方面的考慮。
-
父程序執行fork操作建立子程序,這個過程中父程序是阻塞的。
-
父程序fork後,bgrewriteaof命令返回”Background append only file rewrite started”資訊並不再阻塞父程序,並可以響應其他命令。Redis的所有寫命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確。
由於fork操作使用寫時複製技術,子程序只能共享fork操作時的記憶體資料。由於父程序依然在響應命令,因此Redis使用AOF重寫緩衝區(圖中的aof_rewrite_buf)儲存這部分資料,防止新AOF檔案生成期間丟失這部分資料。也就是說,bgrewriteaof執行期間,Redis的寫命令同時追加到aof_buf和aof_rewirte_buf兩個緩衝區。
-
子程序根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。
-
子程序寫完新的AOF檔案後,向父程序發訊號,父程序更新統計資訊,具體可以通過info persistence檢視。
父程序把AOF重寫緩衝區的資料寫入到新的AOF檔案,這樣就保證了新AOF檔案所儲存的資料庫狀態和伺服器當前狀態一致。
使用新的AOF檔案替換老檔案,完成AOF重寫。
檔案校驗
與載入RDB檔案類似,Redis載入AOF檔案時,會對AOF檔案進行校驗,如果檔案損壞,則日誌中會列印錯誤,Redis啟動失敗。但如果是AOF檔案結尾不完整(機器突然宕機等容易導致檔案尾部不完整),且aof-load-truncated引數開啟,則日誌中會輸出警告,Redis忽略掉AOF檔案的尾部,啟動成功。aof-load-truncated引數預設是開啟的:
AOF常用配置總結
下面是AOF常用的配置項,以及預設值;前面介紹過的這裡不再詳細介紹。
- appendonly no:是否開啟AOF
- appendfilename “appendonly.aof”:AOF檔名
- dir ./:RDB檔案和AOF檔案所在目錄
- appendfsync everysec:fsync持久化策略
- no-appendfsync-on-rewrite no:AOF重寫期間是否禁止fsync;如果開啟該選項,可以減輕檔案重寫時CPU和硬碟的負載(尤其是硬碟),但是可能會丟失AOF重寫期間的資料;需要在負載和安全性之間進行平衡
- auto-aof-rewrite-percentage 100:檔案重寫觸發條件之一
- auto-aof-rewrite-min-size 64mb:檔案重寫觸發提交之一
- aof-load-truncated yes:如果AOF檔案結尾損壞,Redis啟動時是否仍載入AOF檔案
1)info Persistence
執行結果如下:
Redis 4.0 混合持久化
重啟 Redis 時,我們很少使用 RDB來恢復記憶體狀態,因為會丟失大量資料。我們通常使用 AOF 日誌重放,但是重放 AOF 日誌效能相對 RDB來說要慢很多,這樣在 Redis 例項很大的情況下,啟動需要花費很長的時間。 Redis 4.0 為了解決這個問題,帶來了一個新的持久化選項——混合持久化。
通過如下配置可以開啟混合持久化:
# aof-use-rdb-preamble yes
如果開啟了混合持久化,AOF在重寫時,不再是單純將記憶體資料轉換為RESP命令寫入AOF檔案,而是將重寫這一刻之前的記憶體做RDB快照處理,並且將RDB快照內容和增量的AOF修改記憶體資料的命令存在一起,都寫入新的AOF檔案,新的檔案一開始不叫appendonly.aof,等到重寫完新的AOF檔案才會進行改名,原子的覆蓋原有的AOF檔案,完成新舊兩個AOF檔案的替換。
於是在 Redis 重啟的時候,可以先載入 RDB 的內容,然後再重放增量 AOF 日誌就可以完全替代之前的 AOF 全量檔案重放,因此重啟效率大幅得到提升。
混合持久化AOF檔案結構