Redis持久化——AOF日志


最新:Redis內存——三個重要的緩沖區

最新:Redis內存——內存消耗(內存都去哪了?)

最新:Redis持久化——如何選擇合適的持久化方式

最新:Redis持久化——AOF日志

更多文章...

上一篇文章Redis持久化——內存快照(RDB)我們總結到使用Redis內存快照進行持久化,在t 時刻做了一次快照,然后又在 t+n 時刻做了一次快照,此時如果宕機,則會丟失在此期間內修改的數據。但又不能頻繁的進行內存快照,那么有什么辦法能夠盡可能的減少這種數據丟失呢?Redis提供了另一種持久化的方式——AOF日志(Append Only File)。

什么是AOF日志持久化

執行后寫日志

與內存快照保存當前內存中的數據所不同,AOF持久化是通過保存Redis服務器所執行的寫命令來記錄數據庫狀態的。即每執行一個命令,就會把該命令寫到日志文件里。

需要注意的是寫日志的操作在Redis執行命令將數據寫入內存之后,如下圖所示:

AOF-1

這樣做的好處就是不會阻塞當前操作,也可以避免額外的檢查開銷,如果是在命令執行前進行寫日志的操作,一旦命令語法是錯誤的,不進行檢查的話就會導致寫入到日志文件中的命令是錯誤的,在使用日志文件恢復數據的時候就會出錯。而在命令執行后在進行日志的寫入則不會有這個問題。

但是也存在兩個問題,

  1. AOF 雖然避免了對當前命令的阻塞,但卻可能會給下一個操作帶來阻塞風險。因為,AOF 日志是在主進程中執行的,如果在把日志文件寫入磁盤時,磁盤寫壓力大,就會導致寫盤很慢,進而導致后續的操作也無法執行了

  2. 如果剛執行完一個命令,還沒有來得及記日志就宕機了,那么這個命令和相應的數據就有丟失的風險。如果此時 Redis 是用作緩存,還可以從后端數據庫重新讀入數據進行恢復,但是,如果 Redis 是直接用作數據庫的話,此時,因為命令沒有記入日志,所以就無法用日志進行恢復了。

AOF 緩沖區

針對上面兩個問題,Redis提供了緩沖區的方式進行AOF日志的記錄,以達到盡可能的避免阻塞和數據丟失的問題。

Redis在執行完命令進行持久化的時候,並非直接寫入磁盤日志文件,而是先寫入AOF緩沖區內,之后再通過某種策略寫到磁盤。

AOF-2

使用緩存區的方式進行AOF日志的記錄,上面提到的兩個問題其實就和日志從緩沖區寫入磁盤的時機有關系。

三種回寫策略

Redis AOF 機制提供了三種回寫磁盤的策略。

  • Always(同步寫回): 命令寫入 AOF緩沖區后調用系統 fsync操作同步到AOF文件, fsync完成后線程返回
  • Everysec(每秒寫回): 命令寫人 AOF緩沖區后調用系統 write操作, write完成后線程返回。 fsync同步文件操作由專門線程每秒調用一次
  • No(操作系統自動寫回): 命令寫入 AOF緩沖區后調用系統 write操作,不對AOF文件做 fsync同步,同步硬盤操作由操作系統負責,通常同步周期最長30秒

但其實可以看出這三種回寫策略都並不能完美的解決問題,

配置為 always時,每次寫入都要同步AOF文件,硬盤的寫入速度無法與內存相提並論,顯然與 Redis髙性能特性背道而馳

配置為no,由於操作系統每次同步AOF文件的周期不可控,而且會加大每次同步硬盤的數據量,雖然提升了性能,但數據安全性無法保證。

配置為 everysec,是建議的同步策略,也是默認配置,雖然能做到兼顧性能和數據安全性。但極端情況下一會造成1秒內的數據丟失。

在真正使用中,我們可以根據具體對性能和數據完整性的要求,分析這三種回寫策略,選擇適合的策略來進行持久化。

回寫策略 優點 缺點
Always(同步寫回) 可靠性高、數據基本不丟失 性能較差
Everysec(每秒寫回) 性能適中 宕機時丟失1秒內的數據
No(操作系統自動寫回) 性能好 宕機時丟失數據較多

AOF重寫

日志文件越來越大怎么辦

選擇了合適的回寫策略,AOF這種持久化的方式還有其它問題嗎?

因為AOF持久化是通過保存被執行的寫命令來記錄數據庫狀態的,所以隨着時間的流逝,AOF文件中的內容會越來越多,文件的體積也會越來越大,過大的AOF文件不僅追加命令會變慢,而且可能對Redis服務器、甚至整個宿主計算機造成影響,並且AOF文件的體積越大,使用AOF文件來進行數據還原所需的時間就越多。

這個時候就要用到AOF重寫機制了

redis> set testKey testValue
OK
redis> set testKey testValue1
OK
redis> del testKey
OK
redis> set testKey hello
OK
redis> set testKey world
OK

AOF 文件是以追加的方式,逐一記錄接收到的寫命令的。當一個鍵值對被多條寫命令反復修改時,AOF 文件會記錄相應的多條命令。如上示例,我們執行完命令后,Redis會在AOF里面追加5條命令。但實際上只需要set testKey world一條命令就夠了。

