Backup API
c++ api,請參考:include/rocksdb/utilities/backupable_db.h。核心模塊是backup engine,其暴露了創建backup的簡單接口、查詢backup的相關信息以及從backup中恢復數據。backup engine主要有以下形式:1) 創建backup的BackupEngine 2)從backup恢復數據的BackupEngineReadOnly。每個engine都可以用來查詢backup的信息。
Creating and verifying a backup
RocksDB實現了一種backup DB的簡單方式,還可以對backup做正確性校驗。下面是一個簡單示例:
#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;
}
??例子中會對/tmp/rocksdb_backup數據創建兩個backup。用戶可以使用相同的backup engine來創建和校驗多個backup。
??正常情況下,backup數據是遞增的(參考BackupableDBOptions::share_table_files)。用戶可以使用BackupEngine::CreateNewBackup() 創建一個新的backup,且只有新增的數據才會copy到backup 目錄中。
??如果你已經保存了一些backup,就可以調用BackupEngine::GetBackupInfo()來查詢所有的backup信息。每一個backup都有一個遞增的ID來標識。
??當調用BackupEngine::VerifyBackups()時,會check backup目錄中文件的大小,并與db目錄中相應的文件對比。但是,并不會對文件的checksum進行校驗,因為這樣需要讀取所有的文件數據。調用BackupEngine::VerifyBackups()接口進行校驗唯一適用的場景就是在執行完create backup之后,因為校驗邏輯中使用了backup期間的一些狀態信息。
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;
}
示例中會把第一個backup數據恢復到/tmp/rocksdb。BackupEngineReadOnly::RestoreDBFromBackup()的第一個參數是backup ID,第二個參數是目標DB目錄,第三個參數是日志文件的目標位置目錄(DB目錄和LOG目錄可以不一致)。BackupEngineReadOnly::RestoreDBFromLatestBackup()接口會從最新的backup(ID最大的backup)中恢復數據到DB。恢復期間,會計算所有存儲文件的checksum,并與backup期間存儲的checksum值對比。如果檢測到checksum不匹配,就會中斷restore過程,返回Status::Corruption。如果要查詢恢復的數據,需要打開所有恢復成功的數據庫。
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是一個記錄了最大backup id的文件。這個文件用來查詢最大的backup id,由于META信息中也包含了這個最大id,所以在RocksDB 5.0版本之后就刪除了這個文件。
??meta目錄包含了meta文件,對應地記錄了每一個backup的描述信息,文件名就是backup id。如果有三個backup分別為1、2、3,那么這個目錄中就包含了文件名為1、2、3的文件,記錄了對應backup的信息。
??private目錄有non-SST 文件,主要是options,current,manifest和WAL。如果不設置Options::share_table_files,那么SST file也會在這個目錄中。
??shared目錄包含了SSTfile(前提是設置了Options::share_table_files且Options::share_files_with_checksum未設置)。在這個目錄中文件與db目錄中的文件名相同。所以所以,在這種情況下,只能備份單個RocksDB實例,否則文件名會沖突。
??shared_checksum目錄中包含了SST files(前提是設置了Options::share_table_files和Options::share_files_with_checksum)。文件名以DB目錄中的文件名、size和checksum組成。這個文件名是唯一的,可以來自不同的RocksDB實例。
Backup performance
??backup engine的open函數的耗時與當前存在的backup的數目是正相關的,因為我們要initialize所有backup 的信息。如果backup數據是在remote文件系統(比如HDFS)且有很多backup,那么初始化backup engine會消耗一額外的網絡傳輸時間。官方建議backup engine一直保持打開狀態,不需要在每一次backup或者restore時都重新創建。
??另一種加速backup engine 初始化的方法就是刪除非必須的backup。可以通過調用PurgeOldBackups(N)函數要刪除backups,其中N表示要保留多少個backup。除了top N newest backups保留外,其他的都被刪除。用戶也可以調用DeleteBackup(id)來刪除任一個backup。
??要知道,backup性能是由從Local db中讀數據的速度和拷貝到backup目錄的速度共同決定的。盡管用戶可以使用不同的環境來讀數據和拷貝數據,但是仍然可能存在讀寫瓶頸。比如,如果local db是HDD的話,盡管配置了更多的線程來做backup,但是未必就會有效果。這是因為此時的性能瓶頸是磁盤的讀性能,很有可能早就已經飽和了。一個低配的HDFS集群也不能提供好的并行性能。但是,如果local db是SSD且backup目標是在高性能的HDFS上的話,配置更多的線程往往會有收益。在RocksDB官方的benchmark里,配16個線程與單線程相比,前者的backup time是后者的1/3。
Under the hood
當調用BackupEngine::CreateNewBackup()時會做以下工作:
- 1、禁止文件刪除
- 2、找到live files(table、current、options、manifest)
- 3、copy live files到backup 目錄
- 4、如果設置了flush_before_backup為false,需要拷貝log files到backup 目錄。可以調用GetSortedWalFiles()然后拷貝到備份目錄。
- 5、重新允許文件刪除
Advanced usage
??RocksDB支持將用戶自定義的metadata數據保存在backup中。調用BackupEngine::CreateNewBackupWithMetadata()函數可以創建backup并保存Metadata,后續可以調用BackupEngine::GetBackupInfo()來讀取Metadata。這可以用來根據backup id查詢meta信息來區分不同的backup。
??RocksDB也支持備份和恢復options file。在恢復數據后,可以調用ocksdb::LoadLatestOptions() or rocksdb:: LoadOptionsFromFile()接口來從db目錄中load配置信息。有個限制就是,并不是options 對象中的每個配置都可以轉為text存儲在文件中,在restore結束后加載options時,用戶需要手動執行一些步驟來加載這些特殊的option信息。
??備份時,需要實例化一些環境變量和初始化BackupableDBOptions::backup_env。設置backup root dir(BackupableDBOptions::backup_dir)。在backup目錄中,文件會按照上述所示的結構組織在一起。
- BackupableDBOptions::share_table_files
這個配置控制著多個backup是否是遞增完成的。如果設置為true的話,SST file都會存儲在shred/目錄下。如果不同的SST file具有相同名字的話,有可能會發生沖突(比如,多個數據庫有相同的backup目錄)。 - BackupableDBOptions::share_files_with_checksum
這個配置控制著shared files是怎么被識別的。如果設置為true的話,shared files是通過checksum、size和序列號來區分的。這樣如果多個數據庫配置了相同的backup目錄的話,就會避免文件名沖突問題。 - BackupableDBOptions::max_background_operations
這個參數配置了在backup和restore期間,有多少個線程用于copy文件。對于HDFS等分布式分解系統,可以通過并行copy提高性能。 - BackupableDBOptions::info_log
是一個Logger object用來打印LOG 信息。
??如果BackupableDBOptions::sync設置為true的話,RocksDB會在每一次文件寫時調用fsync來同步文件數據和meta數據到磁盤,這樣可以保證如果服務器宕機后重啟的話,backups是滿足數據一致性的。如果設置為false的話,可能會提高一點點性能,但是會引起backup的不一致問題。盡管如下,絕大部分情況下,還是沒有問題的。
??如果設置了BackupableDBOptions::destroy_old_data為true的話,創建一個新的BackupEngine時會刪除所有老的backup數據。
??BackupEngine::CreateNewBackup() 方法會有一個flush_before_backup參數,默認為false。如果這個參數為true的話,BackupEngine會首先執行一次memtable flush,然后只拷貝DB files 到backup 目錄,不會拷貝log files到backup目錄的原因是因為flush操作最終會觸發并刪除這些log file。如果這個參數設置為false的話,在開始backup時,BackupEngine不會執行flush操作。這種情況下,backup也會拷貝live memtable對應的log files。不管這個參數為true還是false,backup都會和數據庫的當前狀態保持一致性。