RDB算法
RDB是將當前數據生成快照保存到硬盤上。數據庫
RDB的工做流程:express
1. 執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,若是存在bgsave命令直接返回。promise
2. 父進程執行fork操做建立子進程,fork操做過程當中父進程被阻塞。網絡
3. 父進程fork完成後,bgsave命令返回「* Background saving started by pid xxx」信息,並再也不阻塞父進程,能夠繼續響應其餘命令。app
4. 父進程建立RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。根據lastsave命令能夠獲取最近一次生成RDB的時間,對應info Persistence中的rdb_last_save_time。運維
5. 進程發送信號給父進程表示完勝,父進程更新統計信息。性能
對於大多數操做系統來講,fork都是個重量級操做,雖然建立的子進程不須要拷貝父進程的物理內存空間,可是會複製父進程的空間內存頁表。spa
子進程經過fork操做產生,佔用內存大小等同於父進程,理論上須要兩倍的內存來完成持久化操做,但Linux有寫時複製機制(copy-on-write)。父子進程會共享相同的物理內存頁,當父進程處理寫請求時會把要修改的頁建立副本,而子進程在fork操做過程當中會共享父進程的內存快照。操作系統
觸發機制:
1. 手動觸發
包括save和bgsave命令。
由於save會阻塞當前Redis節點,因此,Redis內部全部涉及RDB持久化的的操做都經過bgsave方式,save方式已廢棄。
2. 自動觸發
1> 使用save的相關配置。
2> 從節點執行全量複製操做。
3> 執行debug reload命令。
4> 執行shutdown命令時,若是沒有開啓AOF持久化功能則會自動執行bgsave。
RDB的優缺點:
優勢:
1. RDB是一個緊湊壓縮的二進制文件,表明Redis在某個時間點上的數據快照,適合備份,全量複製等場景。
2. 加載RDB恢復數據遠遠快於AOF的方式。
缺點:
沒辦法作到實時持久化/秒級持久化,由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做,頻繁執行成本太高。
RDB的相關參數
save 900 1
save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir ./
其中,前三個參數的含義是,
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed
若是要禁用RDB的自動觸發,可註銷這三個參數,或者設置save ""。
stop-writes-on-bgsave-error:在開啓RDB且最近一次bgsave執行失敗的狀況下,若是該參數爲yes,則Redis會阻止客戶端的寫入,直到bgsave執行成功。
rdbcompression:使用LZF算法壓縮字符對象。
rdbchecksum:從RDB V5開始,在保存RDB文件時,會在文件末尾添加CRC64校驗和,這樣,能較容易的判斷文件是否被損壞。但同時,對於帶有校驗和的RDB文件的保存和加載,會有10%的性能損耗。
dbfilename: RDB文件名。
dir:RDB文件保存的目錄。
RDB的相關變量
127.0.0.1:6379> info Persistence
# Persistence
loading:0 rdb_changes_since_last_save:0 rdb_bgsave_in_progress:0 rdb_last_save_time:1538447605 rdb_last_bgsave_status:ok rdb_last_bgsave_time_sec:0 rdb_current_bgsave_time_sec:-1 rdb_last_cow_size:155648
其含義以下:
loading: Flag indicating if the load of a dump file is on-going。是否在加載RDB文件
rdb_changes_since_last_save: Number of changes since the last dump。
rdb_bgsave_in_progress: Flag indicating a RDB save is on-going。是否在執行bgsave操做。
rdb_last_save_time: Epoch-based timestamp of last successful RDB save。最近一次bgsave操做時的時間戳。
rdb_last_bgsave_status: Status of the last RDB save operation。最近一次bgsave是否執行成功。
rdb_last_bgsave_time_sec: Duration of the last RDB save operation in seconds。最近一次bgsave操做花費的時間。
rdb_current_bgsave_time_sec: Duration of the on-going RDB save operation if any。當前bgsave操做已經執行的時間。
rdb_last_cow_size: The size in bytes of copy-on-write allocations during the last RBD save operation。COW的大小。指的是父進程與子進程相比執行了多少修改,包括讀取緩衝區,寫入緩衝區,數據修改等。
AOF
與RDB不同的是,AOF記錄的是命令,而不是數據。須要注意的是,其保存的是Redis Protocol,而不是直接的Redis命令。可是以文本格式保存。
如何開啓AOF
只需將appendonly設置爲yes就行。
AOF的工做流程:
1. 全部的寫入命令追加到aof_buf緩衝區中。
2. AOF會根據對應的策略向磁盤作同步操做。刷盤策略由appendfsync參數決定。
3. 按期對AOF文件進行重寫。重寫策略由auto-aof-rewrite-percentage,auto-aof-rewrite-min-size兩個參數決定。
appendfsync參數有以下取值:
no: don't fsync, just let the OS flush the data when it wants. Faster. 只調用系統write操做,不對AOF文件作fsync操做,同步硬盤操做由操做系統負責,一般同步週期最長爲30s。
always: fsync after every write to the append only log. Slow, Safest. 命令寫入到aof_buf後,會調用系統fsync操做同步到文件中。
everysec: fsync only one time every second. Compromise. 只調用系統write操做,fsync同步文件操做由專門進程每秒調用一次。
默認值爲everysec,也是建議值。
重寫機制
爲何要重寫?重寫後能夠加快節點啓動時的加載時間。
重寫後的文件爲何能夠變小?
1. 進程內超時的數據不用再寫入到AOF文件中。
2. 存在刪除命令。
3. 多條寫命令能夠合併爲一個。
重寫條件:
1. 手動觸發
直接調用bgrewriteaof命令。
2. 自動觸發。
與auto-aof-rewrite-percentage,auto-aof-rewrite-min-size兩個參數有關。
觸發條件,aof_current_size > auto-aof-rewrite-min-size 而且 (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage。
其中,aof_current_size是當前AOF文件大小,aof_base_size 是上一次重寫後AOF文件的大小,這兩部分的信息可從info Persistence處獲取。
AOF重寫的流程。
1. 執行AOF重寫請求。
若是當前進程正在執行bgsave操做,重寫命令會等待bgsave執行完後再執行。
2. 父進程執行fork建立子進程。
3. fork操做完成後,主進程會繼續響應其它命令。全部修改命令依然會寫入到aof_buf中,並根據appendfsync策略持久化到AOF文件中。
4. 因fork操做運用的是寫時複製技術,因此子進程只能共享fork操做時的內存數據,對於fork操做後,生成的數據,主進程會單獨開闢一塊aof_rewrite_buf保存。
5. 子進程根據內存快照,按照命令合併規則寫入到新的AOF文件中。每次批量寫入磁盤的數據量由aof-rewrite-incremental-fsync參數控制,默認爲32M,避免單次刷盤數據過多形成硬盤阻塞。
6. 新AOF文件寫入完成後,子進程發送信號給父進程,父進程更新統計信息。
7. 父進程將aof_rewrite_buf(AOF重寫緩衝區)的數據寫入到新的AOF文件中。
8. 使用新AOF文件替換老文件,完成AOF重寫。
實際上,當Redis節點執行完一個命令後,它會同時將這個寫命令發送到AOF緩衝區和AOF重寫緩衝區。
Redis經過AOF文件還原數據庫的流程。
1. 建立一個不帶網絡鏈接的僞客戶端。由於Redis的命令只能在客戶端上下文中執行。
2. 從AOF文件中分析並讀取一條命令。
3. 使用僞客戶端執行該命令。
4. 反覆執行步驟2,3,直到AOF文件中的全部命令都被處理完。
注意:AOF的持久化也可能會形成阻塞。
AOF經常使用的持久化策略是everysec,在這種策略下,fsync同步文件操做由專門線程每秒調用一次。當系統磁盤較忙時,會形成Redis主線程阻塞。
1. 主線程負責寫入AOF緩衝區。
2. AOF線程負責每秒執行一次同步磁盤操做,並記錄最近一次同步時間。
3. 主線程負責對比上次AOF同步時間。
1> 若是距上次同步成功時間在2s內,主線程直接返回。
2> 若是距上次同步成功時間超過2s,主線程會阻塞,直到同步操做完成。每出現一次阻塞,info Persistence中aof_delayed_fsync的值都會加1。
因此,使用everysec策略最多會丟失2s數據,而不是1s。
AOF的相關變量
127.0.0.1:6379> info Persistence
# Persistence
...
aof_enabled:1 aof_rewrite_in_progress:0 aof_rewrite_scheduled:0 aof_last_rewrite_time_sec:-1 aof_current_rewrite_time_sec:-1 aof_last_bgrewrite_status:ok aof_last_write_status:ok aof_last_cow_size:0 aof_current_size:19276803 aof_base_size:19276803 aof_pending_rewrite:0 aof_buffer_length:0 aof_rewrite_buffer_length:0 aof_pending_bio_fsync:0 aof_delayed_fsync:0
其含義以下,
aof_enabled: Flag indicating AOF logging is activated. 是否開啓AOF
aof_rewrite_in_progress: Flag indicating a AOF rewrite operation is on-going. 是否在進行AOF的重寫操做。
aof_rewrite_scheduled: Flag indicating an AOF rewrite operation will be scheduled once the on-going RDB save is complete. 是否有AOF操做等待執行。
aof_last_rewrite_time_sec: Duration of the last AOF rewrite operation in seconds. 最近一次AOF重寫操做消耗的時間。
aof_current_rewrite_time_sec: Duration of the on-going AOF rewrite operation if any. 當前正在執行的AOF操做已經消耗的時間。
aof_last_bgrewrite_status: Status of the last AOF rewrite operation. 最近一次AOF重寫操做是否執行成功。
aof_last_write_status: Status of the last write operation to the AOF. 最近一次追加操做是否執行成功。
aof_last_cow_size: The size in bytes of copy-on-write allocations during the last AOF rewrite operation. 在執行AOF重寫期間,分配給COW的大小。
若是開啓了AOF,還會增長如下變量
aof_current_size: AOF current file size. AOF的當前大小。
aof_base_size: AOF file size on latest startup or rewrite. 最近一次重寫後AOF的大小。
aof_pending_rewrite: Flag indicating an AOF rewrite operation will be scheduled once the on-going RDB save is complete.是否有AOF操做在等待執行。
aof_buffer_length: Size of the AOF buffer. AOF buffer的大小
aof_rewrite_buffer_length: Size of the AOF rewrite buffer. AOF重寫buffer的大小。
aof_pending_bio_fsync: Number of fsync pending jobs in background I/O queue. 在等待執行的fsync操做的數量。
aof_delayed_fsync: Delayed fsync counter. Fsync操做延遲執行的次數。
若是一個load操做在進行,還會增長如下變量
loading_start_time: Epoch-based timestamp of the start of the load operation. Load操做開始的時間。
loading_total_bytes: Total file size. 文件的大小。
loading_loaded_bytes: Number of bytes already loaded.已經加載的文件的大小。
loading_loaded_perc: Same value expressed as a percentage. 已經加載的比例。
loading_eta_seconds: ETA in seconds for the load to be complete. 預計多久加載完畢。
AOF的相關參數
appendonly yes
appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble no
其中,
no-appendfsync-on-rewrite:在執行bgsave或bgrewriteaof操做時,不調用fsync()操做,此時,Redis的持久化策略至關於"appendfsync none"。
aof-load-truncated:在Redis節點啓動的時候,若是發現AOF文件已經損壞了,其處理邏輯與該參數的設置有關,若爲yes,則會忽略掉錯誤,儘量加載較多的數據,若爲no,則會直接報錯退出。默認爲yes。須要注意的是,該參數只適用於Redis啓動階段,若是在Redis運行過程當中,發現AOF文件corrupted,Redis會直接報錯退出。
aof-use-rdb-preamble:是否啓用Redis 4.x提供的AOF+RDB的混合持久化方案,若爲yes,在重寫AOF文件時,Redis會將數據以RDB的格式做爲AOF文件的開始部分。在重寫以後,Redis會繼續以AOF格式持久化寫入操做。默認值爲no。
參考:
1. 《Redis開發與運維》
2. 《Redis設計與實現》
3. 《Redis 4.X Cookbook》