AOF 重寫機制就是在重寫時,Redis 根據數據庫的現狀創建一個新的 AOF 文件,也就是說,讀取數據庫中的所有鍵值對,然后對每一個鍵值對用一條命令記錄它的寫入。比如說,當讀取了鍵值對“testkey”: “world”之后,重寫機制會記錄 set testkey world這條命令。這樣,當需要恢復時,可以重新執行該命令,實現“testkey”: “world”的寫入。

這樣,重寫后的日志,從5條變成了1條,而對於可能被修改過成百上千次的鍵值對來說,重寫能節省的空間就更大了。

雖然 AOF 重寫后,日志文件會縮小,但是,要把整個數據庫的最新數據的操作日志都寫回磁盤,仍然是一個非常耗時的過程。這時,我們不得不關注:重寫會不會導致阻塞?這就要看看AOF重寫的過程是怎么樣的

AOF 重寫過程

因為AOF重寫也是一個非常耗時的過程,又因為Redis單線程的特性,同內存快照一樣,AOF重寫的過程也是由父進程fork出bgrewriteaof子進程來完成的.

使用子進程(而不是開啟一個線程)進行AOF重寫雖然可以避免使用鎖的情況下,保證數據安全性,但是會帶來子進程和父進程一致性問題。
例如在開始重寫之后父進程又接收了新的鍵值對此時子進程是無法知曉的,當子進程重寫完成后的數據庫和父進程的數據庫狀態是不一致的。

如下表:

時間 服務器進程(父進程) 子進程
T1 執行命令 SET K1 V1
T2 執行命令 SET K1 V1
T3 創建子進程,執行AOF文件重寫 開始AOF重寫
T4 執行命令 SET K2 V2 執行重寫
T5 執行命令 SET K3 V3 執行重寫
T6 執行命令 SET K4 V4 完成AOF重寫

在T6時刻服務器進程有了4個鍵,而子進程卻只有1個鍵

為了解決這種不一致性,Redis設置了一個AOF重寫緩沖區。

AOF重寫

在子進程執行AOF重寫期間。服務器進程需要執行以下3個動作:

  1. 執行客戶端命令
  2. 執行后追加到AOF緩沖區
  3. 執行后追加到AOF重寫緩沖區

子進程完成AOF重寫后,它向父進程發送一個信號,父進程收到信號后會調用一個信號處理函數,該函數把AOF重寫緩沖區的命令追加到新AOF文件中然后替換掉現有AOF文件。父進程處理完畢后可以繼續接受客戶端命令調用,可以看出在AOF后台重寫過程中只有這個信號處理函數會阻塞服務器進程。
下表是完整的AOF后台重寫過程:

時間 服務器進程(父進程) 子進程
T1 執行命令 SET K1 V1
T2 執行命令 SET K1 V1
T3 創建子進程,執行AOF文件重寫 開始AOF重寫
T4 執行命令 SET K2 V2 執行重寫
T5 執行命令 SET K3 V3 執行重寫
T6 執行命令 SET K4 V4 完成AOF重寫,向父進程發送信號
T7 接收到信號,將T5 T6 T7 服務器的寫命令追加到新的AOF文件末尾
T8 用新的AOF替換舊的AOF

這樣就可以保證重寫日志期間的所有操作也都會寫入新的AOF文件。

需要注意的是, T7 T8執行的任務會阻塞服務器處理命令。

總的來說,就是每次 AOF 重寫時,Redis 會先fork出一個子進程用於重寫;然后,使用兩個日志保證在重寫過程中,新寫入的數據不會丟失。

AOF文件恢復

Redis 服務器重啟后,會優先去載入AOF日志文件。因為AOF文件里面包含了重建數據庫狀態所需的所有寫命令,所以服務器重新執行一遍AOF文件里面保存的寫命令,就可以還原服務器關閉之前的數據庫狀態。

而由於Redis命令只能在客戶端上下文中執行,Redis會創建一個沒有網絡連接的偽客戶端來執行AOF文件中的內容。

小結

本文主要總結了Redis AOF 持久化的方式,介紹了它同步磁盤的三種策略,以及日志文件過大時如何進行重寫。我們知道Redis持久化方式有AOF和RDB兩種,那么這兩種持久化方式各自有什么優點和缺點?真正使用中我們應該如何去選擇合適的持久化方式,又可能遇到哪些問題呢?我們下一篇文章繼續總結

系列文章:

最新:Redis內存——三個重要的緩沖區

最新:Redis內存——內存消耗(內存都去哪了?)

最新:Redis持久化——如何選擇合適的持久化方式

最新:Redis持久化——AOF日志

Redis持久化——內存快照(RDB)

一文回顧Redis五大對象(數據類型)

Redis對象——有序集合(ZSet)

Redis對象——集合(Set)

Redis對象——列表(List)

Redis對象——哈希(Hash)

Redis數據結構——quicklist

Redis對象——字符串

Redis對象——Redis對象系統簡介

Redis數據結構——壓縮列表

Redis數據結構——整數集合

Redis數據結構——跳躍表

Redis數據結構——字典

Redis數據結構——鏈表

Redis數據結構——簡單動態字符串SDS

-----END-----

關注下方公眾號,回復“Redis”,可得Redis相關學習資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM