深入探索Redis持久化原理
Redis是一個(gè)內(nèi)存數(shù)據(jù)庫(kù),為了保證數(shù)據(jù)的持久化,redis提供了兩種持久化方式RDB和AOF,下面我們就分別來(lái)看下這兩種持久化方式的實(shí)現(xiàn)原理。
RDB(默認(rèn))
RDB是通過(guò)快照方式完成的,當(dāng)滿足一定條件時(shí),redis會(huì)自動(dòng)將內(nèi)存中的數(shù)據(jù)持久化到磁盤。
觸發(fā)快照的時(shí)機(jī)
- 符合自定義配置的快照規(guī)則。(在redis.conf中配置,下面會(huì)詳細(xì)介紹)
- 執(zhí)行save或者bgsave命令
- 執(zhí)行flushall命令
- 執(zhí)行主從復(fù)制操作(第一次)
原理圖

- 在快照進(jìn)行的過(guò)程中,也就是生成文件的過(guò)程中,不會(huì)對(duì)原有的rdb文件進(jìn)行修改,直到快照生成完畢,直接將老的替換成新的,保證rdb文件任何時(shí)刻都是完整的。
- 我們可以通過(guò)定時(shí)備份rdb文件來(lái)實(shí)現(xiàn)redis數(shù)據(jù)的備份,rdb是壓縮的二進(jìn)制文件,占用空間小,有利于傳輸
###快照設(shè)置規(guī)則 save {多少秒內(nèi)} {數(shù)據(jù)變化了多少}
例如:save 100 1:在100秒內(nèi),至少有一個(gè)鍵被修改就進(jìn)行快照;save 200 4:在200秒內(nèi),至少4個(gè)鍵被修改就進(jìn)行快照。
RDB的優(yōu)缺點(diǎn)
- 缺點(diǎn):使用RDB進(jìn)行持久化,在redis突然異常退出的時(shí)候,會(huì)丟失最后一次快照之后的數(shù)據(jù)。但是,可以根據(jù)組合設(shè)置自動(dòng)快照的方式,降低數(shù)據(jù)損失,確保在接受范圍內(nèi)。如果數(shù)據(jù)較為重要,可以使用AOF方式
- 優(yōu)點(diǎn):使用RDB方式可以最大化redis性能,在快照過(guò)程中,我們可以看到主進(jìn)程只需要fork出一個(gè)子進(jìn)程即可,剩下的工作全部由子進(jìn)程完成,父進(jìn)程無(wú)需進(jìn)行任何的磁盤I/O操作。但是,如果數(shù)據(jù)集較大,在fork子進(jìn)程的時(shí)候比較耗時(shí),會(huì)導(dǎo)致redis在一段時(shí)間內(nèi)停止處理請(qǐng)求。
AOF方式
默認(rèn)情況下,redis是沒(méi)有開(kāi)啟AOF(append only file)的。在開(kāi)始AOF之后,redis每接收到一條更改redis數(shù)據(jù)的命令,就會(huì)將該命令寫(xiě)入硬盤中的AOF文件。很明顯,該過(guò)程會(huì)降低redis的性能,但大部分情況下是能夠接受的,同時(shí),使用性能較好的硬盤可以提高AOF性能
AOF配置方式
# 開(kāi)啟appendonly參數(shù)appendonly true# 設(shè)置AOF文件位置dir ./# 設(shè)置AOF文件名稱,默認(rèn)是appendonly.aofappendfilename appendonly.aof
原理圖

