高頻面試題——Redis 的 AOF 持久化
良心公眾號(hào)
關(guān)注不迷路
01
AOF 持久化背景
在之前的高頻面試題——Redis 的 RDB 持久化文章中,我們討論了 Redis 的 RDB 持久化。由于?RDB 文件的寫(xiě)入并不是實(shí)時(shí)的,通過(guò) RDB 文件僅僅能將數(shù)據(jù)庫(kù)狀態(tài)恢復(fù)到上一次 RDB 持久化的狀態(tài),在此之后所做的改動(dòng)將會(huì)被丟失,因此,RDB 持久化比較適用于對(duì)數(shù)據(jù)丟失不敏感的場(chǎng)合。
為了應(yīng)對(duì)對(duì)數(shù)據(jù)丟失比較敏感的場(chǎng)合,Redis 提供了另外一種持久化的方式,也就是本文要提到的 AOF 持久化。
02
AOF 持久化簡(jiǎn)介
與 RDB 持久化通過(guò)保存數(shù)據(jù)庫(kù)中的鍵值對(duì)來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài)的方式不同,AOF 持久化是通過(guò)保存 Redis 服務(wù)所執(zhí)行的寫(xiě)命令來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài)的。
03
AOF 持久化原理
AOF 持久化功能的具體實(shí)現(xiàn)可以分為:命令追加,文件寫(xiě)入與同步。
命令追加
當(dāng)開(kāi)啟 AOF 持久化功能之后,Redis 服務(wù)器在執(zhí)行完成一個(gè)寫(xiě)命令之后,會(huì)將該命令追加到 aof_buf 緩沖區(qū)末尾。
文件寫(xiě)入與同步
當(dāng)命令追加到 aof_buf 緩沖區(qū)末尾,Redis 進(jìn)程會(huì)調(diào)用 flushAppendOnlyFile 方法,然后根據(jù)配置來(lái)決定是否將 aof_buf 緩沖區(qū)中的內(nèi)容寫(xiě)入和保存到 AOF 文件中。這個(gè)配置是由 redis.conf 中的 appendfsync 選項(xiàng)的值來(lái)決定的。
appendfsync 的值有如下三個(gè)選項(xiàng):
always:?將 aof_buf 緩沖區(qū)中的所有內(nèi)容寫(xiě)入并同步到 AOF 文件。
everysec (默認(rèn)):?將 aof_buf 緩沖區(qū)中的所有內(nèi)容寫(xiě)入到 AOF 文件,但是否同步 AOF 文件取決于和上次同步的時(shí)間間隔是否超過(guò)一秒鐘。
no:?將?aof_buf?緩沖區(qū)中的所有內(nèi)容寫(xiě)入到 AOF 文件,但不主動(dòng)對(duì)其進(jìn)行同步,具體何時(shí)同步 AOF 文件由操作系統(tǒng)決定。
appendfsync 這三種選項(xiàng)實(shí)際上就是對(duì)于 AOF 寫(xiě)入和同步的三種策略。
always 策略是最為嚴(yán)格的,每次?flushAppendOnlyFile 都需要對(duì) AOF 文件進(jìn)行同步,因此效率最低,但換來(lái)的是較高的數(shù)據(jù)安全性,如果系統(tǒng)宕機(jī),僅僅會(huì)丟失當(dāng)前事件循環(huán)中執(zhí)行的寫(xiě)入命令。
everysec 策略的嚴(yán)格程度次之,對(duì)于 AOF 文件的同步是以一秒鐘為間隔的,因此效率相對(duì)高一些,但也就會(huì)有數(shù)據(jù)安全性方面的損失,如果系統(tǒng)宕機(jī),會(huì)丟失最近一秒鐘執(zhí)行的寫(xiě)入命令。
no?策略的嚴(yán)格程度最弱,在 執(zhí)行?flushAppendOnlyFile 方法期間,不會(huì)對(duì) AOF 文件進(jìn)行同步,因此效率最高,但數(shù)據(jù)安全性方面最弱,同時(shí),在操作系統(tǒng)對(duì)于 AOF 文件進(jìn)行同步的時(shí)候,由于期間可能積攢了大量的命令,所以單次同步時(shí)間會(huì)比較長(zhǎng),同時(shí),如果系統(tǒng)宕機(jī),會(huì)丟失從上次同步之后的所有寫(xiě)入命令。
由于 AOF 文件中包含了重建數(shù)據(jù)庫(kù)狀態(tài)所需的所有寫(xiě)入命令 (不考慮數(shù)據(jù)丟失情況),因此,服務(wù)器只需要讀取 AOF 文件并執(zhí)行其中的命令,即可還原服務(wù)器之前的狀態(tài),這也就實(shí)現(xiàn)了 AOF 持久化。
04
AOF?文件重寫(xiě)
細(xì)心的小伙伴可能會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,隨著時(shí)間的流逝,寫(xiě)入命令的量可能是巨大的,這會(huì)導(dǎo)致 AOF 文件的不斷膨脹,這不僅會(huì)占用更多計(jì)算資源,也會(huì)在使用 AOF 文件還原數(shù)據(jù)的時(shí)候耗費(fèi)更多的時(shí)間。為了解決這個(gè)問(wèn)題,Redis 提供了 AOF 文件重寫(xiě)功能。
值得注意的是,AOF 文件重寫(xiě)的分析對(duì)象并不是現(xiàn)有的 AOF 文件,而是當(dāng)前的數(shù)據(jù)庫(kù)狀態(tài)。舉個(gè)例子:
redis>?RPUSH?numbers?1redis>?RPUSH?numbers?2redis>?RPUSH?numbers?3redis>?LPOP?numbers
在對(duì) numbers 鍵執(zhí)行上述命令時(shí),服務(wù)器為了保存當(dāng)前 numbers 鍵的狀態(tài),會(huì)在 AOF 文件中寫(xiě)入上述四條命令。但在進(jìn)行 AOF 重寫(xiě)時(shí),對(duì) numbers 鍵的狀態(tài)進(jìn)行分析,只需要保存下面這一條命令即可:
?RPUSH?numbers?2?3這就是 AOF 文件重寫(xiě)的基本原理,通過(guò) AOF 文件重寫(xiě),可以將針對(duì)于同一個(gè)鍵的眾多命令進(jìn)行合并,大大減少命令數(shù)量,從而達(dá)到節(jié)省資源和提高效率的目的。
值得注意的是,由于 AOF 文件重寫(xiě)方法可能會(huì)執(zhí)行大量的寫(xiě)入操作,因此,執(zhí)行該方法的線程會(huì)被阻塞,由于 Redis 服務(wù)器是單線程的,因此,由 Redis 服務(wù)器線程來(lái)執(zhí)行 AOF 文件重寫(xiě)方法是不合適的。對(duì)此,Redis 的處理是將 AOF 文件重寫(xiě)方法放到子進(jìn)程里進(jìn)行執(zhí)行,這樣可以避免阻塞服務(wù)器進(jìn)程。同時(shí),子進(jìn)程持有服務(wù)器進(jìn)程的數(shù)據(jù)副本,從而避免了數(shù)據(jù)共享,在不必考慮加鎖的情況下保證了數(shù)據(jù)安全。
05
數(shù)據(jù)一致性
那么問(wèn)題又來(lái)了,子進(jìn)程在執(zhí)行 AOF 文件重寫(xiě)期間,服務(wù)器很有可能會(huì)接收到新的寫(xiě)命令,此時(shí),如何保證子進(jìn)程和服務(wù)器進(jìn)程數(shù)據(jù)一致呢?Redis 為了解決這個(gè)問(wèn)題,引入了 AOF 重寫(xiě)緩沖區(qū)的概念。當(dāng) Redis 服務(wù)器執(zhí)行寫(xiě)命令之后,會(huì)同時(shí)將這個(gè)寫(xiě)命令發(fā)送到 AOF 緩沖區(qū)和 AOF 重寫(xiě)緩沖區(qū)。當(dāng)子進(jìn)程完成 AOF 重寫(xiě)之后,會(huì)向父進(jìn)程發(fā)送一個(gè)信號(hào),父進(jìn)程接收到信號(hào)之后,會(huì)將 AOF 重寫(xiě)緩沖區(qū)中的內(nèi)容寫(xiě)入到新的 AOF 文件中,并用新的 AOF 文件原子地覆蓋掉舊的 AOF 文件。
綜上所述,本文關(guān)于?Redis 的 AOF 持久化機(jī)制就總結(jié)到這里了。
歡迎關(guān)注【有理想的菜雞】公眾號(hào),大家一起討論技術(shù),共同成長(zhǎng)!
06
相關(guān)閱讀
Redis 的五種基本類(lèi)型(實(shí)戰(zhàn)篇)
07
參考資料
《Redis 設(shè)計(jì)與實(shí)現(xiàn)》黃健宏 著
https://github.com/redis/redis

學(xué)習(xí) | 工作 |?分享
??關(guān)注“有理想的菜雞”
