Redis持久化機(jī)制
Redis 的數(shù)據(jù)全部在內(nèi)存里坏逢,如果突然宕機(jī)域帐,數(shù)據(jù)就會(huì)全部丟失,因此必須有一種機(jī)制來(lái)保證 Redis 的數(shù)據(jù)不會(huì)因?yàn)楣收隙鴣G失是整,這種機(jī)制就是 Redis 的持久化機(jī)制肖揣。
什么是持久化?
就是把內(nèi)存里的數(shù)據(jù)保存到硬盤(pán)上浮入。
必須使用數(shù)據(jù)持久化嗎?
Redis的數(shù)據(jù)持久化機(jī)制是可以關(guān)閉的龙优。如果你只把Redis作為緩存服務(wù)使用,Redis中存儲(chǔ)的所有數(shù)據(jù)都不是該數(shù)據(jù)的主體而僅僅是同步過(guò)來(lái)的備份事秀,那么可以關(guān)閉Redis的數(shù)據(jù)持久化機(jī)制彤断。
但通常來(lái)說(shuō),仍然建議至少開(kāi)啟RDB方式的數(shù)據(jù)持久化易迹,因?yàn)椋?br>
①數(shù)據(jù)量不是非常大時(shí)宰衙,RDB方式的持久化幾乎不損耗Redis本身的性能,因?yàn)镽edis父進(jìn)程持久化時(shí)只需要fork一個(gè)子進(jìn)程睹欲,這個(gè)子進(jìn)程可以共享主進(jìn)程的所有內(nèi)存數(shù)據(jù)供炼,子進(jìn)程會(huì)去讀取主進(jìn)程的內(nèi)存數(shù)據(jù)一屋,并把它們寫(xiě)入RDB文件。
②Redis無(wú)論因?yàn)槭裁丛虬l(fā)送故障袋哼,重啟時(shí)能夠自動(dòng)恢復(fù)到上一次RDB快照中記錄的數(shù)據(jù)(自動(dòng)加載RDB文件)冀墨。這省去了手工從其他數(shù)據(jù)源(如數(shù)據(jù)庫(kù))同步數(shù)據(jù)的過(guò)程,而且要比其他任何的數(shù)據(jù)恢復(fù)方式都要快先嬉。
③服務(wù)器的硬盤(pán)都是T級(jí)別的轧苫,幾個(gè)G的數(shù)據(jù)影響忽略不計(jì)楚堤。
Redis 不同于 Memcached 的很重要一點(diǎn)就是疫蔓,Redis 支持持久化,而且支持三種不同的持久化策略身冬。
1.RDB
Redis提供了兩個(gè)命令來(lái)生成 RDB 文件:
- save:在主進(jìn)程中執(zhí)行衅胀,會(huì)導(dǎo)致寫(xiě)請(qǐng)求阻塞。
- bgsave:fork一個(gè)子進(jìn)程酥筝,專(zhuān)門(mén)用于寫(xiě)入 RDB 文件滚躯,避免了主進(jìn)程的阻塞。
為了快照而阻塞寫(xiě)請(qǐng)求嘿歌,這是系統(tǒng)無(wú)法接受的掸掏,因此Redis借助操作系統(tǒng)提供的寫(xiě)時(shí)復(fù)制技術(shù)(Copy-On-Write, COW),在執(zhí)行快照的同時(shí)宙帝,正常處理寫(xiě)操作丧凤。
Redis在執(zhí)行持久化時(shí),會(huì)fork出一個(gè)bgsave子進(jìn)程步脓,這個(gè)子進(jìn)程可以共享主進(jìn)程的所有內(nèi)存數(shù)據(jù)愿待,bgsave子進(jìn)程運(yùn)行后,會(huì)去讀取主進(jìn)程的內(nèi)存數(shù)據(jù)靴患,并把它們寫(xiě)入RDB文件仍侥。
有小伙伴問(wèn),為什么要fork一個(gè)子線程鸳君?
redis是單線程程序农渊,若單線程同時(shí)在服務(wù)線上的請(qǐng)求還需要進(jìn)行文件IO操作,這不僅影響性能而且還會(huì)阻塞線上業(yè)務(wù)或颊,因此這里主進(jìn)程fork出一個(gè)進(jìn)程砸紊,fork出的這個(gè)進(jìn)程去完成快照操作。
快照持久化是 Redis 默認(rèn)采用的持久化方式饭宾,我們可以根據(jù)業(yè)務(wù)需求配置下面參數(shù):
save 900 1 #每900秒(15分鐘)至少有1個(gè)key發(fā)生變化批糟,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
save 300 10 #每300秒(5分鐘)至少有10個(gè)key發(fā)生變化看铆,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照徽鼎。
save 60 10000 #每60秒(1分鐘)至少有10000個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
key發(fā)生變化(key數(shù)據(jù)添加否淤、修改悄但、刪除)
觸發(fā)快照的幾種方式:
①服務(wù)器正常關(guān)閉時(shí),會(huì)照一次快照 ./bin/redis-cli shutdown
②key滿(mǎn)足一定條件石抡,會(huì)照一次快照(通過(guò)上述Redis.conf配置)
③通過(guò)BGSAVE命令(在redis中執(zhí)行)手動(dòng)觸發(fā)RDB快照保存
優(yōu)點(diǎn):
①RDB文件緊湊檐嚣,體積小,網(wǎng)絡(luò)傳輸快啰扛,適合全量復(fù)制嚎京。
②與AOF方式相比,通過(guò)RDB文件恢復(fù)數(shù)據(jù)比較快更快隐解。
③RDB最大化了Redis的性能鞍帝,因?yàn)镽edis父進(jìn)程持久化時(shí)只需要fork一個(gè)子進(jìn)程,這個(gè)子進(jìn)程可以共享主進(jìn)程的所有內(nèi)存數(shù)據(jù)煞茫,子進(jìn)程會(huì)去讀取主進(jìn)程的內(nèi)存數(shù)據(jù)帕涌,并把它們寫(xiě)入RDB文件。
缺點(diǎn):
①快照是定期生成的续徽,所有在 Redis 故障時(shí)或多或少會(huì)丟失一部分?jǐn)?shù)據(jù)蚓曼。
②當(dāng)數(shù)據(jù)量比較大時(shí),fork 的過(guò)程是非常耗時(shí)的钦扭,fork 子進(jìn)程時(shí)是會(huì)阻塞的纫版,在這期間 Redis 是不能響應(yīng)客戶(hù)端的請(qǐng)求的。
2.AOF
Redis會(huì)把每一個(gè)寫(xiě)請(qǐng)求都記錄在一個(gè)日志文件里土全,在Redis重啟時(shí)捎琐,會(huì)把AOF文件中記錄的所有寫(xiě)操作順序執(zhí)行一遍,確保數(shù)據(jù)恢復(fù)到最新裹匙。
Redis 會(huì)在收到客戶(hù)端修改指令后瑞凑,先進(jìn)行參數(shù)校驗(yàn),如果沒(méi)問(wèn)題概页,就立即將該指令文本存儲(chǔ)到 AOF 日志中籽御,也就是先存到磁盤(pán),然后再執(zhí)行指令惰匙。這樣即使遇到突發(fā)宕機(jī)技掏,已經(jīng)存儲(chǔ)到 AOF 日志的指令進(jìn)行重放一下就可以恢復(fù)到宕機(jī)前的狀態(tài)。
日志文件太大怎么辦项鬼?
AOF 日志在長(zhǎng)期的運(yùn)行過(guò)程中會(huì)變的很大哑梳,Redis重啟時(shí)需要加載 AOF 日志進(jìn)行指令重放,此時(shí)這個(gè)過(guò)程就會(huì)非常耗時(shí)绘盟。 所以需要定期進(jìn)行AOF 重寫(xiě)鸠真,給 AOF 日志進(jìn)行瘦身悯仙。
AOF如何重寫(xiě)?
Redis 提供了 bgrewriteaof 指令用于對(duì) AOF 日志進(jìn)行瘦身吠卷。每次執(zhí)行重寫(xiě)時(shí)锡垄,主進(jìn)程 fork 出一個(gè)bgrewriteaof 子進(jìn)程,會(huì)把主進(jìn)程的內(nèi)存拷貝一份給 bgrewriteaof 子進(jìn)程祭隔,對(duì)內(nèi)存進(jìn)行遍歷轉(zhuǎn)換成一系列 Redis 的操作指令货岭,序列化到一個(gè)新的 AOF 日志文件中。序列化完畢后再將操作期間發(fā)生的增量 AOF 日志追加到這個(gè)新的 AOF 日志文件中疾渴,追加完畢后就立即替代舊的 AOF 日志文件了千贯,瘦身工作就完成了。
Redis提供了AOF rewrite功能程奠,可以重寫(xiě)AOF文件丈牢,只保留能夠把數(shù)據(jù)恢復(fù)到最新?tīng)顟B(tài)的最小寫(xiě)操作集。
AOF 重寫(xiě)可以通過(guò)bgrewriteaof命令(在redis里執(zhí)行)觸發(fā)瞄沙,也可以配置Redis定期自動(dòng)進(jìn)行:
## Redis在每次AOF rewrite時(shí),會(huì)記錄完成rewrite后的AOF日志大小慌核,當(dāng)AOF日志大小在該基礎(chǔ)上增長(zhǎng)了100%后距境,自動(dòng)進(jìn)行AOF rewrite。同時(shí)如果增長(zhǎng)的大小沒(méi)有達(dá)到64mb垮卓,則不會(huì)進(jìn)行rewrite垫桂。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
AOF默認(rèn)是關(guān)閉的,如果需要開(kāi)啟粟按,需要在redis.conf配置文件中配置:
appendonly yes
AOF提供三種fsync配置诬滩,always/everysec/no,通過(guò)配置項(xiàng)appendfsync指定灭将,默認(rèn)是everysec疼鸟。
appendfsync always # 每寫(xiě)入一條日志就進(jìn)行一次fsync操作,數(shù)據(jù)安全性最高庙曙,但速度最慢(每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫(xiě)入AOF文)
appendfsync everysec # 折中的做法空镜,交由后臺(tái)線程每秒fsync一次(每秒鐘同步一次,該策略為AOF的缺省策略)
appendfsync no # 不進(jìn)行fsync捌朴,將flush文件的時(shí)機(jī)交給OS決定吴攒,速度最快(從不同步。高效但是數(shù)據(jù)不會(huì)被持久化)
優(yōu)點(diǎn):
①數(shù)據(jù)安全性高砂蔽,可以根據(jù)業(yè)務(wù)需求配置fsync策略
②AOF文件易讀洼怔,可修改,在進(jìn)行了某些錯(cuò)誤的數(shù)據(jù)清除操作后左驾,只要AOF文件沒(méi)有rewrite镣隶,就可以把AOF文件備份出來(lái)泽台,把錯(cuò)誤命令刪除,然后恢復(fù)數(shù)據(jù)
缺點(diǎn):
①AOF方式生成的日志文件太大矾缓,即使通過(guò)AFO重寫(xiě)怀酷,文件體積仍然很大
②數(shù)據(jù)恢復(fù)速度比RDB慢
3.混合持久化
如果我們采用 RDB 持久化會(huì)丟失一段時(shí)間數(shù)據(jù)。如果我們采用 AOF 持久化嗜闻,AOF日志較大蜕依,重放比較慢。
Redis 4.0 為了解決這個(gè)問(wèn)題琉雳,支持混合持久化样眠。將 RDB 文件的內(nèi)容和增量的 AOF 日志文件存在一起。
混合持久化同樣也是通過(guò) bgrewriteaof 完成的翠肘,不同的是當(dāng)開(kāi)啟混合持久化時(shí)檐束,fork出的子進(jìn)程先將共享的內(nèi)存副本全量的以 RDB 方式寫(xiě)入 AOF 文件,然后在將重寫(xiě)緩沖區(qū)的增量命令以 AOF 方式寫(xiě)入到文件束倍,寫(xiě)入完成后通知主進(jìn)程更新統(tǒng)計(jì)信息被丧,并將新的含有RDB格式和 AOF 格式的 AOF 文件替換舊的的 AOF 文件。簡(jiǎn)單的說(shuō):新的AOF文件前半段是RDB格式的全量數(shù)據(jù)后半段是AOF格式的增量數(shù)據(jù)绪妹。
于是在 Redis 重啟的時(shí)候甥桂,可以先加載 rdb 的內(nèi)容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放邮旷,重啟效率因此大幅得到提升黄选。
4.實(shí)戰(zhàn)經(jīng)驗(yàn)
快照需要fork子進(jìn)程的方式進(jìn)行的,它是一個(gè)比較耗資源的操作婶肩。(當(dāng)數(shù)據(jù)量非常大時(shí)办陷,fork會(huì)很耗時(shí),需要大概幾百毫秒甚至1秒律歼,fork時(shí)父進(jìn)程是阻塞的民镜,不能正常服務(wù)redis讀寫(xiě)請(qǐng)求)
AOF 的 fsync 是一個(gè)耗時(shí)的 IO 操作,它會(huì)降低 Redis 性能苗膝,同時(shí)也會(huì)增加系統(tǒng) IO 負(fù)擔(dān)
所以通常 Redis 的主節(jié)點(diǎn)是不會(huì)進(jìn)行持久化操作殃恒,持久化操作主要在從節(jié)點(diǎn)進(jìn)行。從節(jié)點(diǎn)是備份節(jié)點(diǎn)辱揭,沒(méi)有來(lái)自客戶(hù)端請(qǐng)求的壓力离唐,它的操作系統(tǒng)資源往往比較充沛。
但是如果出現(xiàn)網(wǎng)絡(luò)分區(qū)问窃,從節(jié)點(diǎn)長(zhǎng)期連不上主節(jié)點(diǎn)亥鬓,就會(huì)出現(xiàn)數(shù)據(jù)不一致的問(wèn)題,特別是在網(wǎng)絡(luò)分區(qū)出現(xiàn)的情況下又不小心主節(jié)點(diǎn)宕機(jī)了域庇,那么數(shù)據(jù)就會(huì)丟失嵌戈,所以在生產(chǎn)環(huán)境要做好實(shí)時(shí)監(jiān)控工作覆积,保證網(wǎng)絡(luò)暢通或者能快速修復(fù)。另外還應(yīng)該再增加一個(gè)從節(jié)點(diǎn)以降低網(wǎng)絡(luò)分區(qū)的概率熟呛,只要有一個(gè)從節(jié)點(diǎn)數(shù)據(jù)同步正常宽档,數(shù)據(jù)也就不會(huì)輕易丟失。