redis是內(nèi)存數(shù)據(jù)庫,所以發(fā)生宕機(jī)后妖碉,數(shù)據(jù)會消失猴仑,所以數(shù)據(jù)的持久化至關(guān)重要审轮,接下來我們看一下redis關(guān)于持久化是如何設(shè)計(jì)的肥哎。
AOF
關(guān)于日志辽俗,我們在學(xué)習(xí)mysql或者zk的時候,都知道WAL日志模式篡诽,AOF與之相反崖飘,AOF是先將數(shù)據(jù)寫入內(nèi)存再記錄日志,
我們先了解一下AOF具體記錄了什么杈女,舉個例子朱浴,比如我們執(zhí)行一條命令:set hello world,AOF日志具體是這樣記錄的:
*3? ?$3? set? $5? hello? $5 world达椰,*3表示命令有三個部分 翰蠢,$3 表示命令內(nèi)容有3個字節(jié)
redis在記錄這些命令時,并不會進(jìn)行語法檢查啰劲,所以先讓系統(tǒng)執(zhí)行梁沧,執(zhí)行成功了也代表語法沒有問題,而且也不會阻塞
當(dāng)前的寫操作蝇裤,然后配合 always廷支、everysec、no三種回寫策略進(jìn)行回寫記錄日志栓辜。
always是每次命令執(zhí)行完緊接著進(jìn)行日志記錄恋拍,不可避免的會影響主線程的性能。
everysec是把日志寫到緩沖區(qū)并還未執(zhí)行落盤操作便返回藕甩,每隔一秒有系統(tǒng)執(zhí)行落盤動作施敢,所以這里存在數(shù)據(jù)丟失的風(fēng)險,
可以看出everysec是redis在性能與數(shù)據(jù)可靠性之間做的權(quán)衡取了個折中狭莱。
no策略是命令執(zhí)行完把日志記錄到緩沖區(qū)便返回僵娃,由操作系統(tǒng)控制落盤時機(jī),這樣宕機(jī)時數(shù)據(jù)丟失會比較嚴(yán)重 贩毕,
我們根據(jù)具體業(yè)務(wù)場景選擇合適的回寫策略
AOF重寫
因?yàn)橐粋€鍵值對可能會被反復(fù)改動悯许,每改動一次,AOF就得增加一次上述的日志記錄辉阶,那么整個日志文件會越來越大先壕,
所以redis采取AOF重寫機(jī)制避免這種情況瘩扼,AOF重寫是這樣實(shí)現(xiàn)的,對數(shù)據(jù)庫中的所有鍵值對垃僚,比如我們之前set進(jìn)去的hello world集绰,
日志記錄為 set hello world,意思就是說不管你之前改動過多少次谆棺,我只記錄當(dāng)前的情況栽燕,這樣舊日志的多條記錄,在新日志里面
舊變成了1條記錄改淑,多變一碍岔,日志文件自然小了很多,還有一點(diǎn)不同的是朵夏,AOF的重寫是由主進(jìn)程程fork出來的一個bgrewriteaaof子進(jìn)程
執(zhí)行的蔼啦,所以不會影響主進(jìn)程的性能。
當(dāng)AOF重寫時仰猖,如果數(shù)據(jù)發(fā)生變動呢捏肢?機(jī)制是:會將變動的記錄寫在AOF重寫緩沖區(qū),這樣等重寫完再來根據(jù)緩沖區(qū)的記錄繼續(xù)寫進(jìn)饥侵,這樣
便可以使用新的AOF日志代替舊的AOF日志鸵赫。
接下來著重描述一下一些風(fēng)險點(diǎn),就是主進(jìn)程在fork重寫子進(jìn)程的時候躏升,子進(jìn)程會拷貝父進(jìn)程的頁表辩棒,就是內(nèi)存的虛實(shí)映射,并不會真的去
拷貝實(shí)際的物理內(nèi)存煮甥。需要注意的是fork這個bgrewriteaaof子進(jìn)程時盗温,內(nèi)核需要創(chuàng)建管理子進(jìn)程的數(shù)據(jù)結(jié)構(gòu),稱做PCB成肘,
process control block進(jìn)程控制塊卖局,這個過程是阻塞主進(jìn)程的,而且如果redis實(shí)例的內(nèi)存越大双霍,那么我們上面提過的頁表也會越大砚偶,
那么fork時間就越長,就存在阻塞主進(jìn)程的風(fēng)險洒闸,其次就是我們剛剛提過的在AOF重寫時染坯,數(shù)據(jù)的變動會寫時復(fù)制,就是會申請一塊緩沖區(qū)
以記錄改動的數(shù)據(jù)丘逸,這就會造成寫放大单鹿,因?yàn)楦高M(jìn)程需要讀取內(nèi)存把這份數(shù)據(jù)再寫入緩沖區(qū)。假如我們當(dāng)時寫入的數(shù)據(jù)是bigkey深纲,那么主進(jìn)程也會因?yàn)橐暾埓蟮膬?nèi)存空間而發(fā)生阻塞仲锄。
RDB
RDB是redis內(nèi)存數(shù)據(jù)的全量快照劲妙,相較于AOF而言,RDB更小而且是二進(jìn)制文件儒喊,AOF記錄的是操作記錄镣奋,RDB記錄的是照快照這一
時刻確定性的數(shù)據(jù),同樣的RDB也存在在照快照的時候怀愧,redis實(shí)例還是需要正常接收寫操作的侨颈,那么就會發(fā)生數(shù)據(jù)的更改,
同樣的也是利用COW寫時復(fù)制機(jī)制芯义,從而保證數(shù)據(jù)的正確性哈垢。
快照我們總不能頻率很高的一直照,總是需要時間間隔毕贼,那么當(dāng)間隔時如果發(fā)生宕機(jī)温赔,那么數(shù)據(jù)就會丟失蛤奢,那么這段期間我們可以利用AOF
記錄日志鬼癣,等下一次快照照完,那么就可以清空這段間隔時間記錄的AOF啤贩,同時也保證了數(shù)據(jù)的可靠性待秃。
接下來也描述一下一些關(guān)于RDB的風(fēng)險點(diǎn),假如我們的業(yè)務(wù)場景是寫多讀少的場景痹屹,假設(shè)讀寫
比4:1章郁,那么在rdb持久化的過程中,會有大量的寫操作志衍,達(dá)到80%暖庄,假設(shè)我們的內(nèi)存是4G,
已經(jīng)寫了2個G楼肪,那么4:1的讀寫比培廓,導(dǎo)致rdb持久化過程中,cow需要申請的空間為1.6g春叫,
導(dǎo)致整個實(shí)例內(nèi)存幾乎吃滿肩钠,然后再加上這時發(fā)生大量的請求進(jìn)來,那么redis實(shí)例將面臨OOM
風(fēng)險暂殖,甚至大概率被kill掉价匠。假如云主機(jī)開啟swap,就會有一部分?jǐn)?shù)據(jù)換到磁盤上呛每,那么訪問
磁盤效率明顯降低踩窖,性能下降嚴(yán)重