相對(duì)來(lái)說(shuō)RDB這種持久化模式更加適合較多的場(chǎng)景
Redis支持RDB和AOF兩種持久化機(jī)制,持久化功能有效地避免因進(jìn)程退出造成的數(shù)據(jù)丟失問題矾策,當(dāng)下次重啟時(shí)利用之前持久化文件即可實(shí)現(xiàn)數(shù)據(jù)恢復(fù)宛乃。
1. RDB是什么
RDB持久化是把當(dāng)前進(jìn)程數(shù)據(jù)生成快照保存到硬盤的過(guò)程悠咱,觸發(fā)RDB持久化過(guò)程分為**手動(dòng)觸發(fā)**和**自動(dòng)觸發(fā)**。
1.1.1 觸發(fā)機(jī)制
手動(dòng)觸發(fā)分別對(duì)應(yīng)save和bgsave命令:
save命令:阻塞當(dāng)前Redis服務(wù)器征炼,知道RDB過(guò)程完成為止析既,對(duì)于內(nèi)存比較大的實(shí)例會(huì)造成長(zhǎng)時(shí)間阻塞,先上環(huán)境不建議使用柒室。運(yùn)行save命令對(duì)應(yīng)Redis日志如下:
DB saved on disk
bgsave命令:Redis進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程渡贾,RDB持久化過(guò)程由子進(jìn)程負(fù)責(zé),完成后自動(dòng)結(jié)束雄右。阻塞只發(fā)生在fork階段空骚,一段時(shí)間很短。運(yùn)行bgsave名字對(duì)應(yīng)的Redis日志如下:
Background saving started by pid 3152
DB saved on disk
RDB: 0MB of memory userd by copy-on-write
Background saving terminated with success
bgsave命令是針對(duì)save阻塞問題做的優(yōu)化擂仍。因此Redis內(nèi)部所有涉及到RDB操作都采用bgsave的方式囤屹,而save命令可以廢棄。
Redis內(nèi)部還存在自動(dòng)觸發(fā)RDB的持久化機(jī)制逢渔,例如一下場(chǎng)景:
1) 使用save相關(guān)配置肋坚,如‘save m n’表示m秒之內(nèi)數(shù)據(jù)集存在n次修改時(shí),自動(dòng)觸發(fā)bgsave。
2)如果從節(jié)點(diǎn)執(zhí)行全量復(fù)制操作智厌,主節(jié)點(diǎn)自動(dòng)執(zhí)行bgsave生成RDB文件并發(fā)送給從節(jié)點(diǎn)诲泌。
3)執(zhí)行debug reload命令重新加載Redis時(shí),也會(huì)自動(dòng)觸發(fā)save操作铣鹏。
4)默認(rèn)情況下執(zhí)行shutdown命令時(shí)敷扫,如果沒有開啟AOF持久化功能則自動(dòng)執(zhí)行bgsave。
1.1.2 bgsave流程說(shuō)明
bgsave是主流的觸發(fā)RDB持久化方式诚卸,下圖是運(yùn)作流程
執(zhí)行bgsave命令葵第,Redis父進(jìn)程判斷當(dāng)前是否存在正在執(zhí)行的子進(jìn)程,如只RDB/AOF子進(jìn)程合溺,如果存在bgsave命令直接返回卒密。
父進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,fork操作過(guò)程中父進(jìn)程會(huì)阻塞棠赛,通過(guò)info stats命令查看latest_fork_usec選項(xiàng)哮奇,可以獲取最近一個(gè)fork以操作的耗時(shí),單位為微秒睛约。
父進(jìn)程仍fork完成后屏镊,bgsave命令返回“Background saving started”信息并不再阻塞父進(jìn)程,可以繼續(xù)響應(yīng)其他命令痰腮。
子進(jìn)程創(chuàng)建RDB文件,根據(jù)父進(jìn)程內(nèi)存生成臨時(shí)快照文件律罢,完成后對(duì)原有文件進(jìn)行原子替換膀值。執(zhí)行l(wèi)astsave命令可以獲取最后一次生成尺RDB的時(shí)間,對(duì)應(yīng)info統(tǒng)計(jì)的rdb_last_save_time選項(xiàng)误辑。
進(jìn)程發(fā)送信號(hào)給父進(jìn)程衣示完成沧踏,父進(jìn)程更新統(tǒng)計(jì)信息,具體見info Persistence下的rdb_*相關(guān)選項(xiàng)巾钉。
1.1.3 RDB文件處理
保存:RDB文件保存在dir配置指定的目錄下翘狱,文件名通過(guò)dbfilename配置指定∨椴裕可以通過(guò)執(zhí)行config set dir {newDir} 和 config set dbfilename {newFileName}運(yùn)行期動(dòng)態(tài)執(zhí)行潦匈,當(dāng)下次運(yùn)行時(shí)RDB文件會(huì)保存到新目錄。
壓縮:Redis默認(rèn)采用LZF算法對(duì)生成的RDB文件做壓縮處理赚导,壓縮后的文件遠(yuǎn)遠(yuǎn)小于內(nèi)存大小茬缩,默認(rèn)開啟,可以通過(guò)參數(shù)config set rdbcompression {yes|no}動(dòng)態(tài)修改吼旧。
校驗(yàn):如果Redis加載損壞的RDB文件時(shí)拒絕啟動(dòng)凰锡,并打印如下日志:
Short read or OOM loading DB. Unrecoverable error , aborting now.
這時(shí)可以使用Redis提供的redis-check-dump工具檢測(cè)RDB文件并獲取對(duì)應(yīng)的錯(cuò)誤報(bào)告
1.1.4 RDB的優(yōu)缺點(diǎn)
RDB的優(yōu)點(diǎn):
RDB是一個(gè)緊湊壓縮的二進(jìn)制文件,代表Redis在某一個(gè)時(shí)間點(diǎn)上的數(shù)據(jù)快照。非常適合用于備份掂为,全量復(fù)制等場(chǎng)景裕膀。比如每6小時(shí)執(zhí)行bgsave備份,并把RDB文件拷貝到遠(yuǎn)程機(jī)器或者文件系統(tǒng)中(如hdfs)勇哗,用于災(zāi)難恢復(fù)昼扛。
-
Redis加載RDB恢復(fù)數(shù)據(jù)遠(yuǎn)遠(yuǎn)快于AOF方式。
RDB的缺點(diǎn)
RDB方式數(shù)據(jù)沒辦法做到實(shí)時(shí)持久化/秒級(jí)持久化智绸。因?yàn)閎gsave每次運(yùn)行都要執(zhí)行fork操作創(chuàng)建子進(jìn)程野揪,屬于重量級(jí)操作,頻繁執(zhí)行成本過(guò)高瞧栗。
-
RDB文件使用特定二進(jìn)制格式保存斯稳,Redis版本演進(jìn)過(guò)程中有多個(gè)格式的RDB笨笨,存在老版本Redis服務(wù)無(wú)法兼容新版RDB格式的問題迹恐。
針對(duì)RDB不適合實(shí)時(shí)持久化的問題挣惰,Redis提供了AOF持久化方式來(lái)解決
2. AOF是什么
AOF(append only file)持久化:以獨(dú)立日志的方式記錄每次寫命令,重啟時(shí)再重新執(zhí)行AOF文件中命令達(dá)到恢復(fù)數(shù)據(jù)的目的殴边。AOF的主要作用是解決了數(shù)據(jù)持久化的實(shí)時(shí)性憎茂,目前已經(jīng)是Redis持久化的主流方式。
2.1.1 使用AOF
開啟AOF功能需要設(shè)置配置:appendonly yes,默認(rèn)不開啟锤岸。AOF文件通過(guò)appendfilename 配置設(shè)置竖幔,默認(rèn)文件名是appendonly.aof。保存路徑同RDB持久化方式一致是偷。通過(guò)dir配置指定拳氢。AOF的工作流程操作:命令寫入(append)、文件同步(sync)蛋铆、文件重寫(rewrite)馋评、重啟加載(load),工作流程如下:
流程如下:
1) 所有的寫入命令會(huì)追加到aof_buf(緩沖區(qū))中。
2) AOF緩沖區(qū)根據(jù)對(duì)應(yīng)的策略向硬盤做同步操作刺啦。
3) 隨著AOF文件越來(lái)越大留特,需要定期對(duì)AOF文件進(jìn)行重寫,達(dá)到壓縮的目的玛瘸。
4) 當(dāng)Redis服務(wù)重啟時(shí)蜕青,可以加載AOF文件進(jìn)行數(shù)據(jù)恢復(fù)。了解AOF工作流程之后糊渊,下面針對(duì)每個(gè)步驟做詳細(xì)介紹市咆。
2.1.2 命令寫入
AOF命令寫入的內(nèi)容直接是文本協(xié)議格式。例如set hello world 這條命令再来,在AOF緩沖區(qū)會(huì)追加如下文本:
\r\n
5\r\nhello\r\n$5\r\nworld\r\n
介紹關(guān)于AOF的連個(gè)疑惑:
1) AOF為什么直接采用文本協(xié)議格式蒙兰?可能的理由如下:
-
文本協(xié)議具有很好的兼容性磷瘤。
開啟AOF后,所有寫入命令都包含追加操作搜变,直接采用協(xié)議格式采缚,避免二次處理開銷。
文本協(xié)議具有可讀性挠他,方便直接修改和處理扳抽。
2) AOF為什么把命令追加到aof_buf中?Redis使用單線程響應(yīng)命令殖侵,如果每次寫AOF文件命令都直接追加到硬盤贸呢,那么性能完全取決于當(dāng)前硬盤負(fù)載÷>縣寫入緩沖區(qū)aof_buf中楞陷,還有另一個(gè)好處,Redis可以提供多種緩沖區(qū)同步硬盤的策略茉唉,在性能和安全性方面做出平衡固蛾。
2.1.3 文件同步
Redis提供了多種AOF緩沖區(qū)同步文件策略,由參數(shù)appendfsync控制度陆,不同值的含義如表所示
系統(tǒng)調(diào)用writ和fsync說(shuō)明:
write操作會(huì)處罰延遲寫(delayed write)機(jī)制艾凯,Linux在內(nèi)核提供頁(yè)緩沖區(qū)用來(lái)提高硬盤IO性能。write操作在寫入系統(tǒng)緩沖區(qū)后直接返回懂傀。同步硬盤操作依賴于系統(tǒng)調(diào)度機(jī)制趾诗,列如:緩沖區(qū)頁(yè)空間寫滿或達(dá)到特定時(shí)間周期。同步文件之前蹬蚁,如果此時(shí)系統(tǒng)故障宕機(jī)沧竟,緩沖區(qū)內(nèi)數(shù)據(jù)將丟失。
-
fsync針對(duì)單個(gè)文件操作(比如AOF文件)缚忧,做強(qiáng)制硬盤同步,fsync將阻塞知道寫入硬盤完成后返回杈笔,保證了數(shù)據(jù)持久化闪水。
除了write、fsync蒙具、Linx還提供了sync球榆、fdatasync操作,具體API說(shuō)明參見:http://linux.die.net/man/2/write
配置為always時(shí)禁筏,每次寫入都要同步AOF文件持钉,在一般的STAT硬盤上,Redis只能支持大約幾百TPS寫入篱昔,顯然跟Redis高性能特性背道而馳每强,不建議配置始腾。
配置為no,由于操作系統(tǒng)每次同步AOF文件的周期不可控,而且會(huì)極大每次同步硬盤的數(shù)據(jù)量空执,雖然提升了性能浪箭,但數(shù)據(jù)安全性無(wú)法保證。
配置為everysec,是建議的同步策略辨绊,也是默認(rèn)配置奶栖,做到兼顧性能和數(shù)據(jù)安全性,理論上只有在系統(tǒng)突然宕機(jī)的情況下丟失1s的數(shù)據(jù)门坷。(嚴(yán)格來(lái)說(shuō)最多丟失1s數(shù)據(jù)是不準(zhǔn)確)
2.1.4 重寫機(jī)制
隨著命令不斷寫入AOF宣鄙,文件會(huì)越來(lái)越大,為了解決這個(gè)問題默蚌,Redis引入了AOF重寫機(jī)制壓縮文件體積冻晤。AOF文件重寫是吧Redis進(jìn)程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令同步到新AOF文件的過(guò)程。
重寫后的AOF文件為什么可以變下敏簿?有如下原因:
1) 進(jìn)程內(nèi)已經(jīng)超時(shí)的數(shù)據(jù)不再寫文件明也。
2)舊的AOF文件含有無(wú)效命令,如del key1惯裕、 hdel key2温数、srem keys、set a 111蜻势、set a 222等撑刺。重寫使用進(jìn)程內(nèi)數(shù)據(jù)直接生成,這樣新的AOF文件只保留最終數(shù)據(jù)的寫入命令握玛。
3) 多條寫命令可以合并為一個(gè)够傍,如lpush list a、lpush list b挠铲、 lpush list c 可以轉(zhuǎn)化為:lpush list a b c冕屯。為了防止但挑明了過(guò)大造成客戶端緩沖區(qū)溢出,對(duì)于list拂苹、set安聘、hash、zset等類型曹組瓢棒,以64個(gè)元素為界拆分為多條浴韭。
AOF重寫降低了文件占用空間,除此之外脯宿,另一個(gè)目的是:更小的AOF文件可以更快地被Redis加載念颈。
AOF重寫過(guò)程可以手動(dòng)觸發(fā)和自動(dòng)觸發(fā):
手動(dòng)觸發(fā):直接調(diào)用bgrewriteaof命令
-
自動(dòng)觸發(fā):更具auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數(shù)確定自動(dòng)觸發(fā)時(shí)機(jī)
auto-aof-rewrite-min-size:表示運(yùn)行AOF重寫時(shí)文件最小體積,默認(rèn)為64MB
auto-aof-rewrite-percentage:代表當(dāng)前AOF文件空間(aof_current_size)和上一次重寫后AOF文件空間(aof_base_size)的值
自動(dòng)觸發(fā)時(shí)機(jī)=aof_current_size>auto-aof-rewrite-min-size && (aof_current_size-aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage
其中aof_current_size和aof_base_size可以再info Persistence統(tǒng)計(jì)信息中查看连霉。
當(dāng)觸發(fā)AOF重寫時(shí)榴芳,內(nèi)部做了那些事嗡靡?下面結(jié)合圖介紹它的運(yùn)行流程:
流程說(shuō)明:
1)執(zhí)行AOF重寫請(qǐng)求。
如果當(dāng)前進(jìn)程正在執(zhí)行AOF重寫翠语,請(qǐng)求不執(zhí)行并返回如下響應(yīng):
ERR Background append only file rewriting already in progress
如果當(dāng)前進(jìn)程正在執(zhí)行bgsave操作叽躯,重寫命令延遲到bgsave完成后再執(zhí)行,返回如下響應(yīng):
Background append only file rewriting scheduled
2) 父進(jìn)程執(zhí)行fork創(chuàng)建子進(jìn)程肌括,開銷等同于bgsave過(guò)程点骑。
3.1) 主進(jìn)程fork操作完成后,繼續(xù)響應(yīng)其他命令谍夭。所有修改命令依然寫入AOF緩沖區(qū)并更具appendfsync策略同步到硬盤黑滴,保證原有AOF機(jī)制正確性。
3.2) 由于fork操作運(yùn)用寫時(shí)復(fù)制技術(shù)紧索,子進(jìn)程只能共享fork操作時(shí)的內(nèi)存數(shù)據(jù)袁辈。由于父進(jìn)程依然響應(yīng)命令,Redis使用"AOF重寫緩沖區(qū)"保存這部分新數(shù)據(jù)珠漂,防止新AOF文件生成期間丟失這部分?jǐn)?shù)據(jù)晚缩。
4)子進(jìn)程根據(jù)內(nèi)存快照,按照命令合并規(guī)則寫入到新的AOF文件媳危。每次批量寫入硬盤數(shù)據(jù)量由配置aof-rewrite-incremental-fsync控制荞彼,默認(rèn)為32MB,防止單次刷盤數(shù)據(jù)過(guò)多造成硬盤阻塞待笑。
5.1)新AOF文件寫入完成后鸣皂,子進(jìn)程發(fā)送信號(hào)給父進(jìn)程,父進(jìn)程更新統(tǒng)計(jì)信息暮蹂,具體見info persistence下的aof_*相關(guān)統(tǒng)計(jì)寞缝。
5.2)父進(jìn)程把AOF重寫緩沖區(qū)的數(shù)據(jù)寫入到新的AOF文件。
5.3)使用新AOF文件替換老文件仰泻,完成AOF重寫荆陆。
2.1.5 重啟加載
AOF和RDB文件都可以用于服務(wù)器重啟時(shí)的數(shù)據(jù)恢復(fù)。如圖所示集侯,表示Redis持久化文件加載流程:
流程說(shuō)明:
1) AOF持久化開啟且存在AOF文件時(shí)被啼,優(yōu)先加載AOF文件,打印如下日志:
DB loaded from append only file: 5.841 seconds
2) AOF關(guān)閉或者AOF文件不存在時(shí)浅悉,加載RDB文件,打印如下日志:
DB loaded from disk:5.586 seconds
3) 加載AOF/RDB文件城后券犁,Redis啟動(dòng)成功术健。
4) AOF/RDB文件存在錯(cuò)誤時(shí),Redis啟動(dòng)失敗并打印錯(cuò)誤信息