RocksDB系列十一:How to backup RocksDB?

Backup API

c++ api,請(qǐng)參考:include/rocksdb/utilities/backupable_db.h。核心模塊是backup engine,其暴露了創(chuàng)建backup的簡(jiǎn)單接口、查詢backup的相關(guān)信息以及從backup中恢復(fù)數(shù)據(jù)。backup engine主要有以下形式:1) 創(chuàng)建backup的BackupEngine 2)從backup恢復(fù)數(shù)據(jù)的BackupEngineReadOnly。每個(gè)engine都可以用來查詢backup的信息。

Creating and verifying a backup

RocksDB實(shí)現(xiàn)了一種backup DB的簡(jiǎn)單方式,還可以對(duì)backup做正確性校驗(yàn)。下面是一個(gè)簡(jiǎn)單示例:

 #include "rocksdb/db.h"
    #include "rocksdb/utilities/backupable_db.h"

    #include <vector>

    using namespace rocksdb;

    int main() {
        Options options;                                                                                  
        options.create_if_missing = true;                                                                 
        DB* db;
        Status s = DB::Open(options, "/tmp/rocksdb", &db);
        assert(s.ok());
        db->Put(...); // do your thing

        BackupEngine* backup_engine;
        s = BackupEngine::Open(Env::Default(), BackupableDBOptions("/tmp/rocksdb_backup"), &backup_engine);
        assert(s.ok());
        s = backup_engine->CreateNewBackup(db);
        assert(s.ok());
        db->Put(...); // make some more changes
        s = backup_engine->CreateNewBackup(db);
        assert(s.ok());

        std::vector<BackupInfo> backup_info;
        backup_engine->GetBackupInfo(&backup_info);

        // you can get IDs from backup_info if there are more than two
        s = backup_engine->VerifyBackup(1 /* ID */);
        assert(s.ok());
        s = backup_engine->VerifyBackup(2 /* ID */);
        assert(s.ok());
        delete db;
        delete backup_engine;
    }

??例子中會(huì)對(duì)/tmp/rocksdb_backup數(shù)據(jù)創(chuàng)建兩個(gè)backup。用戶可以使用相同的backup engine來創(chuàng)建和校驗(yàn)多個(gè)backup。
??正常情況下,backup數(shù)據(jù)是遞增的(參考BackupableDBOptions::share_table_files)。用戶可以使用BackupEngine::CreateNewBackup() 創(chuàng)建一個(gè)新的backup,且只有新增的數(shù)據(jù)才會(huì)copy到backup 目錄中。
??如果你已經(jīng)保存了一些backup,就可以調(diào)用BackupEngine::GetBackupInfo()來查詢所有的backup信息。每一個(gè)backup都有一個(gè)遞增的ID來標(biāo)識(shí)。
??當(dāng)調(diào)用BackupEngine::VerifyBackups()時(shí),會(huì)check backup目錄中文件的大小,并與db目錄中相應(yīng)的文件對(duì)比。但是,并不會(huì)對(duì)文件的checksum進(jìn)行校驗(yàn),因?yàn)檫@樣需要讀取所有的文件數(shù)據(jù)。調(diào)用BackupEngine::VerifyBackups()接口進(jìn)行校驗(yàn)唯一適用的場(chǎng)景就是在執(zhí)行完create backup之后,因?yàn)樾r?yàn)邏輯中使用了backup期間的一些狀態(tài)信息。

Restoring a backup

 #include "rocksdb/db.h"
    #include "rocksdb/utilities/backupable_db.h"

    using namespace rocksdb;

    int main() {
        BackupEngineReadOnly* backup_engine;
        Status s = BackupEngineReadOnly::Open(Env::Default(), BackupableDBOptions("/tmp/rocksdb_backup"), &backup_engine);
        assert(s.ok());
        backup_engine->RestoreDBFromBackup(1, "/tmp/rocksdb", "/tmp/rocksdb");
        delete backup_engine;
    }

示例中會(huì)把第一個(gè)backup數(shù)據(jù)恢復(fù)到/tmp/rocksdb。BackupEngineReadOnly::RestoreDBFromBackup()的第一個(gè)參數(shù)是backup ID,第二個(gè)參數(shù)是目標(biāo)DB目錄,第三個(gè)參數(shù)是日志文件的目標(biāo)位置目錄(DB目錄和LOG目錄可以不一致)。BackupEngineReadOnly::RestoreDBFromLatestBackup()接口會(huì)從最新的backup(ID最大的backup)中恢復(fù)數(shù)據(jù)到DB?;謴?fù)期間,會(huì)計(jì)算所有存儲(chǔ)文件的checksum,并與backup期間存儲(chǔ)的checksum值對(duì)比。如果檢測(cè)到checksum不匹配,就會(huì)中斷restore過程,返回Status::Corruption。如果要查詢恢復(fù)的數(shù)據(jù),需要打開所有恢復(fù)成功的數(shù)據(jù)庫(kù)。

