特立獨(dú)行是對(duì)的,融入圈子也是對(duì)的,重點(diǎn)是要想清楚自己向往怎樣的生活,為此愿意付出怎樣的代價(jià)。
我們通常將 Redis 作為緩存使用,提高讀取響應(yīng)性能,一旦 Redis 宕機(jī),內(nèi)存中的數(shù)據(jù)全部丟失,假如現(xiàn)在直接訪問(wèn)數(shù)據(jù)庫(kù)大量流量打到 MySQL 可能會(huì)帶來(lái)更加嚴(yán)重的問(wèn)題。
另外慢慢的從數(shù)據(jù)庫(kù)讀取放到 Redis 性能必然比不過(guò)從 Redis 獲取快,也會(huì)導(dǎo)致響應(yīng)變慢。
Redis 為了實(shí)現(xiàn)無(wú)畏宕機(jī)快速恢復(fù),設(shè)計(jì)了兩大殺手锏,分別是 AOF(Append Only FIle)日志和 RDB 快照。
學(xué)習(xí)一個(gè)技術(shù),通常只接觸了零散的技術(shù)點(diǎn),沒(méi)有在腦海里建立一個(gè)完整的知識(shí)框架和架構(gòu)體系,沒(méi)有系統(tǒng)觀。這樣會(huì)很吃力,而且會(huì)出現(xiàn)一看好像自己會(huì),過(guò)后就忘記,一臉懵逼。
本文硬核,建議收藏點(diǎn)贊,靜下心來(lái)閱讀,我相信都會(huì)有很多收獲。
上一篇《Redis 核心篇:唯快不破的秘密》分析了 Redis 的核心數(shù)據(jù)結(jié)構(gòu)、IO 模型、線程模型、根據(jù)不同數(shù)據(jù)使用合適的數(shù)據(jù)編碼。深層次掌握真正快的原因!
本篇將圍繞如下幾點(diǎn)展開(kāi):
宕機(jī)后,如何快速恢復(fù)?
宕機(jī)了,Redis 如何避免數(shù)據(jù)丟失?
什么是 RDB 內(nèi)存快照?
AOF 日志實(shí)現(xiàn)機(jī)制
什么是 寫(xiě)時(shí)復(fù)制技術(shù)?
涉及的知識(shí)點(diǎn)如圖所示:
Redis 日志篇:無(wú)畏宕機(jī)與快速恢復(fù)的殺手锏
Redis 全景圖全景圖可以圍繞兩個(gè)維度展開(kāi),分別是:
應(yīng)用維度:緩存使用、集群運(yùn)用、數(shù)據(jù)結(jié)構(gòu)的巧妙使用
系統(tǒng)維度:可以歸類為三高
高性能:線程模型、網(wǎng)絡(luò) IO 模型、數(shù)據(jù)結(jié)構(gòu)、持久化機(jī)制;
高可用:主從復(fù)制、哨兵集群、Cluster 分片集群;
高拓展:負(fù)載均衡
Redis 系列篇章圍繞如下思維導(dǎo)圖展開(kāi),這次從 《Redis 日志篇:無(wú)畏宕機(jī)與快速恢復(fù)的殺手锏》一起探索 Redis 的高性能、持久化機(jī)制的秘密。
吃透Redis
擁有全景圖,掌握系統(tǒng)觀。
系統(tǒng)觀其實(shí)是至關(guān)重要的,從某種程度上說(shuō),在解決問(wèn)題時(shí),擁有了系統(tǒng)觀,就意味著你能有依據(jù)、有章法地定位和解決問(wèn)題。
RDB 內(nèi)存快照,讓宕機(jī)快速恢復(fù)
65 哥:Redis 因?yàn)槟承┰蝈礄C(jī)了,會(huì)導(dǎo)致所有的流量會(huì)打到后端 MySQL,我立馬重啟 Redis,可是它的數(shù)據(jù)存在內(nèi)存里面,重啟后如何還是沒(méi)有任何數(shù)據(jù),如何防止重啟數(shù)據(jù)丟失呢?
65 哥別急,帶你一步步深入理解到底 Redis 宕機(jī)后如何快速恢復(fù)的。
Redis 數(shù)據(jù)存儲(chǔ)在內(nèi)存中,是否可以考慮將內(nèi)存中的數(shù)據(jù)寫(xiě)到磁盤上呢?當(dāng) Redis 重啟的時(shí)候就把保存在磁盤上的數(shù)據(jù)快速恢復(fù)到內(nèi)存中,這樣就能實(shí)現(xiàn)重啟后正常提供服務(wù)了。
65 哥:我想到一個(gè)方案,每次執(zhí)行「寫(xiě)」操作操作內(nèi)存的同時(shí)寫(xiě)入到磁盤
這個(gè)方案有一個(gè)致命問(wèn)題:每次寫(xiě)指令不僅寫(xiě)內(nèi)存還是寫(xiě)入磁盤,磁盤的性能相對(duì)內(nèi)存太慢,會(huì)導(dǎo)致 Redis 性能大大降低。
內(nèi)存快照
65 哥:那如何規(guī)避這個(gè)同時(shí)寫(xiě)入的問(wèn)題呢?
我們通常將 Redis 當(dāng)作緩存使用,所以即使 Redis 沒(méi)有保存全部數(shù)據(jù),還可以通過(guò)數(shù)據(jù)庫(kù)獲取,所以 Redis 不會(huì)保存所有的數(shù)據(jù), Redis 的數(shù)據(jù)持久化使用了「RDB 數(shù)據(jù)快照」的方式來(lái)實(shí)現(xiàn)宕機(jī)快速恢復(fù)。
65 哥:那什么是 RDB 內(nèi)存快照呢?
在 Redis 執(zhí)行「寫(xiě)」指令過(guò)程中,內(nèi)存數(shù)據(jù)會(huì)一直變化。所謂的內(nèi)存快照,指的就是 Redis 內(nèi)存中的數(shù)據(jù)在某一刻的狀態(tài)數(shù)據(jù)。
好比時(shí)間定格在某一刻,當(dāng)我們拍照的,通過(guò)照片就能把某一刻的瞬間畫(huà)面完全記錄下來(lái)。
Redis 跟這個(gè)類似,就是把某一刻的數(shù)據(jù)以文件的形式拍下來(lái),寫(xiě)到磁盤上。這個(gè)快照文件叫做 RDB 文件,RDB 就是 Redis DataBase 的縮寫(xiě)。
Redis 通過(guò)定時(shí)執(zhí)行 RDB 內(nèi)存快照,這樣就不必每次執(zhí)行「寫(xiě)」指令都寫(xiě)磁盤,只需要在執(zhí)行內(nèi)存快照的時(shí)候?qū)懘疟P。既保證了唯快不破,還實(shí)現(xiàn)了持久化,宕機(jī)快速恢復(fù)。
RDB內(nèi)存快照
在做數(shù)據(jù)恢復(fù)時(shí),直接將 RDB 文件讀入內(nèi)存完成恢復(fù)。
65 哥:對(duì)哪些數(shù)據(jù)做快照呢?或者多久做一次快照呢?這個(gè)會(huì)影響快照的執(zhí)行效率。
65 哥不錯(cuò)呀,開(kāi)始考慮數(shù)據(jù)效率問(wèn)題了。在《Redis 核心篇:唯快不破的秘密》中我們知道他的單線程模型決定了我們要盡可能的避免會(huì)阻塞主線程的操作,避免 RDB 文件生成阻塞主線程。
生成 RDB 策略
Redis 提供了兩個(gè)指令用于生成 RDB 文件:
save:主線程執(zhí)行,會(huì)阻塞;
bgsave:調(diào)用 glibc 的函數(shù)fork產(chǎn)生一個(gè)子進(jìn)程用于寫(xiě)入 RDB 文件,快照持久化完全交給子進(jìn)程來(lái)處理,父進(jìn)程繼續(xù)處理客戶端請(qǐng)求,生成 RDB 文件的默認(rèn)配置。
65 哥:那在對(duì)內(nèi)存數(shù)據(jù)做「快照」的時(shí)候,內(nèi)存數(shù)據(jù)還能修改么?也就是寫(xiě)指令能否正常處理?
首先我們要明確一點(diǎn),避免阻塞和 RDB 文件生成期間能處理寫(xiě)操作不是一回事。雖然主線程沒(méi)有阻塞,到那時(shí)為了保證快照的數(shù)據(jù)的一致性,只能處理讀操作,不能修改正在執(zhí)行快照的數(shù)據(jù)。
很明顯,為了生成 RDB 而暫停寫(xiě)操作,Redis 是不答應(yīng)的。
65 哥:那 Redis 如何實(shí)現(xiàn)一邊處理寫(xiě)請(qǐng)求,同時(shí)生成 RDB 文件呢?
Redis 使用操作系統(tǒng)的多進(jìn)程寫(xiě)時(shí)復(fù)制技術(shù) COW(Copy On Write) 來(lái)實(shí)現(xiàn)快照持久化,這個(gè)機(jī)制很有意思,也很少人知道。多進(jìn)程 COW 也是鑒定程序員知識(shí)廣度的一個(gè)重要指標(biāo)。
Redis 在持久化時(shí)會(huì)調(diào)用 glibc 的函數(shù)fork產(chǎn)生一個(gè)子進(jìn)程,快照持久化完全交給子進(jìn)程來(lái)處理,父進(jìn)程繼續(xù)處理客戶端請(qǐng)求。
子進(jìn)程剛剛產(chǎn)生時(shí),它和父進(jìn)程共享內(nèi)存里面的代碼段和數(shù)據(jù)段。這時(shí)你可以將父子進(jìn)程想像成一個(gè)連體嬰兒,共享身體。
這是 Linux 操作系統(tǒng)的機(jī)制,為了節(jié)約內(nèi)存資源,所以盡可能讓它們共享起來(lái)。在進(jìn)程分離的一瞬間,內(nèi)存的增長(zhǎng)幾乎沒(méi)有明顯變化。
bgsave 子進(jìn)程可以共享主線程的所有內(nèi)存數(shù)據(jù),讀取主線程的數(shù)據(jù)并寫(xiě)入到 RDB 文件。
在執(zhí)行 SAVE 命令或者BGSAVE命令創(chuàng)建一個(gè)新的 RDB 文件時(shí),程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行檢查,已過(guò)期的鍵不會(huì)被保存到新創(chuàng)建的 RDB 文件中。
當(dāng)主線程執(zhí)行寫(xiě)指令修改數(shù)據(jù)的時(shí)候,這個(gè)數(shù)據(jù)就會(huì)復(fù)制一份副本, bgsave 子進(jìn)程讀取這個(gè)副本數(shù)據(jù)寫(xiě)到 RDB 文件,所以主線程就可以直接修改原來(lái)的數(shù)據(jù)。
寫(xiě)時(shí)復(fù)制技術(shù)保證快照期間數(shù)據(jù)客修改
這既保證了快照的完整性,也允許主線程同時(shí)對(duì)數(shù)據(jù)進(jìn)行修改,避免了對(duì)正常業(yè)務(wù)的影響。
Redis 會(huì)使用 bgsave 對(duì)當(dāng)前內(nèi)存中的所有數(shù)據(jù)做快照,這個(gè)操作是子進(jìn)程在后臺(tái)完成的,這就允許主線程同時(shí)可以修改數(shù)據(jù)。
65 哥:那可以每秒都執(zhí)行 RDB 文件么,這樣即使發(fā)生宕機(jī)最多丟失 1 秒的數(shù)據(jù)。
過(guò)于頻繁的執(zhí)行全量數(shù)據(jù)快照,有兩個(gè)嚴(yán)重性能開(kāi)銷:
頻繁生成 RDB 文件寫(xiě)入磁盤,磁盤壓力過(guò)大。會(huì)出現(xiàn)上一個(gè) RDB 還未執(zhí)行完,下一個(gè)又開(kāi)始生成,陷入死循環(huán)。
fork 出 bgsave 子進(jìn)程會(huì)阻塞主線程,主線程的內(nèi)存越大,阻塞時(shí)間越長(zhǎng)。
優(yōu)缺點(diǎn)
快照的恢復(fù)速度快,但是生成 RDB 文件頻率不好把握,頻率過(guò)低宕機(jī)丟失的數(shù)據(jù)就會(huì)比較多;太快,又會(huì)消耗額外開(kāi)銷。
RDB 采用二進(jìn)制 + 數(shù)據(jù)壓縮的方式寫(xiě)磁盤,文件體積小,數(shù)據(jù)恢復(fù)速度快。
Redis 除了 RDB 全量快照以外,還設(shè)計(jì)了 AOF 寫(xiě)后日志,接下來(lái)我們一起來(lái)聊下什么是 AOF 日志。
AOF 寫(xiě)后日志,避免宕機(jī)數(shù)據(jù)丟失AOF 日志存儲(chǔ)的是 Redis 服務(wù)器的順序指令序列,AOF 日志只記錄對(duì)內(nèi)存進(jìn)行修改的指令記錄。
假設(shè) AOF 日志記錄了自 Redis 實(shí)例創(chuàng)建以來(lái)所有的修改性指令序列,那么就可以通過(guò)對(duì)一個(gè)空的 Redis 實(shí)例順序執(zhí)行所有的指令,也就是「重放」,來(lái)恢復(fù) Redis 當(dāng)前實(shí)例的內(nèi)存數(shù)據(jù)結(jié)構(gòu)的狀態(tài)。
寫(xiě)前與寫(xiě)后日志對(duì)比
寫(xiě)前日志(Write Ahead Log, WAL): 在實(shí)際寫(xiě)數(shù)據(jù)之前,將修改的數(shù)據(jù)寫(xiě)到日志文件中,故障恢復(fù)得以保證。
比如 MySQL Innodb 存儲(chǔ)引擎 中的 redo log(重做日志)便是記錄修改的數(shù)據(jù)日志,在實(shí)際修改數(shù)據(jù)前先記錄修改日志在執(zhí)行修改數(shù)據(jù)。
寫(xiě)后日志: 先執(zhí)行「寫(xiě)」指令請(qǐng)求,將數(shù)據(jù)寫(xiě)入內(nèi)存,再記錄日志。
AOF寫(xiě)后指令
日志格式
當(dāng) Redis 接受到 「set key MageByte」命令將數(shù)據(jù)寫(xiě)到內(nèi)存后,Redis 會(huì)按照如下格式寫(xiě)入 AOF 文件。
「*3」:表示當(dāng)前指令分為三個(gè)部分,每個(gè)部分都是 「$ + 數(shù)字」開(kāi)頭,緊跟后面是該部分具體的「指令、鍵、值」。
「數(shù)字」:表示這部分的命令、鍵、值多占用的字節(jié)大小。比如 「$3」表示這部分包含 3 個(gè)字節(jié),也就是 「set」指令。
AOF 日志格式
65 哥:為什么 Redis 使用寫(xiě)后日志這種方式呢?
寫(xiě)后日志避免了額外的檢查開(kāi)銷,不需要對(duì)執(zhí)行的命令進(jìn)行語(yǔ)法檢查。如果使用寫(xiě)前日志的話,就需要先檢查語(yǔ)法是否有誤,否則日志記錄了錯(cuò)誤的命令,在使用日志恢復(fù)的時(shí)候就會(huì)出錯(cuò)。
另外,寫(xiě)后才記錄日志,不會(huì)阻塞當(dāng)前的「寫(xiě)」指令執(zhí)行。
65 哥:那有了 AOF 就萬(wàn)無(wú)一失了么?
傻孩子,可沒(méi)這么簡(jiǎn)單。假如 Redis 剛執(zhí)行完指令,還沒(méi)記錄日志宕機(jī)了,就有可能丟失這個(gè)命令相關(guān)的數(shù)據(jù)。
還有,AOF 避免了當(dāng)前命令的阻塞,但是可能會(huì)給下一個(gè)命令帶來(lái)阻塞的風(fēng)險(xiǎn)。AOF 日志是主線程執(zhí)行,將日志寫(xiě)入磁盤過(guò)程中,如果磁盤壓力大就會(huì)導(dǎo)致寫(xiě)磁盤很慢,導(dǎo)致后續(xù)的「寫(xiě)」指令阻塞。
發(fā)現(xiàn)了沒(méi),這兩個(gè)問(wèn)題與磁盤寫(xiě)回有關(guān),如果能合理的控制「寫(xiě)」指令執(zhí)行完后 AOF 日志寫(xiě)回磁盤的時(shí)機(jī),問(wèn)題就迎刃而解。
寫(xiě)回策略
為了提高文件的寫(xiě)入效率,當(dāng)用戶調(diào)用 write 函數(shù),將一些數(shù)據(jù)寫(xiě)入到文件的時(shí)候,操作系統(tǒng)通常會(huì)將寫(xiě)入數(shù)據(jù)暫時(shí)保存在一個(gè)內(nèi)存緩沖區(qū)里面,等到緩沖區(qū)的空間被填滿、或者超過(guò)了指定的時(shí)限之后,才真正地將緩沖區(qū)中的數(shù)據(jù)寫(xiě)入到磁盤里面。
這種做法雖然提高了效率,但也為寫(xiě)入數(shù)據(jù)帶來(lái)了安全問(wèn)題,因?yàn)槿绻?jì)算機(jī)發(fā)生停機(jī),那么保存在內(nèi)存緩沖區(qū)里面的寫(xiě)入數(shù)據(jù)將會(huì)丟失。
為此,系統(tǒng)提供了fsync和fdatasync兩個(gè)同步函數(shù),它們可以強(qiáng)制讓操作系統(tǒng)立即將緩沖區(qū)中的數(shù)據(jù)寫(xiě)入到硬盤里面,從而確保寫(xiě)入數(shù)據(jù)的安全性。
Redis 提供的 AOF 配置項(xiàng)appendfsync寫(xiě)回策略直接決定 AOF 持久化功能的效率和安全性。
always:同步寫(xiě)回,寫(xiě)指令執(zhí)行完畢立馬將 aof_buf緩沖區(qū)中的內(nèi)容刷寫(xiě)到 AOF 文件。
everysec:每秒寫(xiě)回,寫(xiě)指令執(zhí)行完,日志只會(huì)寫(xiě)到 AOF 文件緩沖區(qū),每隔一秒就把緩沖區(qū)內(nèi)容同步到磁盤。
no: 操作系統(tǒng)控制,寫(xiě)執(zhí)行執(zhí)行完畢,把日志寫(xiě)到 AOF 文件內(nèi)存緩沖區(qū),由操作系統(tǒng)決定何時(shí)刷寫(xiě)到磁盤。
沒(méi)有兩全其美的策略,我們需要在性能和可靠性上做一個(gè)取舍。
always同步寫(xiě)回可以做到數(shù)據(jù)不丟失,但是每個(gè)「寫(xiě)」指令都需要寫(xiě)入磁盤,性能最差。
everysec每秒寫(xiě)回,避免了同步寫(xiě)回的性能開(kāi)銷,發(fā)生宕機(jī)可能有一秒位寫(xiě)入磁盤的數(shù)據(jù)丟失,在性能和可靠性之間做了折中。
no操作系統(tǒng)控制,執(zhí)行寫(xiě)指令后就寫(xiě)入 AOF 文件緩沖就可以執(zhí)行后續(xù)的「寫(xiě)」指令,性能最好,但是有可能丟失很多的數(shù)據(jù)。
65 哥:那我該如何選擇策略呢?
我們可以根據(jù)系統(tǒng)對(duì)高性能和高可靠性的要求,來(lái)選擇寫(xiě)回策略。總結(jié)一下:想要獲得高性能,就選擇 No 策略;如果想要得到高可靠性保證,就選擇 Always 策略;如果允許數(shù)據(jù)有一點(diǎn)丟失,又希望性能別受太大影響的話,那么就選擇 Everysec 策略。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):執(zhí)行成功才記錄日志,避免了指令語(yǔ)法檢查開(kāi)銷。同時(shí),不會(huì)阻塞當(dāng)前「寫(xiě)」指令。
缺點(diǎn):由于 AOF 記錄的是一個(gè)個(gè)指令內(nèi)容,具體格式請(qǐng)看上面的日志格式。故障恢復(fù)的時(shí)候需要執(zhí)行每一個(gè)指令,如果日志文件太大,整個(gè)恢復(fù)過(guò)程就會(huì)非常緩慢。
另外文件系統(tǒng)對(duì)文件大小也有限制,不能保存過(guò)大文件,文件變大,追加效率也會(huì)變低。
日志過(guò)大:AOF 重寫(xiě)機(jī)制
65 哥:AOF 日志文件過(guò)大著怎么辦?
AOF 寫(xiě)前日志,記錄的是每個(gè)「寫(xiě)」指令操作。不會(huì)像 RDB 全量快照導(dǎo)致性能損耗,但是執(zhí)行速度沒(méi)有 RDB 快,同時(shí)日志文件過(guò)大也會(huì)造成性能問(wèn)題,對(duì)于唯快不破的 Redis 這個(gè)真男人來(lái)說(shuō),絕對(duì)不能忍受日志過(guò)大導(dǎo)致的問(wèn)題。
所以,Redis 設(shè)計(jì)了一個(gè)殺手锏「AOF 重寫(xiě)機(jī)制」,Redis 提供了 bgrewriteaof指令用于對(duì) AOF 日志進(jìn)行瘦身。
其原理就是開(kāi)辟一個(gè)子進(jìn)程對(duì)內(nèi)存進(jìn)行遍歷轉(zhuǎn)換成一系列 Redis 的操作指令,序列化到一個(gè)新的 AOF 日志文件中。序列化完畢后再將操作期間發(fā)生的增量 AOF 日志追加到這個(gè)新的 AOF 日志文件中,追加完畢后就立即替代舊的 AOF 日志文件了,瘦身工作就完成了。
65 哥:為啥 AOF 重寫(xiě)機(jī)制能縮小日志文件呢?
重寫(xiě)機(jī)制有「多變一」功能,將舊日志中的多條指令,在重寫(xiě)后就變成了一條指令。
如下所示:
AOF重寫(xiě)機(jī)制(糾錯(cuò):重寫(xiě)前記錄了 3 條指令)
65 哥:重寫(xiě)后 AOF 日志變小,最后把整個(gè)數(shù)據(jù)庫(kù)最新數(shù)據(jù)的操作日志刷寫(xiě)到磁盤了。重寫(xiě)會(huì)不會(huì)阻塞主線程呢?
上文說(shuō)了,AOF 日志是主線程寫(xiě)回的,AOF 重寫(xiě)的過(guò)程實(shí)際上后臺(tái)子進(jìn)程 bgrewriteaof 完成,防止阻塞主線程。
重寫(xiě)過(guò)程
和 AOF 日志由主線程寫(xiě)回不同,重寫(xiě)過(guò)程是由后臺(tái)子進(jìn)程 bgrewriteaof 來(lái)完成的,這也是為了避免阻塞主線程,導(dǎo)致數(shù)據(jù)庫(kù)性能下降。
總的來(lái)說(shuō),一共出現(xiàn) 兩個(gè)日志,一次拷內(nèi)存數(shù)據(jù)拷貝,分別是舊的 AOF 日志和新的 AOF 重寫(xiě)日志和 Redis 數(shù)據(jù)拷貝。
Redis 會(huì)將重寫(xiě)過(guò)程中的接收到的「寫(xiě)」指令操作同時(shí)記錄到舊的 AOF 緩沖區(qū)和 AOF 重寫(xiě)緩沖區(qū),這樣重寫(xiě)日志也保存最新的操作。等到拷貝數(shù)據(jù)的所有操作記錄重寫(xiě)完成后,重寫(xiě)緩沖區(qū)記錄的最新操作也會(huì)寫(xiě)到新的 AOF 文件中。
每次 AOF 重寫(xiě)時(shí),Redis 會(huì)先執(zhí)行一個(gè)內(nèi)存拷貝,用于遍歷數(shù)據(jù)生成重寫(xiě)記錄;使用兩個(gè)日志保證在重寫(xiě)過(guò)程中,新寫(xiě)入的數(shù)據(jù)不會(huì)丟失,并且保持?jǐn)?shù)據(jù)一致性。
AOF 重寫(xiě)過(guò)程
65 哥:AOF 重寫(xiě)也有一個(gè)重寫(xiě)日志,為什么它不共享使用 AOF 本身的日志呢?
這個(gè)問(wèn)題問(wèn)得好,有以下兩個(gè)原因:
一個(gè)原因是父子進(jìn)程寫(xiě)同一個(gè)文件必然會(huì)產(chǎn)生競(jìng)爭(zhēng)問(wèn)題,控制競(jìng)爭(zhēng)就意味著會(huì)影響父進(jìn)程的性能。
如果 AOF 重寫(xiě)過(guò)程中失敗了,那么原本的 AOF 文件相當(dāng)于被污染了,無(wú)法做恢復(fù)使用。所以 Redis AOF 重寫(xiě)一個(gè)新文件,重寫(xiě)失敗的話,直接刪除這個(gè)文件就好了,不會(huì)對(duì)原先的 AOF 文件產(chǎn)生影響。等重寫(xiě)完成之后,直接替換舊文件即可。
Redis 4.0 混合日志模型重啟 Redis 時(shí),我們很少使用 rdb 來(lái)恢復(fù)內(nèi)存狀態(tài),因?yàn)闀?huì)丟失大量數(shù)據(jù)。我們通常使用 AOF 日志重放,但是重放 AOF 日志性能相對(duì) rdb 來(lái)說(shuō)要慢很多,這樣在 Redis 實(shí)例很大的情況下,啟動(dòng)需要花費(fèi)很長(zhǎng)的時(shí)間。
Redis 4.0 為了解決這個(gè)問(wèn)題,帶來(lái)了一個(gè)新的持久化選項(xiàng)——混合持久化。將 rdb 文件的內(nèi)容和增量的 AOF 日志文件存在一起。這里的 AOF 日志不再是全量的日志,而是自持久化開(kāi)始到持久化結(jié)束的這段時(shí)間發(fā)生的增量 AOF 日志,通常這部分 AOF 日志很小。
于是在 Redis 重啟的時(shí)候,可以先加載 rdb 的內(nèi)容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重啟效率因此大幅得到提升。
所以 RDB 內(nèi)存快照以稍微慢一點(diǎn)的頻率執(zhí)行,在兩次 RDB 快照期間使用 AOF 日志記錄期間發(fā)生的所有「寫(xiě)」操作。
這樣快照就不用頻繁的執(zhí)行,同時(shí)由于 AOF 只需要記錄兩次快照之間發(fā)生的「寫(xiě)」指令,不需要記錄所有的操作,避免出現(xiàn)文件過(guò)大的情況。
總結(jié)Redis 設(shè)計(jì)了 bgsave 和寫(xiě)時(shí)復(fù)制,盡可能避免執(zhí)行快照期間對(duì)讀寫(xiě)指令的影響,頻繁快照會(huì)給磁盤帶來(lái)壓力以及 fork 阻塞主線程。
Redis 設(shè)計(jì)了兩大殺手锏實(shí)現(xiàn)了宕機(jī)快速恢復(fù),數(shù)據(jù)不丟失。
避免日志過(guò)大,提供了 AOF 重寫(xiě)機(jī)制,根據(jù)數(shù)據(jù)庫(kù)的數(shù)據(jù)最新?tīng)顟B(tài),生成數(shù)據(jù)的寫(xiě)操作作為新日志,并且通過(guò)后臺(tái)完成不阻塞主線程。
綜合 AOF 和 RDB 在 Redis 4.0 提供了新的持久化策略,混合日志模型。在 Redis 重啟的時(shí)候,可以先加載 rdb 的內(nèi)容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重啟效率因此大幅得到提升。
最后,關(guān)于 AOF 和 RDB 的選擇問(wèn)題,有三點(diǎn)建議:
數(shù)據(jù)不能丟失時(shí),內(nèi)存快照和 AOF 的混合使用是一個(gè)很好的選擇;
如果允許分鐘級(jí)別的數(shù)據(jù)丟失,可以只使用 RDB;
如果只用 AOF,優(yōu)先使用 everysec 的配置選項(xiàng),因?yàn)樗诳煽啃院托阅苤g取了一個(gè)平衡。
原文標(biāo)題:Redis 日志篇:無(wú)畏宕機(jī)快速恢復(fù)的殺手锏
文章出處:【微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
責(zé)任編輯:haq
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7077瀏覽量
89161 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3034瀏覽量
74131 -
Redis
+關(guān)注
關(guān)注
0文章
376瀏覽量
10887
原文標(biāo)題:Redis 日志篇:無(wú)畏宕機(jī)快速恢復(fù)的殺手锏
文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論