备份接口
BackupEngine是管理备份数据库目录的对象,具有创建、还原、删除和检查备份数据库的功能。磁盘格式特定于 BackupEngine,因此 (a) 即使没有硬链接,也可以在备份之间共享文件,并且 (b) 额外的元数据可以与备份相关联,以实现数据完整性和其他目的。C++ API 位于(不幸的旧名称)中。include/rocksdb/utilities/backupable_db.h
BackupEngine 的一个关键功能是将备份从一个抽象到另一个抽象,例如从本地文件系统到不是通过操作系统抽象提供的远程文件系统。写入受可配置线程的约束,可以使用许多线程。计算校验和是为了增加数据完整性,当数据库将整个文件校验和与 一起使用时,可提供最佳数据完整性。FileSystemRateLimiterfile_checksum_gen_factory
BackupEngine 是线程安全的(尽管并非总是如此),但如果同时从多个 BackupEngine 对象访问备份目录,则应用复杂的安全规则。(请参阅 API 文档。 在无意写入时提供更安全的抽象。BackupEngineReadOnly
创建和验证备份
在 RocksDB 中,我们实现了一种简单的方法来备份您的数据库并验证正确性。下面是一个简单的示例:
#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”中创建几个备份。请注意,您可以使用同一引擎创建和验证多个备份。
备份通常是增量备份(请参阅)。您可以使用 创建新备份,并且只有新数据将被复制到备份目录(有关复制内容的更多详细信息,请参阅幕后)。BackupableDBOptions::share_table_filesBackupEngine::CreateNewBackup()
保存一些备份后,您可以发出调用以获取所有备份的列表以及有关每个备份的时间戳和逻辑大小的信息。可以选择返回文件详细信息,从中可以确定共享详细信息。 甚至提供了一种以只读数据库形式就地打开备份的方法,这对于检查确切状态等非常有用。备份通过简单的递增整数 ID 进行标识,这些整数 ID 可以在创建新备份时保存在输出参数中,也可以从 中获取。BackupEngine::GetBackupInfo()GetBackupInfo()GetBackupInfo()
调用时,它会根据从原始数据库目录记录的预期大小检查备份目录中的文件大小。校验和验证是可选的,但需要读取所有数据。无论哪种情况,目的都是在备份创建期间检查某种安静故障或之后的意外损坏。 实质上对每个备份执行不带校验和的 ,以确定是否将其归类为损坏。BackupEngine::VerifyBackup()BackupEngine::Open()VerifyBackup()
还原备份
恢复也很容易:
#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());
s = backup_engine->RestoreDBFromBackup(1, "/tmp/rocksdb", "/tmp/rocksdb");
assert(s.ok());
delete backup_engine;
}
此代码会将第一个备份恢复回“/tmp/rocksdb”。第一个参数是备份 ID,第二个是目标数据库目录,第三个是日志文件的目标位置(在某些数据库中,它们与数据库目录不同,但通常它们是相同的。有关详细信息,请参阅选项::wal_dir)。 将从最新备份(即具有最高 ID 的备份)还原数据库。BackupEngineReadOnly::RestoreDBFromBackup()BackupEngineReadOnly::RestoreDBFromLatestBackup()
为任何还原的文件计算校验和,并与备份期间存储的文件进行比较。如果检测到校验和不匹配,还原过程将中止并返回。Status::Corruption
备份目录结构
/tmp/rocksdb_backup/
├── meta
│ └── 1
├── private
│ └── 1
│ ├── CURRENT
│ ├── MANIFEST-000008
| └── OPTIONS-000009
└── shared_checksum
└── 000007_1498774076_590.sst
meta目录包含一个描述每个备份的“元文件”,其中其名称是备份 ID。例如,图元文件包含属于该备份的所有文件的列表。该格式在实现文件 () 中进行了完整描述。utilities/backupable/backupable_db.cc
private目录始终包含非 SST/blob 文件(选项、当前、清单和 WAL)。如果未设置,它还包含 SST/blob 文件。Options::share_table_files
shared_checksum目录包含 SST/blob 文件(如果两者都设置为 和)。在此目录中,文件使用其在原始数据库中的名称、大小和校验和来命名。这些属性唯一标识可能来自多个 RocksDB 实例的文件。Options::share_table_filesOptions::share_files_with_checksum
已弃用:目录(未显示)在设置时包含 SST 文件,并且为 false。在此目录中,文件仅按其在原始数据库中的名称命名。如果存在从最新版本以外的备份还原,即使仅备份单个数据库,这也可能导致损坏。sharedOptions::share_table_filesOptions::share_files_with_checksum
备份性能
请注意,备份引擎花费的时间与现有备份的数量成正比,因为我们初始化有关每个现有备份中的文件的信息。因此,如果您的目标是远程文件系统(如 HDFS),并且您有大量备份,那么由于所有网络往返,初始化备份引擎可能需要一些时间。我们建议保持备份引擎处于活动状态,而不是在每次需要执行备份或还原时都重新创建它。Open()
保持引擎快速初始化的另一种方法是删除不必要的备份。要删除不必要的备份,只需调用 ,其中 N 是您要保留的备份数。除N个最新备份外的所有备份都将被删除。您还可以选择通过调用删除任意备份。PurgeOldBackups(N)DeleteBackup(id)
还要注意,性能是通过从本地数据库读取并复制到备份来决定的。由于您可能使用不同的环境进行读取和复制,因此并行性瓶颈可能位于两端之一。例如,如果本地数据库位于 HDD 上,则使用更多线程进行备份(请参阅高级用法)将无济于事,因为这种情况的瓶颈是磁盘读取能力,该容量已饱和。同样,一个糟糕的小型 HDFS 集群无法显示良好的并行性。如果本地数据库位于 SSD 上并且备份目标是高容量 HDFS,这将非常有用。在我们的基准测试中,使用 16 个线程会将备份时间减少到单线程作业的 1/3。
引擎
创建备份是在检查点上构建的。调用 时,它将执行以下操作:BackupEngine::CreateNewBackup()
禁用文件删除
获取实时文件(包括表文件、当前文件、选项文件和清单文件)。
将实时文件复制到备份目录。由于表文件是不可变的,并且文件名是唯一的,因此我们不会复制备份目录中已存在的表文件。从版本 6.12 开始,我们基本上拥有 SST 文件的唯一标识符,在 SST 文件属性中使用文件编号和数据库会话 ID。选项、清单和当前文件始终复制到私有目录,因为它们不是不可变的。
如果设置为 false,我们还需要将日志文件复制到备份目录。我们调用并将所有实时文件复制到备份目录。flush_before_backupGetSortedWalFiles()
重新启用文件删除
高级用法
我们可以在备份中存储用户定义的元数据。将元数据传递给 ,然后稍后使用 .例如,这可用于使用与我们的自动递增 ID 不同的标识符来识别备份。BackupEngine::CreateNewBackupWithMetadata()BackupEngine::GetBackupInfo()
我们现在还备份和还原选项文件。恢复后,您可以使用 或 从数据库目录加载选项。限制是选项对象中的所有内容都不能转换为文件中的文本。还原和加载后,您仍然需要几个步骤来手动设置选项中缺少的项目。好消息是,您需要的比以前少得多。rocksdb::LoadLatestOptions()rocksdb:: LoadOptionsFromFile()
您需要实例化一些 env 并初始化backup_target。将备份根目录放在 中。在目录下,文件将以上述结构进行组织。BackupableDBOptions::backup_envBackupableDBOptions::backup_dir
BackupableDBOptions::max_background_operations控制在备份和还原期间用于复制文件的线程数。对于像 HDFS 这样的分布式文件系统,提高复制并行度是非常有益的。
BackupableDBOptions::info_log是一个记录器对象,用于打印出 LOG 消息(如果不是空)。请参阅记录器维基。
如果为 true,我们将在每次文件写入后使用将文件数据和元数据同步到磁盘,保证备份在重新启动或计算机崩溃后保持一致。将其设置为 false 会加快速度,但某些(较新的)备份可能不一致。不过,在大多数情况下,一切都应该没问题。BackupableDBOptions::syncfsync(2)
如果设置为 true,则新建将删除备份目录中的所有旧备份。BackupableDBOptions::destroy_old_dataBackupEngine
BackupEngine::CreateNewBackup()方法接受一个参数,默认情况下为 false。如果为 true,将首先发出内存表刷新,然后才将数据库文件复制到备份目录。这样做将防止将日志文件复制到备份目录(因为刷新会删除它们)。如果为 false,则在开始备份之前不会发出刷新。在这种情况下,备份还将包括与实时内存表相对应的日志文件。无论参数如何,备份都将与数据库的当前状态保持一致。flush_before_backupflush_before_backupBackupEngineflush_before_backupflush_before_backup
延伸阅读
有关实现,请参见。utilities/backupable/backupable_db.cc