Redis是記憶體資料庫,如果不將記憶體中的資料庫狀態儲存到磁碟,那麼一旦伺服器程序退出會造成伺服器中的資料庫狀態也會消失。所以 Redis 提供了資料持久化功能。Redis支援兩種方式的持久化,一種是RDB方式;另一種是AOF(append-only-file)方式。兩種持久化方式可以單獨使用,也可以將這兩種方式結合使用。
影片講解如下:
https://www.bilibili.com/video/BV1LrvwejEbq/?aid=112867328133...
這裡重點討論一下Redis的RDB資料持久化。RDB持久化是Redis預設的持久化方式。它是指在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,實際操作過程是fork一個子程序,先將資料集寫入臨時檔案,寫入成功後再替換之前的檔案,並用二進位制壓縮儲存。
影片講解如下:
https://www.bilibili.com/video/BV1qKv6e9E3h/?aid=112873485371...
一、RDB持久化機制的工作流程
RDB執行快照的時機由以下引數決定:
# Save the DB to disk.
# save <seconds> <changes>
# Redis will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
# Snapshotting can be completely disabled with a single empty
# string argument as in following example:
# save ""
# Unless specified otherwise, by default Redis will save the DB:
# * After 3600 seconds (an hour) if at least 1 key changed
# * After 300 seconds (5 minutes) if at least 100 keys changed
# * After 60 seconds if at least 10000 keys changed
# You can set these explicitly by uncommenting the three following lines.
# save 3600 1
# save 300 100
# save 60 10000
提示:Redis執行RDB是透過save命令實現的。在預設情況下觸發RDB的條件如下:
# save 3600 1 在3600秒內,如有1個Key發生了變化,則執行RDB。
# save 300 100 在300秒內,如有100個Key發生了變化,則執行RDB。
# save 60 10000 在60秒內,如有1萬個Key發生了變化,則執行RDB。
RDB持久化機制的工作流程如下:
(1)Redis根據配置引數去生存rdb快照檔案
(2)Redis將fork一個子程序出來。
(3)由子程序嘗試將記憶體中的資料dump到臨時的rdb檔案中。
(4)完成rdb快照檔案的生成之後,就會去替換舊的快照檔案。
從RDB的工作流程可以看出,RDB具有以下的優點和缺點:
- 適合大規模的資料恢復。
- 如果業務對資料完整性和一致性要求不高,RDB是很好的選擇。
- 資料的完整性和一致性不高,因為RDB可能在最後一次備份時當機了。
- 備份時佔用記憶體,因為Redis 在備份時會獨立建立一個子程序,將資料寫入到一個臨時檔案,最後再將臨時檔案替換之前的備份檔案。所以要考慮到大概兩倍的資料膨脹性。
Redis監控RDB最直接的方法當然就是使用系統提供的info命令來做了。只需要執行下面一條命令,就能獲得Redis關於RDB的狀態報告。
bin/redis-cli info | grep rdb_
輸出的資訊如下:
rdb_changes_since_last_save:0 表明上次RDB儲存以後改變的鍵的個數。
rdb_bgsave_in_progress:0 表示當前是否在進行RDB操作,0表示沒有進行。
rdb_last_save_time:1650184060 上次執行RDB操作的時間戳。
rdb_last_bgsave_status:ok 上次執行RDB操作的狀態
rdb_last_bgsave_time_sec:-1 上次執行RDB操作的耗時。
rdb_current_bgsave_time_sec:-1 目前執行RDB操作已花費的時間。
rdb_last_cow_size:0 表示父程序與子程序比較執行了多少修改操作。
二、剖析RDB持久化機制
在rdb.c檔案中可以找到建立RDB檔案的函式rdbSave(),函式定義如下:
/* Save the DB on disk. Return C_ERR on error, C_OK on success. */
int rdbSave(char *filename, rdbSaveInfo *rsi) {
......
// 建立臨時檔案
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
fp = fopen(tmpfile,"w");
......
// 初始化I/O
rioInitWithFile(&rdb,fp);
// 開始執行RDB
startSaving(RDBFLAGS_NONE);
......
//如果持久化成功操作成功,則用臨時檔案替代舊的檔案
if (rename(tmpfile,filename) == -1) {
char *cwdp = getcwd(cwd,MAXPATHLEN);
serverLog(LL_WARNING,
"Error moving temp DB file %s on the final "
"destination %s (in server root dir %s): %s",
tmpfile,
filename,
cwdp ? cwdp : "unknown",
strerror(errno));
unlink(tmpfile);
stopSaving(0);
return C_ERR;
}
serverLog(LL_NOTICE,"DB saved on disk");
//持久化成功後,將計數器重置為0,並更新最近儲存時間。
server.dirty = 0;
server.lastsave = time(NULL);
server.lastbgsave_status = C_OK;
stopSaving(1);
return C_OK;
......
}