RocksDB 5.1.2 版本发布详解:动态选项、外部文件摄取事件与可靠性修复
【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb
本篇技术指南围绕 RocksDB 5.1.2 官方发布说明展开,逐条解析该版本的三项 Public API 变更与两项 Bug 修复,并结合当前仓库源码(include/rocksdb/options.h、include/rocksdb/listener.h、db/db_impl/db_impl.cc、utilities/backup/backup_engine.cc等)印证其底层实现与调用链。读完本文,你将掌握delete_obsolete_files_period_micros的动态修改方法、OnExternalFileIngested事件监听器的正确用法,以及 2PC 场景下 checkpoint 一致性与文件复制 fsync 可靠性的设计要点,可直接对照源码验证 5.1.2 的每一处行为。
版本概览
RocksDB 5.1.2 是一个以 API 演进与稳定性修复为主的维护版本。官方发布说明(原文见 docs/_posts/2017-02-07-rocksdb-5-1-2-released.markdown)共包含两组变更:
- Public API Change(公共 API 变更):3 项,涉及动态选项、事件监听器与备份引擎的返回语义。
- Bug Fixes(缺陷修复):2 项,涉及 2PC 下 checkpoint 的事务一致性与文件复制后的持久化保证。
下文将逐条展开,每条均给出源码级佐证。
Public API 变更详解
1. 支持通过 SetDBOptions() 动态修改 delete_obsolete_files_period_micros
该选项控制过期(obsolete)文件的定期清理周期。RocksDB 中,被 compaction、flush 淘汰出作用域的文件并不会立即从磁盘删除,而是交由后台周期性任务清理,清理周期即由本选项决定。
源码定义位于 include/rocksdb/options.h:
// The periodicity when obsolete files get deleted. The default // value is 6 hours. The files that get out of scope by compaction // process will still get automatically delete on every compaction, // regardless of this setting // // Default: 6 hours // // Dynamically changeable through SetDBOptions() API. uint64_t delete_obsolete_files_period_micros = 6ULL * 60 * 60 * 1000000;关键信息:
- 默认值:6 小时(
6ULL * 60 * 60 * 1000000微秒)。选项单位为微秒(micros)。 - 含义辨析:文档注释明确指出,即使该周期未到,被 compaction 淘汰的文件在每次 compaction 结束时也会被自动清理,此选项控制的是除此之外的定期清理节奏。
- 动态可调:该选项被标记为
Dynamically changeable through SetDBOptions() API,即 5.1.2 之前它只能在打开数据库前通过Options设置,5.1.2 起可以在运行期通过SetDBOptions()调整,无需重启数据库。
动态修改的实现路径在 db/db_impl/db_impl.cc:DBImpl::SetDBOptions()先将用户传入的std::unordered_map<std::string, std::string>通过GetMutableDBOptionsFromStrings解析为MutableDBOptions,再逐项应用到mutable_db_options_。而实际的清理判断逻辑在 db/db_impl/db_impl_files.cc,其中会检查mutable_db_options_.delete_obsolete_files_period_micros是否为 0,用于决定是否执行完整清理(full purge)。
典型使用场景:当应用在运行期需要快速回收磁盘空间(例如临时触发全量 purge),可将该值动态调小或置 0;需要减少周期性清理带来的 I/O 波动时,则动态调大。调用方式:
rocksdb::DB* db; std::unordered_map<std::string, std::string> opt_map = { {"delete_obsolete_files_period_micros", "60000000"}, // 60 秒 }; db->SetDBOptions(opt_map);C API 也提供了对应的存取函数,见 include/rocksdb/c.h 的rocksdb_options_set_delete_obsolete_files_period_micros/rocksdb_options_get_delete_obsolete_files_period_micros。仓库测试中常见将该项设为0以强制“总是执行完整 purge”,例如 db/deletefile_test.cc、db/obsolete_files_test.cc,说明0是一个有明确语义的取值:表示始终清理、不做周期等待。
2. 新增 EventListener::OnExternalFileIngested 回调
5.1.2 为事件监听器体系新增了EventListener::OnExternalFileIngested:当IngestExternalFile()成功将外部文件导入数据库后,该回调会被触发。
接口声明位于 include/rocksdb/listener.h:
// A callback function for RocksDB which will be called after an external // file is ingested using IngestExternalFile. // // Note that the this function will run on the same thread as // IngestExternalFile(), if this function is blocked, IngestExternalFile() // will be blocked from finishing. virtual void OnExternalFileIngested( DB* /*db*/, const ExternalFileIngestionInfo& /*info*/) {}配套的数据结构ExternalFileIngestionInfo定义在 include/rocksdb/listener.h,向回调传递以下信息:
| 字段 | 含义 |
|---|---|
cf_name | 文件被导入到的列族(column family)名称 |
external_file_path | 数据库外部的文件路径 |
internal_file_path | 导入后数据库内部的文件路径 |
global_seqno | 分配给该文件中键的全局序列号 |
table_properties | 被导入表的表属性 |
两个需要特别注意的行为约束(源码注释明确说明):
- 回调与
IngestExternalFile()运行在同一线程; - 因此若回调执行阻塞操作,
IngestExternalFile()将无法完成返回——回调中不应做重计算或长时间阻塞的操作。
调用链的源码级验证:DBImpl::IngestExternalFile()在原子提交成功后,遍历每个 ingestion job,对未 drop 的列族调用NotifyOnExternalFileIngested(cfd, *job)(见 db/db_impl/db_impl.cc);该函数遍历files_to_ingest()中的每个文件,填充ExternalFileIngestionInfo(cf_name、external_file_path、internal_file_path、global_seqno、table_properties),然后逐一通知所有已注册的 listener(见 db/db_impl/db_impl.cc)。
典型使用场景:
- 在外部文件批量导入成功后,触发下游缓存失效、索引更新或元数据记录;
- 统计每次 ingest 的文件路径、序列号区间与表属性,用于审计或监控;
- 注意回调只在“添加文件成功”时触发,失败路径不会调用(源码中
if (!status.ok())分支直接返回,见 db/db_impl/db_impl.cc)。
仓库测试中对这一回调也有验证,例如 db/external_sst_file_test.cc 与 db/db_compaction_test.cc 均实现了OnExternalFileIngested用于断言导入行为。C API 侧同样暴露了对应的监听器实现(db/c.cc),便于 C 语言绑定使用。
3. BackupEngine 的 Open 错误语义对齐
5.1.2 规定:BackupEngine::Open与BackupEngineReadOnly::Open现在总是返回与备份环境(backup Env)一致的状态码。
即此前可能出现底层备份 Env 已失败、但 Open 返回的成功状态与之一致的情况,导致上层无法准确感知备份环境错误。5.1.2 起,两个入口的错误状态直接映射备份 Env 的错误状态,调用方可通过返回的Status可靠判断备份环境是否健康。
两个入口在仓库中的定义位置:
- utilities/backup/backup_engine.cc 的
BackupEngine::Open(const BackupEngineOptions& options, Env* env, BackupEngine** backup_engine) - utilities/backup/backup_engine.cc 的
BackupEngineReadOnly::Open(...)
对应的测试覆盖见 utilities/backup/backup_engine_test.cc,其中包含大量ASSERT_OK(BackupEngine::Open(...))与ASSERT_NOK(BackupEngine::Open(...))(例如 backup_engine_test.cc),用于验证不同环境下 Open 的成功/失败语义。
使用建议:调用方在 Open 后应先检查返回的Status,对Status::IOError()等非 OK 结果做降级处理,不要假设 Open 失败时对象一定为空。
Bug Fixes 详解
1. 修复 2PC 启用时 checkpoint 可能丢失部分近期事务的问题
当数据库启用了两阶段提交(2PC,Two-Phase Commit)时,存在事务先Prepare()写入 WAL、后Commit()的窗口期。5.1.2 修复的问题正是:在创建 checkpoint(checkpoint 本质是数据库目录的一致性快照,实现可参见 db/checkpoint/ 相关源码)时,如果只复制 memtable 与 SST 文件而未正确处理 WAL 中处于 prepared 状态的日志,可能导致 checkpoint 快照丢失部分最近提交/预备的事务。
修复的核心思路是保证 checkpoint 过程对 WAL 的截断与复制是安全的:checkpoint 创建时对 WAL 的处理必须覆盖到所有已 prepare 的事务日志,避免“截断了 WAL 但对应事务尚未提交/回滚”导致的数据缺失。这在实现上意味着 checkpoint 与 2PC 的 prepared transaction 跟踪机制(如 db/logs_with_prep_tracker.h 所维护的、关联了 prepared 事务的日志列表)需要协同,确保 checkpoint 里保留的 WAL 足以恢复所有未决事务。
对使用者的意义:
- 启用 2PC 的应用,在 5.1.2 之前若依赖 checkpoint 做恢复/迁移,存在丢失近期事务的隐患;
- 5.1.2 之后可放心将 checkpoint 与 2PC 结合使用,但仍建议在 checkpoint 创建后执行一致性校验。
2. 文件复制后执行 fsync,保证崩溃一致性
第二个修复与崩溃安全直接相关:当创建 checkpoint 或批量加载(bulk load)外部文件而需要复制文件时,文件复制完成后现在会对目标文件执行 fsync。
背景:在 Linux 等文件系统上,write()返回成功只代表数据进入页缓存,尚未落盘;若此时系统崩溃,文件内容可能不完整或缺失。如果 checkpoint 或 ingest 流程复制完文件后不 fsync,则该副本在断电/崩溃场景下可能是损坏的,随后被当作有效数据使用时会造成不可逆的数据错误。
修复后,db/db_impl/db_impl_files.cc 涉及文件复制/同步的路径会在复制完成后显式同步(源码中对应 WAL 与文件同步逻辑,如PrepareForSync/FinishSync及基于Sync的文件持久化处理,见 db/db_impl/db_impl_files.cc 一带)。这也是 RocksDB 一贯的持久化契约:所有关键文件在“对外可见”之前必须保证已落盘(fsync),从而在系统崩溃后仍能安全恢复。
使用建议:该修复属于透明行为改进,使用者无需改动代码;但若应用自身还依赖其他自定义文件复制逻辑,应同样遵循“复制完成后 fsync”的准则。
从 5.1.2 看 RocksDB 的 API 演进思路
纵观 5.1.2 的变更,可以提炼出三个持续至今的设计取向:
- 运行期可调优先:
delete_obsolete_files_period_micros纳入MutableDBOptions,意味着越来越多的数据库选项支持不重启即动态调整,SetDBOptions()是统一入口(实现见 db/db_impl/db_impl.cc)。 - 事件驱动扩展:
EventListener体系不断补充新回调(如本版的OnExternalFileIngested),把数据库内部的关键生命周期事件暴露给应用,用于构建监控、审计与联动逻辑。 - 崩溃一致性是底线:无论是 checkpoint 与 2PC 的协同,还是文件复制后的 fsync,都指向同一个目标——在任何故障场景下保证数据的可恢复性。
参考与延伸阅读
- 版本发布说明原文:docs/_posts/2017-02-07-rocksdb-5-1-2-released.markdown
- 动态选项定义与默认值:include/rocksdb/options.h
SetDBOptions实现:db/db_impl/db_impl.cc- 过期文件周期清理判断:db/db_impl/db_impl_files.cc
- 事件监听器接口与数据契约:include/rocksdb/listener.h、include/rocksdb/listener.h
- 外部文件摄取成功后的回调触发:db/db_impl/db_impl.cc、db/db_impl/db_impl.cc
- 备份引擎 Open 入口:utilities/backup/backup_engine.cc、utilities/backup/backup_engine.cc
- 相关测试:db/external_sst_file_test.cc、utilities/backup/backup_engine_test.cc
【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考