眾所周知衫嵌,redis是一種內(nèi)存數(shù)據(jù)庫浸锨,在服務(wù)重啟的時候內(nèi)存中的數(shù)據(jù)會全部丟失百侧,既然redis作為nosql的佼佼者,那肯定有自己的一套持久化方案來在宕機之后恢復(fù)自己的數(shù)據(jù)谴供,那我們就來分析一波redis的持久化機制块茁。
目前redis有兩種持久化機制,第一種是RDB快照憔鬼,這種方式直接把某個時間點的內(nèi)存全量快照copy一份持久化到硬盤上龟劲,等服務(wù)重啟后用來恢復(fù)的話不需要執(zhí)行太多的命令就能把快照重寫回內(nèi)存;第二種是AOF日志轴或,服務(wù)端每接收到一次寫入命令昌跌,就會在執(zhí)行完之后append到前一個日志后面,這樣在磁盤上就會生成有序的指令隊列照雁,服務(wù)重啟后蚕愤,按序重新執(zhí)行命令即可。
RDB快照
在滿足RDB觸發(fā)條件時(或者bgsave命令)饺蚊,redis會fork出一個子進(jìn)程萍诱,由子進(jìn)程全權(quán)負(fù)責(zé)內(nèi)存快照的持久化工作。這個子進(jìn)程和主進(jìn)程共享一塊代碼段和數(shù)據(jù)段污呼,當(dāng)fork出子進(jìn)程的時候裕坊,這塊數(shù)據(jù)區(qū)域就幾乎不會發(fā)生變化,隨后子進(jìn)程開始遍歷數(shù)據(jù)并寫入磁盤燕酷。
那這個時候籍凝,有新的寫請求進(jìn)來怎么辦?
有學(xué)過java的小伙伴之前或多或少的接觸過CopyOnWriteArrayList苗缩,之前將Hash數(shù)據(jù)結(jié)構(gòu)那篇也講過饵蒂,都是利用CopyOnWrite機制來處理寫請求的。首先redis將當(dāng)前區(qū)域分成小塊酱讶,如下:
當(dāng)某一個page發(fā)現(xiàn)有寫請求進(jìn)來時退盯,會把此page復(fù)制一份,在新的區(qū)域進(jìn)行寫操作泻肯,這也是redis在存儲RDB時內(nèi)存飆高的主要原因之一渊迁,不過redis中冷數(shù)據(jù)還是占絕大部分,所以page頁復(fù)制的一般也不會很多灶挟。
AOF日志
Redis在有寫命令進(jìn)來時宫纬,會先進(jìn)性合法性校驗之后再執(zhí)行,最后會把指令寫入磁盤拼接到最近一條aof日志后面膏萧,恢復(fù)的時候順序執(zhí)行命令即可恢復(fù)漓骚。不過指令也并不是直接寫入到磁盤當(dāng)中的蝌衔,磁盤頁在內(nèi)存有一個對應(yīng)的緩存,aof日志是先寫到這個緩存蝌蹂,再將緩存刷到磁盤當(dāng)中噩斟,假如在刷到磁盤之前宕機,這個部分未寫入磁盤的aof日志將會丟失孤个。
Linux 的 fsync函數(shù) 可以強制將內(nèi)核緩存刷到磁盤剃允。Redis提供了3種 appendfsync 配置:
- always,每執(zhí)行一條指令就fsync一次齐鲤,這樣完全放棄了redis的高性能換取持久性斥废,一般沒人這么玩。
- no给郊,永不主動fsync牡肉,具體fsync操作交給操作系統(tǒng),這樣搞不是特別安全淆九。
- everysec统锤,定時fsync,一個折中方案炭庙,最好使用這種饲窿。
當(dāng)aof日志越來越大的時候,主進(jìn)程還會fork一個子進(jìn)程對aof日志進(jìn)行瘦身焕蹄,就是將指令合并和重寫逾雄,丟掉已經(jīng)沒有作用的指令,瘦身完成后腻脏,會拼接在瘦身的這段時間內(nèi)新增的aof日志鸦泳,替換掉老的的aof指令。
總結(jié)
也許迹卢,目前為止辽故,你可能多多少少的對為什么會存在兩種持久化機制有些想法了徒仓,這兩種的持久化方式區(qū)別也是很明顯的腐碱,存儲速度方面,RDB快照是復(fù)制內(nèi)存而AOF則是一點點拼接指令日志掉弛,相對而言肯定是“少取多拿”的AOF快一點症见;恢復(fù)速度方面,對于大數(shù)據(jù)集殃饿,粗略來講RDB只需要做一次反序列化就可以了谋作,而AOF則還需要執(zhí)行一遍所有制令,那RDB恢復(fù)是要快一點乎芳;數(shù)據(jù)丟失方面遵蚜,因為RDB是復(fù)制的整個內(nèi)存信息帖池,所以執(zhí)行的肯定不會太頻繁,一般會設(shè)定在一定時間范圍key的修改次數(shù)達(dá)到一定數(shù)量才會觸發(fā)吭净,因此在下一次RDB之前不幸宕機睡汹,那 這段事件內(nèi)的數(shù)據(jù)則會丟失,AOF因為每次拼接一小部分日志寂殉,速度很快囚巴,如果在redis命令執(zhí)行完后到寫入aof日志到磁盤這段時間內(nèi)宕機,這只會丟失這一小部分?jǐn)?shù)據(jù)友扰,這兩種方式都不能完全保證不丟失數(shù)據(jù)(fsync是以性能為代價強刷到磁盤彤叉,暫不討論),一般在數(shù)據(jù)恢復(fù)的時候混合使用兩種方式村怪,RDB用來恢復(fù)較老的數(shù)據(jù)秽浇,AOF用來恢復(fù)剩下的剛剛修改過的數(shù)據(jù)。