Redis官方提供了兩種數據持久化的方式,分別是:RDB和AOF。今天我們來討論一下這兩種持久化方式的區別。
RDB
基本原理:RDB持久化主要是通過SAVE和BGSAVE兩個命令對Redis數據庫中當前的數據做snapshot並生成rdb文件來實現的。其中SAVE是阻塞的,BGSAVE是非阻塞的,通過fork了一個子進程來完成的。在Redis啟動的時候會檢測rdb文件,然后載入rdb文件中未過期的數據到服務器中
配置信息:RDB可以通過向服務器提供配置信息來自動間隔性保存。如默認情況下服務器滿足以下3個條件中任意一個條件就會觸發BGSAVE命令
save 900 1 // 服務器在900秒之內,對數據庫進行了至少1次修改
save 300 10 // 服務器在300秒之內,對數據庫進行了至少10次修改
save 60 10000 // 服務器在60秒之內,對數據庫進行了至少10000次修改
實現方式:服務器通過維護dirty
計數器和lastsave
屬性分別記錄距離上次成功執行SAVE或者BGSAVE命令之后,服務器對數據庫狀態進行修改的次數和最后一次成功SAVE或者BGSAVE的UNIX時間戳。由Redis周期性操作函數serverCron
默認每隔100ms
來檢測是否滿足配置信息中的要求,然后再決定是否執行SAVE或者BGSAVE命令來對數據庫進行備份。
AOF
基本原理:AOF(Append Only File)持久化是通過將存儲每次執行的客戶端命令,然后由一個偽客戶端來執行這些命令將數據寫入到服務器中的方式實現的。一共分為命令追加(append)、文件寫入、文件同步(sync)三個步驟完成的
命令追加
當有修改、刪除操作時,服務器會在執行完之后以協議格式將被執行的寫命令追加到服務器狀態的aof_buf
緩沖區的末尾
文件寫入
Redis的服務進程就是一個事件循環,這個循環中的文件事件負責接收客戶端的命令請求。服務器在處理文件事件時可能會執行寫命令,同時會追加到aof_buf
緩沖區,所以在每結束一次循環之前,都會調用flushAppendOnlyFile
函數,將aof_buf
緩沖區的數據寫入到AOF文件里面。
文件同步
flushAppendOnlyFile
函數通過服務器配置appendfsync
選項的值來決定的將每次循環結束之前aof_buf
緩沖區的數據寫入到AOF文件后,將以何種方式同步到AOF文件里面:
appendfsync | flushAppendOnlyFile函數的行為 |
---|---|
always |
每次都同步 |
everysec |
單獨一個線程一分鍾同步一次 |
no |
操作系統決定何時同步 |
AOF重寫
AOF方式持久化時記錄的時一條一條的寫命令,隨着服務器運行的時間越來越長,AOF文件會越來越大,AOF重寫就是為了解決這個問題。
函數aof_rewrite
啟動一個子進程創建AOF重寫緩沖區,將Redis中所有的數據生成多條寫命令寫入AOF文件。在子進程進行AOF重寫期間,服務器還會處理寫請求的命令,這會導致服務器當前的數據庫狀態和重寫后的AOF文件所保存的數據不一致。為了解決這個問題,子進程在執行AOF重寫期間,服務器進程需要執行以下三件事情:
- 執行客戶端發送來的命令
- 將執行后的寫命令追加到AOF緩沖區
- 將執行后的寫命令追加到AOF重寫緩沖區
當子進程完成AOF重寫工作后,會發送一個信號到父進程,父進程收到信號后會調用信號處理函數(這個過程會block主父進程),執行以下工作:
- 將AOF重寫緩沖區中的數據全部寫入到新AOF文件中,這時新AOF文件所保存的數據庫狀態和服務器當前的數據庫狀態一致
- 對新的AOF文件進行改名,原子的覆蓋現有的AOF文件,完成新舊兩個AOF文件的替換
RDB與AOF區別
- RDB可以理解為是一種全量數據更新機制,AOF可以理解為是一種增量的更新機制,AOF重寫可以理解為是一種全量+增量的更新機制(第一次是全量,后面都是增量)
- RDB適合服務器數據庫數據量小,寫命令頻繁的場景
- AOF適合數據量大,寫命令少的場景
- AOF重寫適合在AOF運行了很久的寫命令之后執行