Backup directory structure

/tmp/rocksdb_backup/
├── LATEST_BACKUP
├── meta
│   └── 1
├── private
│   └── 1
│       ├── CURRENT
│       ├── MANIFEST-000008
|       └── OPTIONS-000009
└── shared_checksum
    └── 000007_1498774076_590.sst

??LATEST_BACKUP是一個(gè)記錄了最大backup id的文件。這個(gè)文件用來查詢最大的backup id,由于META信息中也包含了這個(gè)最大id,所以在RocksDB 5.0版本之后就刪除了這個(gè)文件。
??meta目錄包含了meta文件,對(duì)應(yīng)地記錄了每一個(gè)backup的描述信息,文件名就是backup id。如果有三個(gè)backup分別為1、2、3,那么這個(gè)目錄中就包含了文件名為1、2、3的文件,記錄了對(duì)應(yīng)backup的信息。
??private目錄有non-SST 文件,主要是options,current,manifest和WAL。如果不設(shè)置Options::share_table_files,那么SST file也會(huì)在這個(gè)目錄中。
??shared目錄包含了SSTfile(前提是設(shè)置了Options::share_table_files且Options::share_files_with_checksum未設(shè)置)。在這個(gè)目錄中文件與db目錄中的文件名相同。所以所以,在這種情況下,只能備份單個(gè)RocksDB實(shí)例,否則文件名會(huì)沖突。
??shared_checksum目錄中包含了SST files(前提是設(shè)置了Options::share_table_files和Options::share_files_with_checksum)。文件名以DB目錄中的文件名、size和checksum組成。這個(gè)文件名是唯一的,可以來自不同的RocksDB實(shí)例。

Backup performance

??backup engine的open函數(shù)的耗時(shí)與當(dāng)前存在的backup的數(shù)目是正相關(guān)的,因?yàn)槲覀円猧nitialize所有backup 的信息。如果backup數(shù)據(jù)是在remote文件系統(tǒng)(比如HDFS)且有很多backup,那么初始化backup engine會(huì)消耗一額外的網(wǎng)絡(luò)傳輸時(shí)間。官方建議backup engine一直保持打開狀態(tài),不需要在每一次backup或者restore時(shí)都重新創(chuàng)建。
??另一種加速backup engine 初始化的方法就是刪除非必須的backup。可以通過調(diào)用PurgeOldBackups(N)函數(shù)要?jiǎng)h除backups,其中N表示要保留多少個(gè)backup。除了top N newest backups保留外,其他的都被刪除。用戶也可以調(diào)用DeleteBackup(id)來刪除任一個(gè)backup。
??要知道,backup性能是由從Local db中讀數(shù)據(jù)的速度和拷貝到backup目錄的速度共同決定的。盡管用戶可以使用不同的環(huán)境來讀數(shù)據(jù)和拷貝數(shù)據(jù),但是仍然可能存在讀寫瓶頸。比如,如果local db是HDD的話,盡管配置了更多的線程來做backup,但是未必就會(huì)有效果。這是因?yàn)榇藭r(shí)的性能瓶頸是磁盤的讀性能,很有可能早就已經(jīng)飽和了。一個(gè)低配的HDFS集群也不能提供好的并行性能。但是,如果local db是SSD且backup目標(biāo)是在高性能的HDFS上的話,配置更多的線程往往會(huì)有收益。在RocksDB官方的benchmark里,配16個(gè)線程與單線程相比,前者的backup time是后者的1/3。

Under the hood

