Stories

Detail Return Return

【趙渝強老師】Redis的RDB數據持久化 - Stories Detail

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;
    ......
}
user avatar CuiPengJu Avatar toplist Avatar
Favorites 2 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.