就這?Redis持久化策略——AOF
今天為大家介紹Redis的另一種持久化策略——AOF。
什么是AOF
男孩“一覺醒來”忘記了對女孩子的承諾,這時(shí)候女孩子把曾經(jīng)海誓山盟的錄音逐條播放給男孩子聽,幫助他“恢復(fù)記憶”。
“男孩一覺醒來”像極了Redis宕機(jī)重啟的樣子,而女孩子的錄音就是Redis的AOF日志。
AOF(Append Only File)以文本的形式(文本格式由Redis自定義,后文會(huì)講到),通過將所有對數(shù)據(jù)庫的寫入命令記錄到AOF文件中,達(dá)到記錄數(shù)據(jù)庫狀態(tài)的目的。
注意:AOF文件只會(huì)記錄Redis的寫操作命令,因?yàn)樽x命令對數(shù)據(jù)的恢復(fù)沒有任何意義。
Redis默認(rèn)并未開啟AOF功能,redis.conf配置文件中,關(guān)于AOF的相關(guān)配置如下:
- # 是否開啟AOF功能(開啟:yes 關(guān)閉:no)
- appendonly yes
- # 生成的AOF文件名稱
- appendfilename 6379.aof
- # AOF寫回策略
- appendfsync everysec
- # 當(dāng)前AOF文件大小和最后一次重寫后的大小之間的比率>=指定的增長百分比則進(jìn)行重寫
- # 如100代表當(dāng)前AOF文件大小是上次重寫的兩倍時(shí)候才重寫
- auto-aof-rewrite-percentage 100
- # AOF文件最小重寫大小,只有當(dāng)AOF文件大小大于該值時(shí)候才可能重寫,4.0默認(rèn)配置64mb。
- auto-aof-rewrite-min-size 64mb
AOF日志格式
下面我們通過一個(gè)例子,看一下AOF機(jī)制是如何保存我們的操作日志的,我們對Redis進(jìn)行如下操作。
- 127.0.0.1:6379[3]> RPUSH list 1 2 3 4 5
- (integer) 5
- 127.0.0.1:6379[3]> LRANGE list 0 -1
- 1) "1"
- 2) "2"
- 3) "3"
- 4) "4"
- 5) "5"
- 127.0.0.1:6379[3]> RPOP list
- "5"
- 127.0.0.1:6379[3]> LPUSH list 0
- (integer) 5
- 127.0.0.1:6379[3]> KEYS *
- 1) "list"
- 127.0.0.1:6379[3]> LRANGE list 0 -1
- 1) "0"
- 2) "1"
- 3) "2"
- 4) "3"
- 5) "4"
Redis會(huì)將上述所有的寫指令保存到AOF文件中,如下所示:
- RPUSH list 1 2 3 4 5
- RPOP list
- LPUSH list 0
當(dāng)然,AOF文件不是直接以指令的格式進(jìn)行存儲(chǔ)的,我們以第一條指令RPUSH list 1 2 3 4 5為例,看一下AOF文件實(shí)際保存該條指令的格式。
- *2
- $6
- SELECT
- $1
- 3
- *7
- $5
- RPUSH
- $4
- list
- $1
- 1
- $1
- 2
- $1
- 3
- $1
- 4
- $1
- 5
除了 SELECT命令是AOF程序自己加上去的之外, 其他命令都是之前我們在終端里執(zhí)行的命令。自動(dòng)添加這條指令是因?yàn)镽edis恢復(fù)數(shù)據(jù)的時(shí)候需要知道待恢復(fù)的數(shù)據(jù)屬于哪一個(gè)數(shù)據(jù)庫。
其中,*2表示當(dāng)前命令有2個(gè)部分,每部分都是由$+數(shù)字開頭,后面緊跟著具體的命令、鍵或值。數(shù)字表示這部分中的命令、鍵或值一共有多少字節(jié)。例如,$6 SELECT表示這部分有 6 個(gè)字節(jié),也就是SELECT命令。
AOF日志的生成過程
從我們發(fā)送寫指令開始到指令保存在AOF文件中,需要經(jīng)歷4步,分別為命令傳播、命令追加、文件寫入和文件同步。
命令傳播
命令傳播:Redis 將執(zhí)行完的命令、命令的參數(shù)、命令的參數(shù)個(gè)數(shù)等信息發(fā)送到 AOF程序中。
大家有沒有關(guān)注到其中的一個(gè)細(xì)節(jié),AOF日志寫入是在Redis成功執(zhí)行命令之后才進(jìn)行的,為什么要在執(zhí)行之后而不是之前呢?原因有兩點(diǎn):
首先試想一下,如果我們不小心輸錯(cuò)了Redis指令,然后Redis緊接著將該指令保存到了AOF文件中,等到Redis進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候就可能導(dǎo)致錯(cuò)誤。因此這種寫后日志的形式可以避免對指令進(jìn)行語法檢查,避免出現(xiàn)記錄錯(cuò)誤指令的情況。
其次,先執(zhí)行命令后保存日志,不會(huì)阻塞當(dāng)前的寫操作。
但是,AOF寫后日志也有兩個(gè)風(fēng)險(xiǎn)。
第一個(gè)風(fēng)險(xiǎn),假如Redis寫操作成功之后突然宕機(jī),此時(shí)AOF日志還未來得及寫入,則該條指令和相關(guān)參數(shù)就有丟失的風(fēng)險(xiǎn)。
第二個(gè)風(fēng)險(xiǎn),AOF雖然避免了對當(dāng)前操作的阻塞,但是有可能阻塞下一個(gè)操作。因?yàn)楸4鍭OF日志的部分工作也是由主線程完成的(下文有詳細(xì)介紹),Redis的內(nèi)存操作速度和文件寫入速度簡直是云泥之別,如果主線程在文件保存的過程中花費(fèi)太長的時(shí)間必然會(huì)阻塞后續(xù)的操作。
分析就會(huì)發(fā)現(xiàn),第一個(gè)風(fēng)險(xiǎn)與AOF寫回磁盤的時(shí)機(jī)有關(guān),寫回磁盤的頻率越高,發(fā)生數(shù)據(jù)丟失的可能性就越小。第二個(gè)風(fēng)險(xiǎn)和文件寫入方式以及時(shí)機(jī)有關(guān),如果Redis每次成功執(zhí)行指令之后都力圖將當(dāng)前指令同步到AOF文件,開銷必然很大。
因此Redis引入了緩沖區(qū)的概念,緩沖區(qū)對應(yīng)了文件的寫入方式(不求一步到位,允許循序漸進(jìn)地寫入),而何時(shí)將緩沖區(qū)的內(nèi)容徹底同步到文件就涉及到了AOF的同步策略(寫回磁盤的時(shí)機(jī))。
命令追加
在AOF開啟的情況下,Redis會(huì)將成功執(zhí)行的寫指令以上文我們講過的協(xié)議格式追加到Redis的aof_buf緩沖區(qū)。
- struct redisServer {
- // ...
- // AOF緩沖區(qū)
- sds aof_buf;
- // ...
- };
aof_buf 緩沖區(qū)保存著所有等待寫入到AOF 文件的協(xié)議文本。
至此,將命令追加到緩存區(qū)的步驟完成。
文件寫入
文件的寫入和同步操作往往被放在一起介紹,這里之所以分開,是想向讀者強(qiáng)調(diào)文件的寫入和同步是兩步不同的操作。
為了提高文件的寫入效率,當(dāng)用戶調(diào)用write函數(shù)將數(shù)據(jù)寫入到文件時(shí),操作系統(tǒng)內(nèi)核會(huì)將數(shù)據(jù)首先保存在內(nèi)存緩沖區(qū)中,等到緩沖區(qū)的空間被填滿或者到達(dá)一定的時(shí)機(jī)之后,內(nèi)核會(huì)將數(shù)據(jù)同步到磁盤。
這種同步過于依賴于操作系統(tǒng)內(nèi)核,時(shí)機(jī)無法掌控。為此,操作系統(tǒng)提供了fsync和fdatasync兩個(gè)同步函數(shù),可以強(qiáng)制內(nèi)核立即將緩沖區(qū)內(nèi)的數(shù)據(jù)同步到磁盤。
Redis的主服務(wù)進(jìn)程本質(zhì)上是一個(gè)死循環(huán),循環(huán)中有負(fù)責(zé)接受客戶端的請求,并向客戶端發(fā)送回執(zhí)的邏輯,我們稱之為文件事件。
在AOF功能開啟的情況下,文件事件會(huì)將成功執(zhí)行之后的寫命令追加到aof_buf緩沖區(qū),在主服務(wù)進(jìn)程死循環(huán)的最后,會(huì)調(diào)用flushAppendOnlyFile函數(shù),該函數(shù)會(huì)將aof_buf中的數(shù)據(jù)寫入到內(nèi)核緩沖區(qū),然后判斷是否應(yīng)該進(jìn)行同步。偽代碼如下:
- void eventLoop {
- while(true){
- // ...
- // 文件事件,接受命令請求,返回客戶端回執(zhí)
- // 根據(jù)aof功能是否開啟,決定是否將寫命令追加到aof_buf緩沖區(qū)
- handleFileEvents();
- // 將aof_buf數(shù)據(jù)寫入內(nèi)核緩沖區(qū)
- // 判斷是否需要將數(shù)據(jù)同步到磁盤
- flushAppendOnlyFile();
- // ...
- }
- };
而是否進(jìn)行同步則是由Redis配置中的appendOnlyFile選項(xiàng)來決定的。
文件同步
redis.conf配置文件中appendOnlyFile的選項(xiàng)有三個(gè)值可選,對應(yīng)三種AOF同步策略,分別是:
- No :同步時(shí)機(jī)由內(nèi)核決定。
- Everysec :每一秒鐘同步一次。
- Always :每執(zhí)行一個(gè)命令同步一次。
No
由操作系統(tǒng)內(nèi)核決定同步時(shí)機(jī),每個(gè)寫命令執(zhí)行完,只是先把日志寫入AOF文件的內(nèi)核緩沖區(qū),不立即進(jìn)行同步。在這種模式下, 同步只會(huì)在以下任意一種情況下被執(zhí)行:
- Redis 被關(guān)閉
- AOF功能被關(guān)閉
- 系統(tǒng)的寫緩存被刷新(可能是緩存已經(jīng)被寫滿,或者定期保存操作被執(zhí)行)
這三種情況下的同步操作都會(huì)引起 Redis 主進(jìn)程阻塞。
Everysec
如果用戶未指定appendOnlyFile的值,則默認(rèn)值為Everysec。每秒同步,每個(gè)寫命令執(zhí)行完,只是先把日志寫到 AOF文件的內(nèi)核緩沖區(qū),理論上每隔1秒把緩沖區(qū)中的內(nèi)容同步到磁盤,且同步操作有單獨(dú)的子線程進(jìn)行,因此不會(huì)阻塞主進(jìn)程。
需要注意的是,我們用的是「理論上」這樣的措辭,實(shí)際運(yùn)行中該模式對fsync或fdatasync的調(diào)用并不是每秒一次,而是和調(diào)用flushAppendOnlyFile函數(shù)時(shí)Redis所處的狀態(tài)有關(guān)。
每當(dāng) flushAppendOnlyFile 函數(shù)被調(diào)用時(shí), 可能會(huì)出現(xiàn)以下四種情況:
- 子線程正在執(zhí)行同步,并且這個(gè)同步的執(zhí)行時(shí)間未超過 2 秒,那么程序直接返回 ;這個(gè)同步已經(jīng)執(zhí)行超過 2 秒,那么程序執(zhí)行寫入操作 ,但不執(zhí)行新的同步操作 。但是,這時(shí)的寫入操作必須等待子線程先完成原本的同步操作 ,因此這里的寫入操作會(huì)比平時(shí)阻塞更長時(shí)間。
- 子線程沒有在執(zhí)行同步 ,并且上次成功執(zhí)行同步距今不超過1秒,那么程序執(zhí)行寫入,但不執(zhí)行同步 ;上次成功執(zhí)行同步距今已經(jīng)超過1秒,那么程序執(zhí)行寫入和同步 。
可以用流程圖表示這四種情況:
在Everysec模式下
- 如果在情況1下宕機(jī),那么我們最多損失小于2秒內(nèi)的所有數(shù)據(jù)。
- 如果在情況2下宕機(jī),那么我們損失的數(shù)據(jù)可能會(huì)超過2秒。
因此AOF在Everysec模式下只會(huì)丟失 1 秒鐘數(shù)據(jù)的說法實(shí)際上并不準(zhǔn)確。
Always
每個(gè)寫命令執(zhí)行完,立刻同步地將日志寫回磁盤。此模式下同步操作是由 Redis 主進(jìn)程執(zhí)行的,所以在同步執(zhí)行期間,主進(jìn)程會(huì)被阻塞,不能接受命令請求。
AOF同步策略小結(jié)
對于三種 AOF 同步模式, 它們對Redis主進(jìn)程的阻塞情況如下:
- 不同步(No):寫入和同步都由主進(jìn)程執(zhí)行,兩個(gè)操作都會(huì)阻塞主進(jìn)程;
- 每一秒鐘同步一次(Everysec):寫入操作由主進(jìn)程執(zhí)行,阻塞主進(jìn)程。同步操作由子線程執(zhí)行,不直接阻塞主進(jìn)程,但同步操作完成的快慢會(huì)影響寫入操作的阻塞時(shí)長;
- 每執(zhí)行一個(gè)命令同步一次(Always):同模式 1 。
因?yàn)樽枞僮鲿?huì)讓 Redis 主進(jìn)程無法持續(xù)處理請求, 所以一般說來, 阻塞操作執(zhí)行得越少、完成得越快, Redis 的性能就越好。
No的同步操作只會(huì)在AOF關(guān)閉或Redis關(guān)閉時(shí)執(zhí)行, 或由操作系統(tǒng)內(nèi)核觸發(fā)。在一般情況下, 這種模式只需要為寫入阻塞,因此它的寫入性能要比后面兩種模式要高, 但是這種性能的提高是以降低安全性為代價(jià)的:在這種模式下,如果發(fā)生宕機(jī),那么丟失的數(shù)據(jù)量由操作系統(tǒng)內(nèi)核的緩存沖洗策略決定。
Everysec在性能方面要優(yōu)于Always , 并且在通常情況下,這種模式最多丟失不多于2秒的數(shù)據(jù), 所以它的安全性要高于No ,這是一種兼顧性能和安全性的保存方案。
Always的安全性是最高的,但性能也是最差的,因?yàn)镽edis必須阻塞直到命令信息被寫入并同步到磁盤之后才能繼續(xù)處理請求。
三種 AOF模式的特性可以總結(jié)為如下表格
AOF生成過程小結(jié)
最后總結(jié)一下AOF文件的生成過程。以下步驟都是在AOF開啟的前提下進(jìn)行的
- Redis成功執(zhí)行寫操作指令,然后將寫的指令按照自定義格式追加到aof_buf緩沖區(qū),這是第一個(gè)緩沖區(qū);
- Redis主進(jìn)程將aof_buf緩沖區(qū)的數(shù)據(jù)寫入到內(nèi)核緩沖區(qū),這是第二個(gè)緩沖區(qū);
- 根據(jù)AOF同步策略適時(shí)地將內(nèi)核緩沖區(qū)的數(shù)據(jù)同步到磁盤,過程結(jié)束。
AOF文件的載入和數(shù)據(jù)還原
AOF文件中包含了能夠重建數(shù)據(jù)庫的所有寫命令,因此將所有命令讀入并依次執(zhí)行即可還原Redis之前的數(shù)據(jù)狀態(tài)。
Redis 讀取AOF文件并還原數(shù)據(jù)庫的詳細(xì)步驟如下:
- 創(chuàng)建一個(gè)不帶網(wǎng)絡(luò)連接的偽客戶端(fake client),偽客戶端執(zhí)行命令的效果, 和帶網(wǎng)絡(luò)連接的客戶端執(zhí)行命令的效果完全相同;
- 讀取AOF所保存的文本,并根據(jù)內(nèi)容還原出命令、命令的參數(shù)以及命令的個(gè)數(shù);
- 根據(jù)指令、指令的參數(shù)等信息,使用偽客戶端執(zhí)行命令。
- 執(zhí)行 2 和 3 ,直到AOF文件中的所有命令執(zhí)行完畢。
注意:為了避免對數(shù)據(jù)的完整性產(chǎn)生影響, 在服務(wù)器載入數(shù)據(jù)的過程中, 只有和數(shù)據(jù)庫無關(guān)的發(fā)布訂閱功能可以正常使用, 其他命令一律返回錯(cuò)誤。
AOF重寫
AOF的作用是幫我們還原Redis的數(shù)據(jù)狀態(tài),其中包含了所有的寫操作,但是正常情況下客戶端會(huì)對同一個(gè)KEY進(jìn)行多次不同的寫操作,如下:
- 127.0.0.1:6379[3]> SET name chanmufeng1
- OK
- 127.0.0.1:6379[3]> SET name chanmufeng2
- OK
- 127.0.0.1:6379[3]> SET name chanmufeng3
- OK
- 127.0.0.1:6379[3]> SET name chanmufeng4
- OK
- 127.0.0.1:6379[3]> SET name chanmufeng
- OK
例子中對name的數(shù)據(jù)進(jìn)行寫操作就進(jìn)行了5次,其實(shí)對我們而言僅需要最后一條指令而已,但是AOF會(huì)將這5條指令都記錄下來。更極端的情況是有些被頻繁操作的鍵, 對它們所調(diào)用的命令可能有成百上千、甚至上萬條, 如果這樣被頻繁操作的鍵有很多的話,AOF文件的體積就會(huì)急速膨脹。
- 首先,AOF文件的體積受操作系統(tǒng)大小的限制,本身就不能無限增長;
- 其次,體積過于龐大的AOF文件會(huì)影響指令的寫入速度,阻塞時(shí)間延長;
- 最后AOF文件的體積越大,Redis數(shù)據(jù)恢復(fù)所需的時(shí)間也就越長。
為了解決AOF文件體積龐大的問題,Redis提供了rewrite的AOF重寫功能來精簡AOF文件體積。
AOF重寫的實(shí)現(xiàn)原理
雖然叫AOF「重寫」,但是新AOF文件的生成并非是在原AOF文件的基礎(chǔ)上進(jìn)行操作得到的,而是讀取Redis當(dāng)前的數(shù)據(jù)狀態(tài)來重新生成的。不難理解,后者的處理方式遠(yuǎn)比前者高效。
為了避免阻塞主線程,導(dǎo)致數(shù)據(jù)庫性能下降,和 AOF 日志由主進(jìn)程寫回不同,重寫過程是由子進(jìn)程執(zhí)行bgrewriteaof 來完成的。這樣處理的最大好處是:
- 子進(jìn)程進(jìn)行 AOF重寫期間,主進(jìn)程可以繼續(xù)處理命令請求;
- 子進(jìn)程帶有主進(jìn)程的數(shù)據(jù)副本,操作效率更高。
這里有兩個(gè)問題值得我們來思考一下。
1.為什么使用子進(jìn)程,而不是多線程來進(jìn)行AOF重寫呢?
如果是使用線程,線程之間會(huì)共享內(nèi)存,在修改共享內(nèi)存數(shù)據(jù)的時(shí)候,需要通過加鎖來保證數(shù)據(jù)的安全,這樣就會(huì)降低性能。
如果使用子進(jìn)程,操作系統(tǒng)會(huì)使用「寫時(shí)復(fù)制」的技術(shù):fork子進(jìn)程時(shí),子進(jìn)程會(huì)拷貝父進(jìn)程的頁表,即虛實(shí)映射關(guān)系,而不會(huì)拷貝物理內(nèi)存。子進(jìn)程復(fù)制了父進(jìn)程頁表,也能共享訪問父進(jìn)程的內(nèi)存數(shù)據(jù),達(dá)到共享內(nèi)存的效果。
不過這個(gè)共享的內(nèi)存只能以只讀的方式,當(dāng)父子進(jìn)程任意一方修改了該共享內(nèi)存,就會(huì)發(fā)生「寫時(shí)復(fù)制」,于是父子進(jìn)程就有了獨(dú)立的數(shù)據(jù)副本,就不用加鎖來保證數(shù)據(jù)安全。
這里我把在就這?Redis持久化策略——RDB畫過的一張圖拿過來幫助大家理解一下寫時(shí)復(fù)制。
因此,有兩個(gè)過程可能會(huì)導(dǎo)致主進(jìn)程阻塞:
- fork子進(jìn)程的過程中,由于要復(fù)制父進(jìn)程的頁表等數(shù)據(jù),阻塞的時(shí)間跟頁表的大小有關(guān),頁表越大阻塞的時(shí)間也越長,不過通常而言該過程是非??斓?
- fork完子進(jìn)程后,如果父子進(jìn)程任意一方修改了共享數(shù)據(jù),就會(huì)發(fā)生「寫時(shí)復(fù)制」,這期間會(huì)拷貝物理內(nèi)存,如果內(nèi)存越大,自然阻塞的時(shí)間也越長。
針對第二個(gè)過程,有一個(gè)小細(xì)節(jié)在這里提一下。寫時(shí)復(fù)制,復(fù)制的粒度為一個(gè)內(nèi)存頁。如果只是修改一個(gè)256B的數(shù)據(jù),父進(jìn)程需要讀原來的整個(gè)內(nèi)存頁,然后再映射到新的物理地址寫入。一讀一寫會(huì)造成讀寫放大。如果內(nèi)存頁越大(例如2MB的大頁),那么讀寫放大也就越嚴(yán)重,對Redis性能造成影響。因此使用Redis的AOF功能時(shí),需要注意頁表的大小不要設(shè)置的太大。
2.子進(jìn)程在進(jìn)行 AOF 重寫期間,主進(jìn)程還需要繼續(xù)處理命令,而新的命令可能對現(xiàn)有的數(shù)據(jù)進(jìn)行修改, 會(huì)讓當(dāng)前數(shù)據(jù)庫的數(shù)據(jù)和重寫后的 AOF 文件中的數(shù)據(jù)不一致,這該怎么辦?
為了解決這個(gè)問題,Redis引入了另一個(gè)緩沖區(qū)的概念(這也是本文中涉及到的第3個(gè)緩沖區(qū)的概念)——AOF重寫緩沖區(qū)。
換言之, 當(dāng)子進(jìn)程在執(zhí)行AOF重寫(bgrewriteaof)時(shí), 主進(jìn)程需要執(zhí)行以下三個(gè)工作:
- 處理客戶端的命令請求;
- 將寫命令追加到AOF緩沖區(qū)(aof_buf);
- 將寫命令追加到AOF重寫緩沖區(qū)。
這樣一來可以保證:
- 現(xiàn)有的 AOF功能會(huì)繼續(xù)執(zhí)行,即使在 AOF 重寫期間發(fā)生停機(jī),也不會(huì)有任何數(shù)據(jù)丟失;
- 所有對數(shù)據(jù)庫進(jìn)行修改的命令都會(huì)被記錄到AOF重寫緩沖區(qū)中。
當(dāng)子進(jìn)程完成 AOF重寫之后, 它會(huì)向父進(jìn)程發(fā)送一個(gè)完成信號(hào), 父進(jìn)程在接到完成信號(hào)之后, 會(huì)調(diào)用一個(gè)信號(hào)處理函數(shù), 并完成以下工作:
- 將 AOF重寫緩沖區(qū)中的內(nèi)容全部寫入到新AOF 文件中;
- 對新的 AOF 文件進(jìn)行改名,覆蓋原有的 AOF 文件。注意,這是一個(gè)原子操作,改名過程中不接受客戶端指令。
當(dāng)步驟 1 執(zhí)行完畢之后, 現(xiàn)有 AOF 文件、新 AOF 文件和數(shù)據(jù)庫三者的狀態(tài)就完全一致了。
當(dāng)步驟 2 執(zhí)行完畢之后, 程序就完成了新舊兩個(gè) AOF 文件的交替。
這個(gè)信號(hào)處理函數(shù)執(zhí)行完畢之后, 主進(jìn)程就可以繼續(xù)像往常一樣接受命令請求了。 在整個(gè) AOF 后臺(tái)重寫過程中, 只有將AOF重寫緩沖區(qū)數(shù)據(jù)寫入新AOF文件和改名操作會(huì)造成主進(jìn)程阻塞, 其他時(shí)候, AOF 后臺(tái)重寫都不會(huì)對主進(jìn)程造成阻塞, 這將 AOF 重寫對性能造成的影響降到了最低。
AOF 后臺(tái)重寫的觸發(fā)條件
再看一下關(guān)于AOF的其他兩個(gè)配置:
- auto-aof-rewrite-percentage 100
- auto-aof-rewrite-min-size 64mb
AOF 重寫可以由用戶通過調(diào)用 bgrewriteaof手動(dòng)觸發(fā)。
另外, 服務(wù)器在 AOF 功能開啟的情況下, 會(huì)維持以下三個(gè)變量:
- 記錄當(dāng)前 AOF 文件大小的變量 aof_current_size ;
- 記錄最后一次 AOF 重寫之后, AOF 文件大小的變量 aof_rewrite_base_size ;
- 增長百分比變量 aof_rewrite_perc 。
每次當(dāng)Redis中的定時(shí)函數(shù) serverCron 執(zhí)行時(shí), 它都會(huì)檢查以下條件是否全部滿足, 如果是的話, 就會(huì)觸發(fā)自動(dòng)的 AOF 重寫:
- 沒有 bgsave 命令在進(jìn)行。
- 沒有 bgrewriteaof 在進(jìn)行。
- 當(dāng)前 AOF 文件大小大于 我們設(shè)置的auto-aof-rewrite-min-size。
- 當(dāng)前 AOF 文件大小和最后一次 AOF 重寫后的大小之間的比率大于等于指定的增長百分比auto-aof-rewrite-percentage。
默認(rèn)情況下, 增長百分比為 100% , 也即是說, 如果前面三個(gè)條件都已經(jīng)滿足, 并且當(dāng)前 AOF 文件大小比最后一次 AOF 重寫時(shí)的大小要大一倍的話, 那么觸發(fā)自動(dòng) AOF 重寫。
小結(jié)
經(jīng)過多番改稿,終于!給大家梳理完成Redis的AOF持久化方法,最后我們簡單總結(jié)一下。
AOF是將Redis的所有寫日志同步到磁盤的一種持久化方法,通過執(zhí)行AOF中記錄的所有指令可以達(dá)到恢復(fù)Redis原始數(shù)據(jù)狀態(tài)的目的。
對于指令的同步時(shí)機(jī),Redis提供了三種AOF同步策略,分別是No,Everysec,Always,三種策略對Redis性能的負(fù)面影響是由低到高的,在數(shù)據(jù)可靠性上也是由低到高的。
為了解決AOF日志太大的問題,Redis提供了AOF重寫的機(jī)制,利用「寫時(shí)復(fù)制」和「AOF重寫緩沖區(qū)」達(dá)到精簡AOF文件的目的。