Redis持久化機(jī)制

我們通常將 Redis 作為緩存使用酵幕,提高讀取響應(yīng)性能扰藕,一旦 Redis 宕機(jī),內(nèi)存中的數(shù)據(jù)全部丟失芳撒,假如現(xiàn)在直接訪問數(shù)據(jù)庫(kù)大量流量打到 MySQL 可能會(huì)帶來(lái)更加嚴(yá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 快照舌菜。

RDB 內(nèi)存快照萌壳,讓宕機(jī)快速恢復(fù)

在 Redis 執(zhí)行「寫」指令過(guò)程中,內(nèi)存數(shù)據(jù)會(huì)一直變化日月。所謂的內(nèi)存快照袱瓮,指的就是 Redis 內(nèi)存中的數(shù)據(jù)在某一刻的狀態(tài)數(shù)據(jù)。

好比時(shí)間定格在某一刻爱咬,當(dāng)我們拍照的尺借,通過(guò)照片就能把某一刻的瞬間畫面完全記錄下來(lái)。

Redis 跟這個(gè)類似精拟,就是把某一刻的數(shù)據(jù)以文件的形式拍下來(lái)褐望,寫到磁盤上。這個(gè)快照文件叫做 RDB 文件串前,RDB 就是 Redis DataBase 的縮寫瘫里。

Redis 通過(guò)定時(shí)執(zhí)行 RDB 內(nèi)存快照,這樣就不必每次執(zhí)行「寫」指令都寫磁盤荡碾,只需要在執(zhí)行內(nèi)存快照的時(shí)候?qū)懘疟P谨读。既保證了唯快不破,還實(shí)現(xiàn)了持久化坛吁,宕機(jī)快速恢復(fù)劳殖。

在做數(shù)據(jù)恢復(fù)時(shí),直接將 RDB 文件讀入內(nèi)存完成恢復(fù)拨脉。

生成 RDB 策略

Redis 提供了兩個(gè)指令用于生成 RDB 文件:

  • save:主線程執(zhí)行哆姻,會(huì)阻塞;
  • bgsave:調(diào)用 glibc 的函數(shù)fork產(chǎn)生一個(gè)子進(jìn)程用于寫入 RDB 文件玫膀,快照持久化完全交給子進(jìn)程來(lái)處理矛缨,父進(jìn)程繼續(xù)處理客戶端請(qǐng)求,生成 RDB 文件的默認(rèn)配置

Redis 如何實(shí)現(xiàn)一邊處理寫請(qǐng)求,同時(shí)生成 RDB 文件呢箕昭?

Redis 使用操作系統(tǒng)的多進(jìn)程寫時(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è)連體嬰兒穆壕,共享身體戳粒。

bgsave 子進(jìn)程可以共享主線程的所有內(nèi)存數(shù)據(jù),讀取主線程的數(shù)據(jù)并寫入到 RDB 文件。

在執(zhí)行 SAVE 命令或者BGSAVE命令創(chuàng)建一個(gè)新的 RDB 文件時(shí)梗顺,程序會(huì)對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行檢查舆乔,已過(guò)期的鍵不會(huì)被保存到新創(chuàng)建的 RDB 文件中羽氮。

當(dāng)主線程執(zhí)行寫指令修改數(shù)據(jù)的時(shí)候杨蛋,這個(gè)數(shù)據(jù)就會(huì)復(fù)制一份副本, bgsave 子進(jìn)程讀取這個(gè)副本數(shù)據(jù)寫到 RDB 文件错览,所以主線程就可以直接修改原來(lái)的數(shù)據(jù)纫雁。

寫時(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ù)忌愚。

RDB的優(yōu)缺點(diǎn)

快照的恢復(fù)速度快,但是生成 RDB 文件頻率不好把握却邓,頻率過(guò)低宕機(jī)丟失的數(shù)據(jù)就會(huì)比較多硕糊;太快,又會(huì)消耗額外開銷腊徙。

RDB 采用二進(jìn)制 + 數(shù)據(jù)壓縮的方式寫磁盤简十,文件體積小,數(shù)據(jù)恢復(fù)速度快撬腾。

AOF 寫后日志螟蝙,避免宕機(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)初坠。

寫前與寫后日志對(duì)比

寫前日志(Write Ahead Log, WAL): 在實(shí)際寫數(shù)據(jù)之前和簸,將修改的數(shù)據(jù)寫到日志文件中彭雾,故障恢復(fù)得以保證碟刺。

比如 MySQL Innodb 存儲(chǔ)引擎 中的 redo log(重做日志)便是記錄修改的數(shù)據(jù)日志,在實(shí)際修改數(shù)據(jù)前先記錄修改日志在執(zhí)行修改數(shù)據(jù)薯酝。

