RocksDB 备份指南:BackupEngine 使用、原理与恢复实战

发布时间:2026/9/19 2:45:18
RocksDB 备份指南:BackupEngine 使用、原理与恢复实战
RocksDB 备份指南BackupEngine 使用、原理与恢复实战【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb导读RocksDB 作为嵌入式持久化键值存储引擎为开发者提供了内建的备份Backup与恢复Restore能力你只需几行代码即可把数据库的一致性快照增量地写入备份目录并在灾难发生时完整还原。本文以 RocksDB 官方备份文档为主线结合当前仓库中 include/rocksdb/utilities/backup_engine.h 的头文件定义与 utilities/backup/backup_engine.cc 的底层实现系统讲解两种备份 API 的用法、关键配置参数、备份与恢复的完整流程、校验与增量去重机制以及常见的高级用法帮助你安全地落地 RocksDB 的备份方案。一、五分钟上手两种备份方式RocksDB 的备份能力演进过程中形成了两种 API最早的BackupableDB包装器以及更推荐直接使用的BackupEngine。二者底层共享同一套实现当前仓库中为BackupEngineImpl见 utilities/backup/backup_engine_impl.h核心文件路径均为 utilities/backup/backup_engine.cc。方式一BackupableDB 包装器经典 API在早期版本中通过BackupableDB包装现有DB*即可获得备份能力创建备份只需三步#include rocksdb/db.h #include utilities/backupable_db.h using namespace rocksdb; DB* db; DB::Open(Options(), /tmp/rocksdb, db); BackupableDB* backupable_db new BackupableDB(db, BackupableDBOptions(/tmp/rocksdb_backup)); backupable_db-Put(...); // do your thing backupable_db-CreateNewBackup(); delete backupable_db; // no need to also delete db这段示例会把数据库备份到/tmp/rocksdb_backup。注意创建BackupableDB会接管传入的DB*之后所有数据库方法都应调用在backupable_db对象上同时删除backupable_db时不需要再单独delete db包装器负责回收底层 DB。方式二BackupEngine现代推荐 APIBackupableDB目前已不建议新代码使用现代 API 是独立的BackupEngine它不包装 DB 对象而是接受一个DB*参数来创建备份#include rocksdb/db.h #include utilities/backupable_db.h // 当前仓库中位于 include/rocksdb/utilities/backup_engine.h using namespace rocksdb; DB* db; DB::Open(Options(), /tmp/rocksdb, db); db-Put(...); // do your thing BackupEngine* backup_engine; BackupEngine::Open(BackupEngineOptions(/tmp/rocksdb_backup), Env::Default(), backup_engine); backup_engine-CreateNewBackup(db); delete db; delete backup_engine;在当前仓库中BackupEngine的Open静态方法定义在 include/rocksdb/utilities/backup_engine.h其签名支持新旧两种参数顺序以保持向后兼容。BackupEngine的实现位于 utilities/backup/backup_engine.cc接口类还细分为可读写的BackupEngine、只读的BackupEngineReadOnly与BackupEngineReadOnlyBase。注意头文件路径已从历史文档中的utilities/backupable_db.h迁移到当前仓库的include/rocksdb/utilities/backup_engine.h编写代码时以当前路径为准。二、恢复数据库恢复同样简单直接针对备份目录构造引擎并调用恢复方法RestoreBackupableDB* restore new RestoreBackupableDB( Env::Default(), BackupableDBOptions(/tmp/rocksdb_backup)); restore-RestoreDBFromLatestBackup(/tmp/rocksdb, /tmp/rocksdb); delete restore;使用现代 API 时BackupEngine* backup_engine; BackupEngine::Open(BackupEngineOptions(/tmp/rocksdb_backup), Env::Default(), backup_engine); backup_engine-RestoreDBFromLatestBackup(/tmp/rocksdb, /tmp/rocksdb); delete backup_engine;两个参数的含义分别是第一个参数db_dir数据库目录恢复后的数据文件落在这里第二个参数wal_dir日志WAL文件目录。多数场景下两者相同但若设置了Options::wal_dir将 WAL 与数据分离存放此处需要分别指定。恢复时的校验是强制性的恢复引擎会对每个恢复出来的文件重新计算校验和并与备份时记录的校验和比对一旦不匹配整个恢复过程会中止并返回Status::Corruption避免把损坏的数据写回数据库。恢复指定的备份而非最新备份RestoreDBFromLatestBackup()恢复最新的一致备份而RestoreDBFromBackup(backup_id, db_dir, wal_dir)可恢复指定 ID 的备份。此处有一个非常关键、容易踩坑的语义原文档特别强调假设你已有备份 1、2、3、4若你从备份 2 恢复数据库、继续写入新数据并创建新备份则旧备份 3 和 4 会被删除新备份直接以备份 2 为基础在 ID 3 的位置上重建。原因在于备份采用增量去重共享文件策略后续备份依赖前面的文件破坏该链条会导致文件被误判为无用而回收因此从中间版本恢复后继续备份会触发对更新备份的清理。三、备份管理查询、删除与增量机制增量备份与校验备份是增量的。每次调用CreateNewBackup()只会把新数据拷贝到备份目录。对于任何被备份的文件包括 SST、WAL 日志等引擎都会计算校验和CRC32C以确保文件在文件系统中的完整性对于已存在于备份目录、本次无需复制的历史文件同样会重新计算校验和并与历史记录比对防止备份目录中的文件悄悄损坏。一旦发现校验和不匹配当前备份会直接中止并把系统回滚到调用CreateNewBackup()之前的状态详见下文Under the hood。需要说明的是校验失败可能是备份目录中的文件损坏也可能是当前数据库中对应文件损坏两者需要结合日志进一步甄别。查询备份列表当备份数量增多后可调用GetBackupInfo()获取全部备份的信息列表包括备份 IDbackup_id始终递增用于标识每个备份创建时间戳timestamp备份大小size。注意原文档的提醒所有备份大小之和会大于备份目录的实际占用空间因为多个备份共享了部分数据文件去重size统计的是每个备份逻辑上包含的文件大小。在现代 API 中GetBackupInfo返回std::vectorBackupInfo还支持传入include_file_detailstrue获取每个备份的文件级明细见 include/rocksdb/utilities/backup_engine.h。清理旧备份通常你只需要保留少量备份调用PurgeOldBackups(N)即可保留最新的 N 个备份并删除其余所有旧备份也可以调用DeleteBackup(id)删除任意指定 ID 的备份。这两个操作在现代 API 中定义于BackupEngine接口include/rocksdb/utilities/backup_engine.h。如果删除操作因崩溃或断电而中断下一次调用DeleteBackup、PurgeOldBackups或GarbageCollect时会自动清理残留状态GarbageCollect的定义见 include/rocksdb/utilities/backup_engine.h。四、BackupEngineOptions 关键配置无论是BackupableDBOptions还是现代BackupEngineOptions核心字段基本一致完整定义见 include/rocksdb/utilities/backup_engine.h配置项默认值说明backup_dir必填备份文件存放目录必须与数据库目录不同官方建议设为dbname /backupsbackup_envnullptr用于备份目录所有文件 I/O 的Env备份时写入、恢复时读取。设为 HDFS Env 即可把备份存到 HDFS实现跨机器容灾share_table_filestrue是否让多个备份共享表SST与 blob 文件以节省空间并支持增量备份设为false时每个备份完全独立、互不共享数据synctrue每次文件写入后是否fsync落盘。为true时保证机器重启/崩溃后备份仍一致为false时速度快一些但较新的备份可能不一致destroy_old_datafalse为true时创建引擎即删除备份目录中所有旧备份backup_log_filestrue是否备份日志文件。对于表文件在内存、WAL 落盘的内存数据库可设为false跳过日志备份restore_rate_limit0恢复期间每秒最大传输字节数0表示不限速仅限制写入若还想限制读取需通过restore_rate_limiter传入支持读限速的 RateLimitercallback_trigger_interval_size4194304备份进度回调触发间隔字节数4 MiB配合CreateBackupOptions::progress_callback上报进度max_valid_backups_to_openINT_MAX只读引擎Open时最多打开多少个最新且未损坏的备份此外还有几个值得关注的高级字段share_files_with_checksum默认true仅在share_table_filestrue时生效。该字段用于区分不同历史来源的同编号 SST 文件防止从非最新备份恢复后继续写入并创建新备份这类场景下发生数据丢失不建议设为false已标记为 DEPRECATED 且有风险。share_files_with_checksum_naming共享文件的命名方案。默认kUseDbSessionId | kFlagIncludeFileSize利用 DB session id 保证文件名强唯一且无需先读文件算校验和kLegacyCrc32cAndFileSize为旧版命名仅在兼容旧行为时使用。schema_version备份元数据文件的 schema 版本1兼容非常老的 RocksDB2需要 RocksDB 6.19.0且是保存/恢复文件温度元数据实验特性的最低版本要求。高级用法补充备份到 HDFSBackupableDBOptions::backup_env或BackupEngineOptions::backup_env指定 HDFS Env 后所有备份写入与恢复读取都走该 Env备份即可整体落在 HDFS 上。日志输出info_logLogger*类型非空时用于打印备份相关的 LOG 信息便于排查问题。一致性保证synctrue可保证机器崩溃/重启后备份仍然一致syncfalse时只能保证之前已完成同步的备份与恢复不被本次操作破坏较新备份存在不一致风险。备份前刷盘CreateNewBackup(flush_before_backup)的flush_before_backup参数默认false。为true时引擎先触发 memtable flush 再拷贝文件这样 WAL 日志不会被拷入备份目录flush 后日志被删除为false时备份会包含对应活 memtable 的日志文件。无论该参数取值如何备份都与数据库当前状态一致。现代 API 中该参数位于CreateBackupOptions::flush_before_backupinclude/rocksdb/utilities/backup_engine.h并补充了边界情况2PC 开启时必然触发 flush关闭 WAL 时需设flush_before_backuptrue以免丢失 memtable 中未落盘的数据。备份附加元数据CreateNewBackupWithMetadata()可在备份时携带应用自定义元数据app_metadata查询BackupInfo时一并返回。备份进度与停止progress_callback按callback_trigger_interval_size字节间隔回调进度StopBackup()可异步请求中止正在进行的备份返回Status::Incomplete中止后该引擎实例不可再创建备份需重新Open。五、Under the hood备份流程内部原理BackupableDB实现了DB接口并在其上增加了四个方法CreateNewBackup()、GetBackupInfo()、PurgeOldBackups()、DeleteBackup()所有其他DB接口调用都会被转发给底层DB对象。在现代实现中这些逻辑统一收敛到BackupEngineImpl实现文件 utilities/backup/backup_engine.ccCreateNewBackupWithMetadata入口在 utilities/backup/backup_engine.cc。一次CreateNewBackup()调用大致经历以下步骤禁用文件删除db-DisableFileDeletions()见 utilities/backup/backup_engine.cc防止备份过程中后台 compaction 等操作删除正在被读取的文件。获取存活文件列表live files包括表文件SST、CURRENT与MANIFEST文件。拷贝存活文件到备份目录由于表文件不可变且文件名唯一若备份目录中已存在同名文件如00050.sst则跳过复制。但无论是否需要复制都会对所有文件计算校验和已存在文件的校验和会与历史记录比对发现不匹配立即中止备份并回滚到调用前状态。需要注意的是中止可能源于备份目录文件损坏也可能源于当前数据库中对应文件损坏。由于MANIFEST与CURRENT文件不是不可变的它们总是被复制。若flush_before_backupfalse还需拷贝日志文件调用GetSortedWalFiles()取得所有存活 WAL 文件并复制到备份目录。重新启用文件删除db-EnableFileDeletions()见 utilities/backup/backup_engine.cc。崩溃恢复与 LATEST_BACKUP 文件备份 ID 始终递增备份目录中存在LATEST_BACKUP文件记录最新备份的 ID。如果在备份过程中崩溃重启时会发现备份目录中存在比LATEST_BACKUP更新的文件此时引擎会删除所有比LATEST_BACKUP更新的备份并清理相关文件——因为备份中断时部分表文件可能是损坏的而基于去重共享策略备份目录里残留的损坏表文件是危险的后续增量备份可能误认为文件已存在而跳过复制。通过元数据文件backup_meta记录每个备份的文件清单与校验和引擎才能准确地判断哪些文件属于哪个备份、是否可以安全共享相关读写逻辑见 utilities/backup/backup_engine.cc。并发与只读引擎现代BackupEngine自 6.20 起整体线程安全内部使用读写锁读操作之间可并发追加/写操作之间互斥同一backup_dir上建议只打开一个引擎实例混用多个实例时某些组合行为未定义。需要说明的是destroy_old_datatrue的Open实质是一次写操作。若仅需读取/恢复备份如从备份机读取可使用只读变体BackupEngineReadOnly其Open不会对备份目录做任何写操作。六、测试验证与进一步阅读仓库中针对备份引擎有详尽的测试用例可用于验证本文描述的行为utilities/backup/backup_engine_test.cc 包含大量TEST_F(BackupEngineTest, ...)用例如FileCollisionbackup_engine_test.cc验证不同历史来源的同名文件在去重策略下不会互相污染、BackupWithMetadatabackup_engine_test.cc验证附加元数据的备份/恢复、DeleteTmpFilesbackup_engine_test.cc验证临时文件清理。关于接口细节可查阅 include/rocksdb/utilities/backup_engine.h关于实现细节可深入阅读 utilities/backup/backup_engine.cc 与 utilities/backup/backup_engine_impl.h。另外 examples/rocksdb_backup_restore_example.cc 提供了一个可直接编译运行的备份/恢复完整示例适合作为上手参考Java 绑定示例可参考 java/rocksjni/backupenginejni.cc。结语RocksDB 的备份体系以增量 去重 校验为核心增量复制只传新文件、跨备份共享表文件以节省空间、每次备份与恢复都做 CRC32C 校验保证数据完好配合LATEST_BACKUP元数据实现崩溃后的自愈清理。实际使用中建议开启synctrue保证崩溃一致性、保留少量备份并通过PurgeOldBackups定期清理同时利用backup_env把备份放置到独立存储如 HDFS以实现真正的容灾目标。【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考