Redis 提供了兩種持久化策略git
RDB 持久化機制,會在一段時間內生成指定時間點的數據集快照(snapshot)github
AOF 持久化機制,記錄 server 端收到的每一條寫命令,當 server 重啓時會進行重放以此來重建以前的數據集。AOF 文件中的命令所有以 Redis 協議的格式來保存,新命令會被追加(append)到文件的末尾。 Redis 還能夠在後臺對 AOF 文件進行重寫(rewrite) ,使得 AOF 文件的體積不會超出保存數據集狀態所需的實際大小。redis
若是你僅使用 Redis 做爲緩存加速訪問,你能夠關閉這兩個持久化設置算法
你也能夠同時開啓這兩個持久化設置,可是在這種狀況下,Redis 重啓時會使用 AOF 文件來重建數據集,由於 AOF 文件保存的數據每每更加完整數據庫
Redis 提供了 SAVE 和 BGSAVE 兩個命令來生成 RDB 文件,區別是前者是阻塞的,後者是後臺 fork 子進程進行不會阻塞主進程處理命令請求。載入 RDB 文件不須要手工運行,而是 server 端自動進行,只要啓動時檢測到 RDB 文件存在 server 端便會載入 RDB 文件重建數據集。固然上面簡介中已經提到,若是 同時存在 AOF 的話會優先使用 AOF 重建數據集由於其保存的數據更完整。緩存
SAVE 和 BGSAVE 命令實現安全
C服務器
void saveCommand(client *c) {
// BGSAVE執行時不能執行SAVE
if (server.rdb_child_pid != -1) {
addReplyError(c,"Background save already in progress");
return;
}
rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi);
// 調用rdbSave函數執行備份(阻塞當前客戶端)
if (rdbSave(server.rdb_filename,rsiptr) == C_OK) {
addReply(c,shared.ok);
} else {
addReply(c,shared.err);
}
}
/*
* BGSAVE 命令實現 [可選參數"schedule"]
*/
void bgsaveCommand(client *c) {
int schedule = 0;
/* 當AOF正在執行時,SCHEDULE參數修改BGSAVE的效果
* BGSAVE會在以後執行,而不是報錯
* 能夠理解爲:BGSAVE被提上日程
*/
if (c->argc > 1) {
// 參數只能是"schedule"
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) {
schedule = 1;
} else {
addReply(c,shared.syntaxerr);
return;
}
}
// BGSAVE正在執行,不操做
if (server.rdb_child_pid != -1) {
addReplyError(c,"Background save already in progress");
} else if (server.aof_child_pid != -1) {
// aof正在執行,若是schedule==1,BGSAVE被提上日程
if (schedule) {
server.rdb_bgsave_scheduled = 1;
addReplyStatus(c,"Background saving scheduled");
} else {
addReplyError(c,
"An AOF log rewriting in progress: can't BGSAVE right now. "
"Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever "
"possible.");
}
} else if (rdbSaveBackground(server.rdb_filename,NULL) == C_OK) {// 不然調用rdbSaveBackground執行備份操做
addReplyStatus(c,"Background saving started");
} else {
addReply(c,shared.err);
}
}
SAVE POINT save <seconds> <changes>app
你能夠配置保存點(save point),Redis 若是每 N 秒數據發生了 M 次改變就保存快照文件,例以下面:函數
Save Point 配置
Shell
# 這個保存點配置表示每60秒,若是數據發生了1000次以上的變更,Redis就會自動保存快照文件
save 60 1000
# 保存點能夠設置多個,Redis的配置文件就默認設置了3個保存點
# 格式爲:save <seconds> <changes>
# 能夠設置多個。
save 900 1 #900秒後至少1個key有變更
save 300 10 #300秒後至少10個key有變更
save 60 10000 #60秒後至少10000個key有變更
stop-writes-on-bgsave-error yes | no
若是 Redis 執行 RDB 持久化失敗(常見於操做系統內存不足),那麼 Redis 將再也不接受 client 寫入數據的請求。固然在實踐中,咱們一般會將 stop-writes-on-bgsave-error 設置爲 false,同時讓監控系統在 Redis 執行 RDB 持久化失敗時發送告警,以便介入解決,而不是粗暴地拒絕 client 的寫入請求。
rdbcompression yes | no
當生成 RDB 文件時,Redis 會判斷字符串長度 >=20字節則壓縮,不然不壓縮存儲,默認 Redis 會採用 LZF 算法進行數據壓縮。
rdbchecksum yes | no
從版本5的 RDB 的開始,一個 CRC64 的校驗碼會放在文件的末尾。這樣更能保證文件的完整性,可是在保存或者加載文件時會損失必定的性能(大概10%)。若是想追求更高的性能,能夠把它禁用掉,這樣文件在寫入校驗碼時會用 0 替代,加載的時候看到 0 就會直接跳過校驗。
RDB文件是一個很簡潔的單文件,它保存了某個時間點的 Redis 數據集,很適合用於作備份。你能夠設定一個時間點對 RDB 文件進行歸檔,這樣就能在須要的時候很輕易的把數據恢復到不一樣的版本。
基於上面所描述的特性,RDB 文件很適合用於災備,由於單文件能夠很方便地傳輸到另外的數據中心。
RDB的性能很好,須要進行持久化時,主進程會 fork 一個子進程出來,而後把持久化的工做交給子進程,本身不會有相關的 I/O 操做。
比起 AOF,在數據量比較大的狀況下,RDB的啓動速度更快。
RD B容易形成數據的丟失,當你但願在 Redis 中止工做時儘可能減小數據丟失的話,那 RDB 不適用。假設每5分鐘保存一次快照,若是Redis由於某些緣由不能正常工做,那麼從上次產生快照到 Redis 出現問題這段時間的數據就會丟失了。你能夠經過配置不一樣的 save point 來減輕數據丟失的程度,可是越緊湊的 save point 會越頻繁地觸發 RDB 生成操做,從而對 Redis 性能產生影響
RDB 使用 fork 子進程進行數據的持久化,若是數據比較大的話可能就會花費點時間,形成 Redis 中止服務幾毫秒,若是數據量很大且 CPU 性能不是很好的時候,中止服務的時間甚至會到一秒。AOF 也須要 fork 可是你能夠本身調整 rewrite 的頻率,它不會形成數據丟失。在 Linux 系統中,fork 會拷貝進程的 page table。隨着進程佔用的內存越大,進程的 page table 也會越大,那麼 fork 也會佔用更多的時間。 若是 Redis 佔用的內存很大 (例如 20 GB),那麼在 fork 子進程時,會出現明顯的停頓現象(沒法處理 client 的請求)。另外,在不一樣機器上,fork 的性能是不一樣的,能夠參見 Fork time in different systems
Linux fork 子進程採用的是 copy-on-write 的方式。在 Redis 執行 RDB 持久化期間,若是 client 寫入數據很頻繁,那麼將增長 Redis 佔用的內存,最壞狀況下,內存的佔用將達到原先的兩倍。
和 RDB 持久化數據庫鍵值對來記錄數據庫狀態不一樣,AOF 是經過保存對數據庫的寫命令集來記錄數據庫狀態的。AOF 持久化實現能夠分爲命令追加(append)、文件寫入(write)、文件同步(fsync) 三個步驟。Append 追加命令到 AOF 緩衝區,Write 將緩衝區的內容寫入到程序緩衝區,Fsync 將程序緩衝區的內容寫入到文件。
命令追加
當 AOF 持久化功能打開時,server 端每執行完一個寫命令,會以協議格式將被執行的寫命令追加到 server 端 redisServer 結構體中的 aof_buf 緩衝區末尾。
文件寫入與同步
Redis server 進程是一個事件循環(event loop),server 每結束一個事件循環以前都會調用 flushAppendOnlyFile 函數,考慮是否將 aof_buf 緩衝區中的內容吸入和保存到 AOF 文件,而 flushAppendOnlyFile 函數的行爲由 appendfsync 選項來控制
appendfsync 值 |
flushAppendOnlyFile 行爲 |
---|---|
always |
每一個事件循環都將 aof_buf 緩衝區中的內容寫入 AOF 文件,而且調用 fsync() 將其同步到磁盤。這能夠保證最好的數據持久性,但卻會給系統帶來極大的開銷,其效率是三者中最慢的,但同時安全性也是最高的,即便宕機也只丟失一個事件循環中的數據。 |
no |
每一個事件循環都將 aof_buf 緩衝區中的內容寫入 AOF 文件,但不對其進行同步,什麼時候同步至磁盤會讓操做系統決定。這種模式下 AOF 的寫入速度最快,不過因其會在系統緩存中積累一段時間的數據,因此同步時間爲三者最長。一旦宕機將會丟失自上一次同步 AOF 文件起全部的數據。 |
everysec |
每一個事件循環都將 aof_buf 緩衝區中的內容寫入 AOF 文件,Redis 還會每秒在子線程中執行一次 fsync()。在實踐中,推薦使用這種設置,必定程度上能夠保證數據持久性,又不會明顯下降 Redis 性能。 |
AOF 持久化並非沒有缺點的,Redis 會不斷將接收到的寫命令追加到 AOF 文件中,致使 AOF 文件愈來愈大。過大的 AOF 文件會消耗磁盤空間,而且致使 Redis 重啓時更加緩慢。爲了解決這個問題,在適當狀況下,Redis 會對 AOF 文件進行重寫,去除文件中冗餘的命令,以減少 AOF 文件的體積。
AOF的重寫會執行大量的寫入操做,Redis是單線程的,因此若是有服務器直接調用重寫,服務器就不能處理其餘命令了,所以Redis服務器新起了單獨一個進程來執行AOF重寫。固然也能夠經過 BGREWRITEAOF 命令手動重寫 AOF 文件。重寫後的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。
在子進程執行AOF重寫時,服務端接收到客戶端的命令以後,先執行客戶端發來的命令,而後將執行後的寫命令追加到AOF緩衝區中,同時將執行後的寫命令追加到AOF重寫緩衝區中。 等到子進程完成了重寫工做後,會發一個完成的信號給服務器,服務器就將AOF重寫緩衝區中的全部內容追加到AOF文件中,而後原子性地覆蓋現有的AOF文件。
aof 相關配置
Shell
# 你能夠在 redis.conf 中經過如下配置開啓 AOF 功能
appendonly yes
# 文件存放目錄,與RDB共用。默認爲當前工做目錄。
dir ./
# 默認文件名爲appendonly.aof
appendfilename "appendonly.aof"
# fsync 相關配置
# appendfsync always
appendfsync everysec
# appendfsync no
# Redis會記住自從上一次重寫後AOF文件的大小(若是自Redis啓動後還沒重寫過,則記住啓動時使用的AOF文件的大小)。
# 若是當前的文件大小比起記住的那個大小超過指定的百分比,則會觸發重寫。
# 同時須要設置一個文件大小最小值,只有大於這個值文件纔會重寫,以防文件很小,可是已經達到百分比的狀況。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 上面兩個配置的做用:當 AOF 文件的體積大於 64MB,而且 AOF 文件的體積比上一次重寫以後的體積大了至少一倍,那麼 Redis 就會執行 AOF 重寫。
# 要禁用自動的日誌重寫功能,咱們能夠把百分比設置爲0:
auto-aof-rewrite-percentage 0
比RDB可靠。你能夠制定不一樣的 fsync 策略:no、everysec 和 always。默認是 everysec。這意味着你最多丟失一秒鐘的數據。
AOF日誌文件是一個純追加的文件。就算是遇到忽然停電的狀況,也不會出現日誌的定位或者損壞問題。甚至若是由於某些緣由(例如磁盤滿了)命令只寫了一半到日誌文件裏,咱們也能夠用 redis-check-aof 這個工具很簡單的進行修復。
當AOF文件太大時,Redis 會自動在後臺進行重寫。重寫很安全,由於重寫是在一個新的文件上進行,同時 Redis 會繼續往舊的文件追加數據。新文件上會寫入能重建當前數據集的最小操做命令的集合。當新文件重寫完,Redis 會把新舊文件進行切換,而後開始把數據寫到新文件上。
AOF 把操做命令以簡單易懂的格式一條接一條的保存在文件裏,很容易導出來用於恢復數據。例如咱們不當心用 FLUSHALL 命令把全部數據刷掉了,只要文件沒有被重寫,咱們能夠把服務停掉,把最後那條命令刪掉,而後重啓服務,這樣就能把被刷掉的數據恢復回來。
在相同的數據集下,AOF 文件的大小通常會比 RDB 文件大。
在某些 fsync 策略下,AOF 的速度會比 RDB 慢。一般 fsync 設置爲每秒一次就能得到比較高的性能,而在禁止 fsync 的狀況下速度能夠達到 RDB 的水平。
在過去曾經發現一些很罕見的BUG致使使用AOF重建的數據跟原數據不一致的問題。
Redis 4.0 開始支持 RDB 和 AOF 的混合持久化(默認關閉,能夠經過配置項 aof-use-rdb-preamble 開啓)。若是把混合持久化打開,AOF 重寫的時候就直接把 RDB 的內容寫到 AOF 文件開頭。這樣作的好處是能夠結合 RDB 和 AOF 的優勢, 快速加載同時避免丟失過多的數據。固然缺點也是有的, AOF 裏面的 RDB 部分就是壓縮格式再也不是 AOF 格式,可讀性較差。