寫后日志: 先執(zhí)行「寫」指令請(qǐng)求半沽,將數(shù)據(jù)寫入內(nèi)存,再記錄日志吴菠。

AOF 使用寫后日志這種方式者填。寫后日志避免了額外的檢查開銷,不需要對(duì)執(zhí)行的命令進(jìn)行語(yǔ)法檢查做葵。如果使用寫前日志的話占哟,就需要先檢查語(yǔ)法是否有誤,否則日志記錄了錯(cuò)誤的命令酿矢,在使用日志恢復(fù)的時(shí)候就會(huì)出錯(cuò)榨乎。

另外,寫后才記錄日志瘫筐,不會(huì)阻塞當(dāng)前的「寫」指令執(zhí)行蜜暑。

“有了 AOF 就萬(wàn)無(wú)一失了么?”

假如 Redis 剛執(zhí)行完指令策肝,還沒記錄日志宕機(jī)了肛捍,就有可能丟失這個(gè)命令相關(guān)的數(shù)據(jù)。

還有之众,AOF 避免了當(dāng)前命令的阻塞拙毫,但是可能會(huì)給下一個(gè)命令帶來(lái)阻塞的風(fēng)險(xiǎn)。AOF 日志是主線程執(zhí)行棺禾,將日志寫入磁盤過(guò)程中缀蹄,如果磁盤壓力大就會(huì)導(dǎo)致寫磁盤很慢,導(dǎo)致后續(xù)的「寫」指令阻塞帘睦。

這兩個(gè)問題與磁盤寫回有關(guān)袍患,如果能合理的控制「寫」指令執(zhí)行完后 AOF 日志寫回磁盤的時(shí)機(jī),問題就迎刃而解竣付。

寫回策略

為了提高文件的寫入效率诡延,當(dāng)用戶調(diào)用 write 函數(shù),將一些數(shù)據(jù)寫入到文件的時(shí)候古胆,操作系統(tǒng)通常會(huì)將寫入數(shù)據(jù)暫時(shí)保存在一個(gè)內(nèi)存緩沖區(qū)里面肆良,等到緩沖區(qū)的空間被填滿筛璧、或者超過(guò)了指定的時(shí)限之后,才真正地將緩沖區(qū)中的數(shù)據(jù)寫入到磁盤里面惹恃。

這種做法雖然提高了效率夭谤,但也為寫入數(shù)據(jù)帶來(lái)了安全問題,因?yàn)槿绻?jì)算機(jī)發(fā)生停機(jī)巫糙,那么保存在內(nèi)存緩沖區(qū)里面的寫入數(shù)據(jù)將會(huì)丟失朗儒。

為此,系統(tǒng)提供了fsync和fdatasync兩個(gè)同步函數(shù)参淹,它們可以強(qiáng)制讓操作系統(tǒng)立即將緩沖區(qū)中的數(shù)據(jù)寫入到硬盤里面醉锄,從而確保寫入數(shù)據(jù)的安全性。

Redis 提供的 AOF 配置項(xiàng)appendfsync寫回策略直接決定 AOF 持久化功能的效率和安全性浙值。

  • always:同步寫回恳不,寫指令執(zhí)行完畢立馬將 aof_buf緩沖區(qū)中的內(nèi)容刷寫到 AOF 文件。
  • everysec:每秒寫回开呐,寫指令執(zhí)行完烟勋,日志只會(huì)寫到 AOF 文件緩沖區(qū),每隔一秒就把緩沖區(qū)內(nèi)容同步到磁盤筐付。
  • no: 操作系統(tǒng)控制卵惦,寫執(zhí)行執(zhí)行完畢,把日志寫到 AOF 文件內(nèi)存緩沖區(qū)家妆,由操作系統(tǒng)決定何時(shí)刷寫到磁盤鸵荠。

沒有兩全其美的策略,我們需要在性能和可靠性上做一個(gè)取舍伤极。

always同步寫回可以做到數(shù)據(jù)不丟失蛹找,但是每個(gè)「寫」指令都需要寫入磁盤,性能最差哨坪。

everysec每秒寫回庸疾,避免了同步寫回的性能開銷,發(fā)生宕機(jī)可能有一秒位寫入磁盤的數(shù)據(jù)丟失当编,在性能和可靠性之間做了折中届慈。

no操作系統(tǒng)控制,執(zhí)行寫指令后就寫入 AOF 文件緩沖就可以執(zhí)行后續(xù)的「寫」指令忿偷,性能最好金顿,但是有可能丟失很多的數(shù)據(jù)。

日志過(guò)大:AOF 重寫機(jī)制