RESP協(xié)議
Redis客戶端使用RESP協(xié)議與Redis服務(wù)端進(jìn)行通信,該協(xié)議是專門為redis設(shè)計(jì)的,但是也可以用于其他C-S項(xiàng)目。
- 間隔符號(hào):在linux中是\r\n,在windows中是\n
- 簡(jiǎn)單字符串以'+'開(kāi)頭
- 錯(cuò)誤Errors,以'-'開(kāi)頭
- 整數(shù)類型Integer,以':'開(kāi)頭
- 大字符串以'$'開(kāi)頭
- 數(shù)組類型Arrays,以'*'開(kāi)頭
AOF原理說(shuō)明
redis通過(guò)將所有的寫(xiě)入命令記錄到AOF文件中,來(lái)持久化數(shù)據(jù)。而將命令記錄到AOF文件的過(guò)程,可以分成三個(gè)階段:
- 命令傳播
- 緩存追加
- 文件寫(xiě)入和保存
命令傳播
redis將執(zhí)行完的命令,命令參數(shù),命令參數(shù)格個(gè)數(shù)等內(nèi)容發(fā)送到AOF程序。當(dāng)redis客戶端執(zhí)行命令的時(shí)候,通過(guò)連接,將協(xié)議文本發(fā)送到redis,redis接收到協(xié)議文本之后,根據(jù)內(nèi)容,選擇適當(dāng)?shù)拿詈瘮?shù),將協(xié)議文本轉(zhuǎn)換成Redis字符串對(duì)象,在命令函數(shù)執(zhí)行完成后,將命令參數(shù)發(fā)送到AOF程序。
緩存追加
AOF程序接收到命令參數(shù)之后,會(huì)將其從字符串對(duì)象轉(zhuǎn)換成協(xié)議內(nèi)容,再將協(xié)議內(nèi)容追加到AOF緩存中。AOF緩存是在redisServer結(jié)構(gòu)的aof_buf中,新的內(nèi)容會(huì)被追加到aof_buf末尾。aof_buf保持著所有未被寫(xiě)入到AOF文件的協(xié)議文本。
文件寫(xiě)入和保存
將AOF緩存內(nèi)容寫(xiě)入到AOF文件,并保持到磁盤。 當(dāng)服務(wù)器的常規(guī)函數(shù)被執(zhí)行,或者事件處理器被執(zhí)行的時(shí)候,flushAppendOnlyFile函數(shù)將會(huì)被執(zhí)行。會(huì)有以下兩個(gè)過(guò)程。
- WRITE:將AOF緩存中的內(nèi)容寫(xiě)入到AOF文件
- SAVE:調(diào)用fsync或者fdatasync函數(shù),將AOF文件保存到磁盤中
AOF一共有三種保存模式
- AOF_FSYNC_NO:不保存。在這種模式下,每次調(diào)用flushAppendOnlyFile函數(shù),write會(huì)被執(zhí)行,而save會(huì)被忽略。而save只有在以下三種條件下會(huì)觸發(fā),redis關(guān)閉,aof功能關(guān)閉,系統(tǒng)的寫(xiě)緩存被刷新(可能是緩存滿了,或者定期執(zhí)行保持操作)。這三種情況下執(zhí)行save操作會(huì)引起redis主線程的阻塞。
- AOF_FSYNC_EVERYSEC(默認(rèn)):每秒保存一次。save每秒被執(zhí)行一次,但是save由后臺(tái)子線程完成,不會(huì)導(dǎo)致redis主線程阻塞。
- AOF_FSYNC_ALWAYS:每執(zhí)行一個(gè)命令保存一次。這種情況下,每執(zhí)行一個(gè)命令write和save都會(huì)被執(zhí)行,而且save操作由主線程完成,會(huì)導(dǎo)致redis的阻塞。安全性較高,性能較差,因此不推薦使用。
AOF的文件優(yōu)化
Redis可以在AOF文件過(guò)大的時(shí)候,在后臺(tái)(子進(jìn)程)對(duì)AOF文件進(jìn)行重寫(xiě)。重寫(xiě)之后的新文件,包含恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合。重寫(xiě),并不會(huì)對(duì)AOF文件進(jìn)行讀取和寫(xiě)入,針對(duì)的是數(shù)據(jù)庫(kù)中的當(dāng)前鍵。
優(yōu)化前set s1 1set s1 2set s1 3優(yōu)化后set s1 3
AOF文件優(yōu)化原理
AOF的重寫(xiě)是通過(guò)子進(jìn)程實(shí)現(xiàn)的,因此,主線程是繼續(xù)工作的,有可能對(duì)新的數(shù)據(jù)進(jìn)行修改,有可能會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的數(shù)據(jù)和重寫(xiě)之后的數(shù)據(jù)不一致。redis通過(guò)增加一個(gè)AOF重寫(xiě)緩存來(lái)解決這個(gè)問(wèn)題,當(dāng)fork出子進(jìn)程之后,新的命令不僅會(huì)追加到現(xiàn)有的AOF文件中,還會(huì)添加一份數(shù)據(jù)到這個(gè)緩存當(dāng)中。

重寫(xiě)過(guò)程分析(需要保證從寫(xiě)的操作是絕對(duì)安全的)
Redis創(chuàng)建新的AOF文件之后,會(huì)繼續(xù)將命令添加到原有的AOF文件中,即使數(shù)據(jù)庫(kù)突然宕機(jī)了,原有的AOF文件和文件內(nèi)容也不會(huì)有損失。而當(dāng)新的AOF文件創(chuàng)建完畢之后,會(huì)直接把舊的替換掉,往新的AOF文件中添加命令。
當(dāng)子進(jìn)程在進(jìn)行重寫(xiě)時(shí),主進(jìn)程會(huì)完成下列工作
- 處理請(qǐng)求,將新的命令繼續(xù)添加到AOF文件中,同時(shí)將命令添加到AOF重寫(xiě)緩存中。保證數(shù)據(jù)的一致行,避免出現(xiàn)數(shù)據(jù)丟失。
- 當(dāng)子進(jìn)程重寫(xiě)完畢之后會(huì)向主進(jìn)程發(fā)送一個(gè)完成信號(hào),這時(shí)主進(jìn)程會(huì)把重寫(xiě)緩存中的內(nèi)容添加到新的AOF文件中,這樣新的AOF文件,數(shù)據(jù)庫(kù),舊的AOF文件的內(nèi)容就完全一致了。然后對(duì)新的AOF文件改名,覆蓋原有的AOF文件。
這樣程序就完成了新舊AOF文件的替換工作。而當(dāng)處理完成之后,主進(jìn)程就會(huì)繼續(xù)接受請(qǐng)求。整個(gè)重寫(xiě)過(guò)程中只有最后的緩存寫(xiě)入和改名替換的操作會(huì)導(dǎo)致主進(jìn)程阻塞,其他時(shí)候不會(huì)影響redis的正常工作,把AOF重寫(xiě)對(duì)redis的性能影響降到最低。
優(yōu)化觸發(fā)條件
#當(dāng)前的AOF文件超過(guò)上次重寫(xiě)時(shí)AOF文件大小百分幾的時(shí)候進(jìn)行重寫(xiě),如果沒(méi)有重寫(xiě)過(guò),則以啟動(dòng)時(shí)AOF文件的大小為準(zhǔn)auto-aof-rewrite-percentage 100#限制允許重寫(xiě)的最小的AOF文件,也就是文件小于這個(gè)值的時(shí)候不需要進(jìn)行重寫(xiě)優(yōu)化auto-aof-rewrite-min-size 64mb