為防止數(shù)據(jù)丟失,需要將 Redis 中的數(shù)據(jù)從內(nèi)存中 dump 到磁盤潦闲,這就是持久化挤悉。Redis 提供兩種持久化方式:RDB 和 AOF泣刹。Redis 允許兩者結(jié)合,也允許兩者同時(shí)關(guān)閉命浴。廢話不多說娄猫,今天整理下redis的持久化相關(guān)的筆記。
Redis持久化
Redis 提供了不同級(jí)別的持久化方式:
- RDB持久化方式能夠在指定的時(shí)間間隔能對(duì)你的數(shù)據(jù)進(jìn)行快照存儲(chǔ).
- AOF(Append-only file生闲,AOF)持久化方式記錄每次對(duì)服務(wù)器寫的操作,當(dāng)服務(wù)器重啟的時(shí)候會(huì)重新執(zhí)行這些命令來恢復(fù)原始的數(shù)據(jù),AOF命令以redis協(xié)議追加保存每次寫的操作到文件末尾.Redis還能對(duì)AOF文件進(jìn)行后臺(tái)重寫,使得AOF文件的體積不至于過大.
- 如果你只希望你的數(shù)據(jù)在服務(wù)器運(yùn)行的時(shí)候存在,你也可以不使用任何持久化方式.
- 你也可以同時(shí)開啟兩種持久化方式, 在這種情況下, 當(dāng)redis重啟的時(shí)候會(huì)優(yōu)先載入AOF文件來恢復(fù)原始的數(shù)據(jù),因?yàn)樵谕ǔG闆r下AOF文件保存的數(shù)據(jù)集要比RDB文件保存的數(shù)據(jù)集要完整.
兩種方式優(yōu)缺點(diǎn)比較
RDB優(yōu)點(diǎn)
- RDB是一個(gè)非常緊湊的文件,它保存了某個(gè)時(shí)間點(diǎn)得數(shù)據(jù)集,非常適用于數(shù)據(jù)集的備份,比如你可以在每個(gè)小時(shí)報(bào)保存一下過去24小時(shí)內(nèi)的數(shù)據(jù),同時(shí)每天保存過去30天的數(shù)據(jù),這樣即使出了問題你也可以根據(jù)需求恢復(fù)到不同版本的數(shù)據(jù)集.
- RDB是一個(gè)緊湊的單一文件,很方便傳送到另一個(gè)遠(yuǎn)端數(shù)據(jù)中心或者亞馬遜的S3(可能加密)媳溺,非常適用于災(zāi)難恢復(fù).
- RDB在保存RDB文件時(shí)父進(jìn)程唯一需要做的就是fork出一個(gè)子進(jìn)程,接下來的工作全部由子進(jìn)程來做,父進(jìn)程不需要再做其他IO操作碍讯,所以RDB持久化方式可以最大化redis的性能.
與AOF相比,在恢復(fù)大的數(shù)據(jù)集的時(shí)候悬蔽,RDB方式會(huì)更快一些.
RDB缺點(diǎn)
- 如果你希望在redis意外停止工作(例如電源中斷)的情況下丟失的數(shù)據(jù)最少的話,那么RDB不適合你.雖然你可以配置不同的save時(shí)間點(diǎn)(例如每隔5分鐘并且對(duì)數(shù)據(jù)集有100個(gè)寫的操作),是Redis要完整的保存整個(gè)數(shù)據(jù)集是一個(gè)比較繁重的工作,你通常會(huì)每隔5分鐘或者更久做一次完整的保存,萬一在Redis意外宕機(jī),你可能會(huì)丟失幾分鐘的數(shù)據(jù).
- RDB 需要經(jīng)常fork子進(jìn)程來保存數(shù)據(jù)集到硬盤上,當(dāng)數(shù)據(jù)集比較大的時(shí)候,fork的過程是非常耗時(shí)的,可能會(huì)導(dǎo)致Redis在一些毫秒級(jí)內(nèi)不能響應(yīng)客戶端的請(qǐng)求.如果數(shù)據(jù)集巨大并且CPU性能不是很好的情況下,這種情況會(huì)持續(xù)1秒,AOF也需要fork,但是你可以調(diào)節(jié)重寫日志文件的頻率來提高數(shù)據(jù)集的耐久度.
AOF優(yōu)點(diǎn)
- 使用AOF 會(huì)讓你的Redis更加耐久: 你可以使用不同的fsync策略:無fsync,每秒fsync,每次寫的時(shí)候fsync.使用默認(rèn)的每秒fsync策略,Redis的性能依然很好(fsync是由后臺(tái)線程進(jìn)行處理的,主線程會(huì)盡力處理客戶端請(qǐng)求),一旦出現(xiàn)故障捉兴,你最多丟失1秒的數(shù)據(jù).
一般情況下蝎困,對(duì)硬盤(或者其他持久存儲(chǔ)設(shè)備)文件的write操作,更新的只是內(nèi)存中的頁(yè)緩存(page cache)倍啥,而臟頁(yè)面不會(huì)立即更新到硬盤中禾乘,而是由操作系統(tǒng)統(tǒng)一調(diào)度,如由專門的flusher內(nèi)核線程在滿足一定條件時(shí)(如一定時(shí)間間隔虽缕、內(nèi)存中的臟頁(yè)達(dá)到一定比例)內(nèi)將臟頁(yè)面同步到硬盤上(放入設(shè)備的IO請(qǐng)求隊(duì)列)
因?yàn)閣rite調(diào)用不會(huì)等到硬盤IO完成之后才返回始藕,因此如果OS在write調(diào)用之后、硬盤同步之前崩潰彼宠,則數(shù)據(jù)可能丟失鳄虱。雖然這樣的時(shí)間窗口很小弟塞,但是對(duì)于需要保證事務(wù)的持久化(durability)和一致性(consistency)的數(shù)據(jù)庫(kù)程序來說凭峡,write()所提供的“松散的異步語(yǔ)義”是不夠的,通常需要OS提供的同步IO(synchronized-IO)fsync原語(yǔ)來保證:
fsync的功能是確保文件fd所有已修改的內(nèi)容已經(jīng)正確同步到硬盤上决记,該調(diào)用會(huì)阻塞等待直到設(shè)備報(bào)告IO完成摧冀。
- AOF文件是一個(gè)只進(jìn)行追加的日志文件,所以不需要寫入seek,即使由于某些原因(磁盤空間已滿,寫的過程中宕機(jī)等等)未執(zhí)行完整的寫入命令,你也也可使用redis-check-aof工具修復(fù)這些問題.
- Redis 可以在 AOF 文件體積變得過大時(shí),自動(dòng)地在后臺(tái)對(duì) AOF 進(jìn)行重寫: 重寫后的新 AOF 文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合索昂。 整個(gè)重寫操作是絕對(duì)安全的建车,因?yàn)?Redis 在創(chuàng)建新 AOF 文件的過程中,會(huì)繼續(xù)將命令追加到現(xiàn)有的 AOF 文件里面椒惨,即使重寫過程中發(fā)生停機(jī)缤至,現(xiàn)有的 AOF 文件也不會(huì)丟失。 而一旦新 AOF 文件創(chuàng)建完畢康谆,Redis 就會(huì)從舊 AOF 文件切換到新 AOF 文件领斥,并開始對(duì)新 AOF 文件進(jìn)行追加操作。
- AOF 文件有序地保存了對(duì)數(shù)據(jù)庫(kù)執(zhí)行的所有寫入操作沃暗, 這些寫入操作以 Redis 協(xié)議的格式保存月洛, 因此 AOF 文件的內(nèi)容非常容易被人讀懂, 對(duì)文件進(jìn)行分析(parse)也很輕松孽锥。 導(dǎo)出(export) AOF 文件也非常簡(jiǎn)單: 舉個(gè)例子嚼黔, 如果你不小心執(zhí)行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫惜辑, 那么只要停止服務(wù)器唬涧, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis 盛撑, 就可以將數(shù)據(jù)集恢復(fù)到 FLUSHALL 執(zhí)行之前的狀態(tài)爵卒。
AOF缺點(diǎn)
- 對(duì)于相同的數(shù)據(jù)集來說,AOF 文件的體積通常要大于 RDB 文件的體積撵彻。
- 根據(jù)所使用的 fsync 策略钓株,AOF 的速度可能會(huì)慢于 RDB 。 在一般情況下陌僵, 每秒 fsync 的性能依然非常高轴合, 而關(guān)閉 fsync 可以讓 AOF 的速度和 RDB 一樣快, 即使在高負(fù)荷之下也是如此碗短。 不過在處理巨大的寫入載入時(shí)受葛,RDB 可以提供更有保證的最大延遲時(shí)間(latency)
總結(jié)一下
- RDB的文件比aof文件小,aof文件格式清晰易懂偎谁,文件過大時(shí)候可以自動(dòng)重寫避免文件體積過大总滩。
- 數(shù)據(jù)恢復(fù)方面,RDB方式更快巡雨,適用于災(zāi)難恢復(fù)闰渔,但是恢復(fù)數(shù)據(jù)沒有AOF完整,所以redis重啟在RDB铐望,AOF文件同時(shí)存在的情況下默認(rèn)優(yōu)先載入AOF文件恢復(fù)數(shù)據(jù)冈涧。
- redis寫入量較大的時(shí)候茂附,RDB更能保證最大延遲時(shí)間,但是數(shù)據(jù)集較大的時(shí)候督弓,RDB fork的耗時(shí)長(zhǎng)营曼,毫秒甚至秒級(jí)別可能會(huì)不能響應(yīng)客戶端請(qǐng)求。
如何選擇
- 一般來說愚隧,如果想達(dá)到足以媲美 PostgreSQL 的數(shù)據(jù)安全性蒂阱,你應(yīng)該同時(shí)使用兩種持久化功能。
- 如果你非常關(guān)心你的數(shù)據(jù)狂塘,但仍然可以承受數(shù)分鐘以內(nèi)的數(shù)據(jù)丟失蒜危,那么你可以只使用 RDB 持久化。
- 有很多都只使用 AOF 持久化睹耐,但是并不推薦這種方式:因?yàn)槎〞r(shí)生成 RDB 快照(snapshot)非常便于進(jìn)行數(shù)據(jù)庫(kù)備份辐赞,并且 RDB 恢復(fù)數(shù)據(jù)集的速度也要比 AOF 恢復(fù)的速度要快。
配置&工作原理
RDB配置
快照(snapshot)配置硝训,默認(rèn)保存在dump.rdb的二進(jìn)制文件中响委,在“N秒內(nèi)數(shù)據(jù)集合至少有M個(gè)改動(dòng)”這一條件滿足,自動(dòng)保存一次數(shù)據(jù)集窖梁。也可以通過調(diào)用 SAVE或者 BGSAVE 赘风, 手動(dòng)讓 Redis 進(jìn)行數(shù)據(jù)集保存操作。
save 900 1
save 300 10
save 60 10000
RDB工作原理
當(dāng) Redis 需要保存 dump.rdb 文件時(shí)纵刘, 服務(wù)器執(zhí)行以下操作:
- Redis 調(diào)用forks. 同時(shí)擁有父進(jìn)程和子進(jìn)程邀窃。
- 子進(jìn)程將數(shù)據(jù)集寫入到一個(gè)臨時(shí) RDB 文件中。
- 當(dāng)子進(jìn)程完成對(duì)新 RDB 文件的寫入時(shí)假哎,Redis 用新 RDB 文件替換原來的 RDB 文件瞬捕,并刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時(shí)復(fù)制(copy-on-write)機(jī)制中獲益舵抹。
在Linux程序中肪虎,fork()會(huì)產(chǎn)生一個(gè)和父進(jìn)程完全相同的子進(jìn)程,但子進(jìn)程在此后多會(huì)exec系統(tǒng)調(diào)用惧蛹,出于效率考慮扇救,linux中引入了“寫時(shí)復(fù)制“技術(shù),也就是只有進(jìn)程空間的各段的內(nèi)容要發(fā)生變化時(shí)香嗓,才會(huì)將父進(jìn)程的內(nèi)容復(fù)制一份給子進(jìn)程迅腔。
在fork之后exec之前兩個(gè)進(jìn)程用的是相同的物理空間(內(nèi)存區(qū)),子進(jìn)程的代碼段靠娱、數(shù)據(jù)段沧烈、堆棧都是指向父進(jìn)程的物理空間,也就是說饱岸,兩者的虛擬空間不同掺出,但其對(duì)應(yīng)的物理空間是同一個(gè)。當(dāng)父子進(jìn)程中有更改相應(yīng)段的行為發(fā)生時(shí)苫费,再為子進(jìn)程相應(yīng)的段分配物理空間汤锨,如果不是因?yàn)閑xec,內(nèi)核會(huì)給子進(jìn)程的數(shù)據(jù)段百框、堆棧段分配相應(yīng)的物理空間(至此兩者有各自的進(jìn)程空間闲礼,互不影響),而代碼段繼續(xù)共享父進(jìn)程的物理空間(兩者的代碼完全相同)铐维。而如果是因?yàn)閑xec柬泽,由于兩者執(zhí)行的代碼不同,子進(jìn)程的代碼段也會(huì)分配單獨(dú)的物理空間嫁蛇。
AOF配置
快照功能并不是非常耐久锨并,如果 Redis 因?yàn)槟承┰蚨斐晒收贤C(jī),那么服務(wù)器將丟失最近寫入睬棚、且仍未保存到快照中的那些數(shù)據(jù)第煮。你可以在配置文件中打開AOF方式:
appendonly yes
從現(xiàn)在開始, 每當(dāng) Redis 執(zhí)行一個(gè)改變數(shù)據(jù)集的命令時(shí)(比如 SET)抑党, 這個(gè)命令就會(huì)被追加到 AOF 文件的末尾包警。這樣的話, 當(dāng) Redis 重新啟時(shí)底靠, 程序就可以通過重新執(zhí)行 AOF 文件中的命令來達(dá)到重建數(shù)據(jù)集的目的害晦。
你可以配置 Redis 多久才將數(shù)據(jù) fsync 到磁盤一次。有三種方式:
- 每次有新命令追加到 AOF 文件時(shí)就執(zhí)行一次 fsync :非常慢暑中,也非常安全
- 每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多)壹瘟,并且在故障時(shí)只會(huì)丟失 1 秒鐘的數(shù)據(jù)。
- 從不 fsync :將數(shù)據(jù)交給操作系統(tǒng)來處理鳄逾。更快俐筋,也更不安全的選擇。
- 推薦(并且也是默認(rèn))的措施為每秒 fsync 一次严衬, 這種 fsync 策略可以兼顧速度和安全性澄者。
AOF工作原理
AOF 重寫和 RDB 創(chuàng)建快照一樣,都巧妙地利用了寫時(shí)復(fù)制機(jī)制:
- Redis 執(zhí)行 fork() 请琳,現(xiàn)在同時(shí)擁有父進(jìn)程和子進(jìn)程粱挡。
- 子進(jìn)程開始將新 AOF 文件的內(nèi)容寫入到臨時(shí)文件。
- 對(duì)于所有新執(zhí)行的寫入命令俄精,父進(jìn)程一邊將它們累積到一個(gè)內(nèi)存緩存中询筏,一邊將這些改動(dòng)追加到現(xiàn)有 AOF 文件的末尾,這樣樣即使在重寫的中途發(fā)生停機(jī),現(xiàn)有的 AOF 文件也還是安全的竖慧。
- 當(dāng)子進(jìn)程完成重寫工作時(shí)嫌套,它給父進(jìn)程發(fā)送一個(gè)信號(hào)逆屡,父進(jìn)程在接收到信號(hào)之后,將內(nèi)存緩存中的所有數(shù)據(jù)追加到新 AOF 文件的末尾踱讨。
- 搞定魏蔗!現(xiàn)在 Redis 原子地用新文件替換舊文件,之后所有命令都會(huì)直接追加到新 AOF 文件的末尾痹筛。