Redis 設(shè)計(jì)了一個(gè)殺手锏「AOF 重寫機(jī)制」鲤桥,Redis 提供了 bgrewriteaof指令用于對(duì) AOF 日志進(jìn)行瘦身揍拆。

其原理就是開辟一個(gè)子進(jìn)程對(duì)內(nèi)存進(jìn)行遍歷轉(zhuǎn)換成一系列 Redis 的操作指令,序列化到一個(gè)新的 AOF 日志文件中茶凳。序列化完畢后再將操作期間發(fā)生的增量 AOF 日志追加到這個(gè)新的 AOF 日志文件中嫂拴,追加完畢后就立即替代舊的 AOF 日志文件了播揪,瘦身工作就完成了。

重寫機(jī)制有「多變一」功能筒狠,將舊日志中的多條指令猪狈,在重寫后就變成了一條指令。

重寫過(guò)程
和 AOF 日志由主線程寫回不同辩恼,重寫過(guò)程是由后臺(tái)子進(jìn)程 bgrewriteaof 來(lái)完成的雇庙,這也是為了避免阻塞主線程,導(dǎo)致數(shù)據(jù)庫(kù)性能下降运挫。

“AOF 重寫也有一個(gè)重寫日志状共,為什么它不共享使用 AOF 本身的日志呢套耕?”

1谁帕、一個(gè)原因是父子進(jìn)程寫同一個(gè)文件必然會(huì)產(chǎn)生競(jìng)爭(zhēng)問題,控制競(jìng)爭(zhēng)就意味著會(huì)影響父進(jìn)程的性能冯袍。
2匈挖、如果 AOF 重寫過(guò)程中失敗了,那么原本的 AOF 文件相當(dāng)于被污染了康愤,無(wú)法做恢復(fù)使用儡循。所以 Redis AOF 重寫一個(gè)新文件,重寫失敗的話征冷,直接刪除這個(gè)文件就好了择膝,不會(huì)對(duì)原先的 AOF 文件產(chǎn)生影響。等重寫完成之后检激,直接替換舊文件即可肴捉。

Redis 4.0 混合日志模型

Redis 4.0 為了解決這個(gè)問題,帶來(lái)了一個(gè)新的持久化選項(xiàng)——混合持久化叔收。將 rdb 文件的內(nèi)容和增量的 AOF 日志文件存在一起齿穗。這里的 AOF 日志不再是全量的日志,而是自持久化開始到持久化結(jié)束的這段時(shí)間發(fā)生的增量 AOF 日志饺律,通常這部分 AOF 日志很小窃页。

于是在 Redis 重啟的時(shí)候,可以先加載 rdb 的內(nèi)容复濒,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放脖卖,重啟效率因此大幅得到提升。

所以 RDB 內(nèi)存快照以稍微慢一點(diǎn)的頻率執(zhí)行巧颈,在兩次 RDB 快照期間使用 AOF 日志記錄期間發(fā)生的所有「寫」操作畦木。

這樣快照就不用頻繁的執(zhí)行,同時(shí)由于 AOF 只需要記錄兩次快照之間發(fā)生的「寫」指令洛二,不需要記錄所有的操作馋劈,避免出現(xiàn)文件過(guò)大的情況攻锰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市妓雾,隨后出現(xiàn)的幾起案子娶吞,更是在濱河造成了極大的恐慌,老刑警劉巖械姻,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妒蛇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡楷拳,警方通過(guò)查閱死者的電腦和手機(jī)绣夺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)欢揖,“玉大人陶耍,你說(shuō)我怎么就攤上這事∷欤” “怎么了烈钞?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)坤按。 經(jīng)常有香客問我毯欣,道長(zhǎng),這世上最難降的妖魔是什么臭脓? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任酗钞,我火速辦了婚禮,結(jié)果婚禮上来累,老公的妹妹穿的比我還像新娘砚作。我一直安慰自己,他們只是感情好佃扼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布偎巢。 她就那樣靜靜地躺著,像睡著了一般兼耀。 火紅的嫁衣襯著肌膚如雪压昼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天瘤运,我揣著相機(jī)與錄音窍霞,去河邊找鬼。 笑死拯坟,一個(gè)胖子當(dāng)著我的面吹牛但金,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播郁季,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼冷溃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钱磅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起似枕,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盖淡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后凿歼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褪迟,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年答憔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了味赃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虐拓,死狀恐怖心俗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侯嘀,我是刑警寧澤另凌,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站戒幔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏土童。R本人自食惡果不足惜诗茎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望献汗。 院中可真熱鬧敢订,春花似錦、人聲如沸罢吃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)尿招。三九已至矾柜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間就谜,已是汗流浹背怪蔑。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丧荐,地道東北人缆瓣。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像虹统,于是被迫代替她去往敵國(guó)和親弓坞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子隧甚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容