當(dāng)調(diào)用BackupEngine::CreateNewBackup()時(shí)會(huì)做以下工作:

  • 1、禁止文件刪除
  • 2、找到live files(table、current、options、manifest)
  • 3、copy live files到backup 目錄
  • 4、如果設(shè)置了flush_before_backup為false,需要拷貝log files到backup 目錄??梢哉{(diào)用GetSortedWalFiles()然后拷貝到備份目錄。
  • 5、重新允許文件刪除

Advanced usage

??RocksDB支持將用戶自定義的metadata數(shù)據(jù)保存在backup中。調(diào)用BackupEngine::CreateNewBackupWithMetadata()函數(shù)可以創(chuàng)建backup并保存Metadata,后續(xù)可以調(diào)用BackupEngine::GetBackupInfo()來讀取Metadata。這可以用來根據(jù)backup id查詢meta信息來區(qū)分不同的backup。
??RocksDB也支持備份和恢復(fù)options file。在恢復(fù)數(shù)據(jù)后,可以調(diào)用ocksdb::LoadLatestOptions() or rocksdb:: LoadOptionsFromFile()接口來從db目錄中l(wèi)oad配置信息。有個(gè)限制就是,并不是options 對(duì)象中的每個(gè)配置都可以轉(zhuǎn)為text存儲(chǔ)在文件中,在restore結(jié)束后加載options時(shí),用戶需要手動(dòng)執(zhí)行一些步驟來加載這些特殊的option信息。
??備份時(shí),需要實(shí)例化一些環(huán)境變量和初始化BackupableDBOptions::backup_env。設(shè)置backup root dir(BackupableDBOptions::backup_dir)。在backup目錄中,文件會(huì)按照上述所示的結(jié)構(gòu)組織在一起。

  • BackupableDBOptions::share_table_files
    這個(gè)配置控制著多個(gè)backup是否是遞增完成的。如果設(shè)置為true的話,SST file都會(huì)存儲(chǔ)在shred/目錄下。如果不同的SST file具有相同名字的話,有可能會(huì)發(fā)生沖突(比如,多個(gè)數(shù)據(jù)庫(kù)有相同的backup目錄)。
  • BackupableDBOptions::share_files_with_checksum
    這個(gè)配置控制著shared files是怎么被識(shí)別的。如果設(shè)置為true的話,shared files是通過checksum、size和序列號(hào)來區(qū)分的。這樣如果多個(gè)數(shù)據(jù)庫(kù)配置了相同的backup目錄的話,就會(huì)避免文件名沖突問題。
  • BackupableDBOptions::max_background_operations
    這個(gè)參數(shù)配置了在backup和restore期間,有多少個(gè)線程用于copy文件。對(duì)于HDFS等分布式分解系統(tǒng),可以通過并行copy提高性能。
  • BackupableDBOptions::info_log
    是一個(gè)Logger object用來打印LOG 信息。

??如果BackupableDBOptions::sync設(shè)置為true的話,RocksDB會(huì)在每一次文件寫時(shí)調(diào)用fsync來同步文件數(shù)據(jù)和meta數(shù)據(jù)到磁盤,這樣可以保證如果服務(wù)器宕機(jī)后重啟的話,backups是滿足數(shù)據(jù)一致性的。如果設(shè)置為false的話,可能會(huì)提高一點(diǎn)點(diǎn)性能,但是會(huì)引起backup的不一致問題。盡管如下,絕大部分情況下,還是沒有問題的。
??如果設(shè)置了BackupableDBOptions::destroy_old_data為true的話,創(chuàng)建一個(gè)新的BackupEngine時(shí)會(huì)刪除所有老的backup數(shù)據(jù)。
??BackupEngine::CreateNewBackup() 方法會(huì)有一個(gè)flush_before_backup參數(shù),默認(rèn)為false。如果這個(gè)參數(shù)為true的話,BackupEngine會(huì)首先執(zhí)行一次memtable flush,然后只拷貝DB files 到backup 目錄,不會(huì)拷貝log files到backup目錄的原因是因?yàn)閒lush操作最終會(huì)觸發(fā)并刪除這些log file。如果這個(gè)參數(shù)設(shè)置為false的話,在開始backup時(shí),BackupEngine不會(huì)執(zhí)行flush操作。這種情況下,backup也會(huì)拷貝live memtable對(duì)應(yīng)的log files。不管這個(gè)參數(shù)為true還是false,backup都會(huì)和數(shù)據(jù)庫(kù)的當(dāng)前狀態(tài)保持一致性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第一天 7月13日OCP筆記: Oracle Ocp11g準(zhǔn)備資料: OracleFundmentals 書 管理...
    fjxCode閱讀 2,880評(píng)論 0 4
  • 背景: 閱讀新聞 12C CDB模式下RMAN備份與恢復(fù) [日期:2016-11-29] 來源:Linux社區(qū) 作...
    陽(yáng)屯okyepd閱讀 3,833評(píng)論 0 7
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,284評(píng)論 2 89
  • 1.成功辦理全家人的證件,妥妥的,很快的,錢錢也花的很快,半個(gè)月之后就可以領(lǐng)證啦。這主要還是靠老公的關(guān)系,所以多認(rèn)...
    linda的studio閱讀 144評(píng)論 0 1
  • 雖然文案和策劃的差異巨大,但很多市場(chǎng)部通常只設(shè)一個(gè)崗位——文案策劃,文案和策劃全丟給一個(gè)人做,結(jié)果導(dǎo)致策略和文案傻...
    Hazel_446a閱讀 1,370評(píng)論 0 1

友情鏈接更多精彩內(nèi)容