RocksDB 远程压缩并发 MANIFEST 轮转导致的打开失败:OpenAndCompact 重试机制解析
RocksDB 远程压缩并发 MANIFEST 轮转导致的打开失败OpenAndCompact 重试机制解析【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb导读本文讲解 RocksDB 远程压缩CompactionService/DB::OpenAndCompact在 worker 以只读方式打开 primary 目录时因 primary 并发轮转CURRENT/MANIFEST 文件而偶发失败的问题以及 RocksDB 为此引入的“secondary 打开有限次重试”修复方案。读完本文你将理解该竞态产生的文件系统语义背景、Status::TryAgain/PathNotFound/NotFound三类瞬态错误的含义、OpenAndCompactOptions::max_secondary_open_retries参数的正确用法以及这一修复与remote_compaction_manifest_floor加固机制的关系。本文以 unreleased_history/bug_fixes/remote_compaction_secondary_open_retry.md 为骨架并结合 db/db_impl/db_impl_secondary.cc 与 include/rocksdb/options.h 等源码展开。一、问题背景远程压缩如何打开 primary 目录1.1 远程压缩的基本流程RocksDB 的CompactionService允许把压缩任务卸载到另一台主机或另一个进程执行从而把 primary 上的后台负载转移出去。核心入口是DB::OpenAndCompact()它“以只读方式打开数据库并执行压缩且不修改原始 DB”压缩结果输出到源数据库目录下的子目录而非安装回原 LSM 树。相关声明见 include/rocksdb/db.h。从 db/db_impl/db_impl_secondary.cc 的实现看OpenAndCompact()的执行分为几个明确步骤反序列化压缩输入CompactionServiceInput::Read()从input中恢复 primary 序列化好的压缩任务信息目标 CF、输入文件等加载选项通过LoadOptionsFromFile()读取 primary 的 OPTIONS 文件OptionsFileName(name, compaction_input.options_file_number)再以CompactionServiceOptionsOverride覆盖相关配置确定输出目录RemoteCompactionJobDir()依据use_session_tmp_dir_for_remote_compaction决定输出路径是name/session_tmp/output_directory还是name/output_directory过滤列族只打开 default CF 与目标 CF因为远程压缩只需 MANIFEST 中的 LSM 状态无需 WAL 重放以 secondary 方式打开 primary 目录跳过 WAL 恢复随后在该视图上执行压缩。1.2 secondary 打开与 MANIFEST 跟踪关键在第 5 步worker 调用DBImplSecondary::OpenAsSecondaryImpl()打开primary 的实时目录只读。secondary 依赖ReactiveVersionSet跟踪 primary 的 MANIFEST 演进其中MaybeSwitchManifest()见 db/version_set.cc负责在发现CURRENT指向新 MANIFEST 时切换文件句柄。二、竞态根源无 read-after-unlink 语义的文件系统2.1 primary 如何轮转 MANIFEST每次 MANIFEST 轮转primary 都会写出新的 MANIFEST 文件把新写入的CURRENT文件rename 覆盖到旧的CURRENT之上完成指针切换视清理策略删除旧 MANIFEST。对运行中的 secondary 而言它可能正处于“读CURRENT→ 打开对应 MANIFEST”的窗口期内于是出现两种经典竞态读取CURRENT时拿到了旧值随后旧 MANIFEST 被 primary 删除再打开文件即失败读取CURRENT后 primary 立刻切换旧 MANIFEST 被删除打开时同样失败。2.2 POSIX 与远程/对象存储的语义差异在 POSIX 文件系统上“打开之后删除/替换”是安全的已打开的文件描述符仍可继续读取未打开但刚被 rename 覆盖的文件路径在删除前也有一段可用窗口这就是 “read-after-unlink” 语义。但远程/对象存储remote/object stores不具备该语义被替换的对象会立即被报告为“不存在”。于是 secondary 打开时得到的不再是“文件不可读但进程可继续”而是明确的错误状态状态触发场景Status::PathNotFound打开CURRENT或 MANIFEST 时目标对象已不存在文件系统层的PathNotFoundStatus::NotFound同样的“对象已消失”在另一条路径上的等价表现Status::TryAgainMANIFEST 层面的专门映射见下文MaybeSwitchManifest()MaybeSwitchManifest()中专门做了这种映射当FileExists返回IsNotFound或打开 MANIFEST 返回IsPathNotFound时统一构造Status::TryAgain(The primary may have switched to a new MANIFEST and deleted the old one.)见 db/version_set.cc把“primary 可能刚切换 MANIFEST 并删除了旧文件”这一瞬态竞态显式暴露出来。2.3 为什么这是瞬态而不是损坏关键在于这只是读取时机撞上了轮转窗口并不是数据库损坏。下一次尝试读取时CURRENT已指向新 MANIFEST打开即可成功。因此正确做法不是报错而是在有限次数内重试。三、修复方案max_secondary_open_retries有限重试3.1 参数定义修复为OpenAndCompactOptions新增了max_secondary_open_retries字段声明位于 include/rocksdb/options.hstruct OpenAndCompactOptions { // Allows cancellation of an in-progress compaction. std::atomicbool* canceled nullptr; // Maximum number of times to retry opening the source DB as a secondary // after the initial attempt fails because CURRENT or MANIFEST was replaced // concurrently. A value of zero disables retries. // // Default: 2 uint32_t max_secondary_open_retries 2; // ... allow_resumption 等其余字段 };参数语义默认值为 2即初始尝试之外最多再重试 2 次共最多 3 次尝试设为 0 表示完全禁用重试保持旧行为一次失败即返回仅对瞬态的打开失败生效见下方状态过滤逻辑。3.2 重试逻辑的源码实现重试循环位于 db/db_impl/db_impl_secondary.ccfor (uint32_t retry_count 0;; retry_count) { s DBImplSecondary::OpenAsSecondaryImpl( db_options, name, output_path, column_families, handles, db, /*recover_wal*/false, /*trust_manifest_recovery*/floor_provided); if (s.ok() || !(s.IsTryAgain() || s.IsPathNotFound() || s.IsNotFound()) || retry_count options.max_secondary_open_retries) { break; } ROCKS_LOG_WARN(db_options.info_log, OpenAndCompact: secondary open of %s failed with %s (retry % PRIu32 of % PRIu32 ); the primary may have replaced CURRENT/MANIFEST concurrently, retrying, name.c_str(), s.ToString().c_str(), retry_count 1, options.max_secondary_open_retries); }逻辑要点每次循环调用OpenAsSecondaryImpl()执行一次 secondary 打开跳过 WAL 恢复因为远程压缩只需要 MANIFEST 里的 LSM 状态只有Status::TryAgain、Status::PathNotFound、Status::NotFound三类瞬态状态才会触发重试其他错误如损坏、权限问题、配置错误立即返回不会被重试掩盖重试次数达到max_secondary_open_retries后停止把最后一次的错误状态返回给调用方每次重试前输出一条ROCKS_LOG_WARN级别的日志包含失败状态与“第几次/共几次重试”信息便于在线上定位此类竞态发生的频率。注意循环条件中retry_count options.max_secondary_open_retries时也会 break配合循环后对s.ok()的判断保证重试次数严格有界。3.3 配套计时统计打开过程整体耗时被记录到OPEN_AND_COMPACT_DB_OPEN_MICROS直方图db/db_impl/db_impl_secondary.cc对应 include/rocksdb/statistics.h 中“Time spent opening the secondary DB insideDB::OpenAndCompact()”的说明。运维者可通过该指标观察重试对打开耗时的实际影响。四、不重试的代价primary 后台错误4.1 失败如何传导回 primary该修复之所以重要是因为对不回退到本地压缩的CompactionService实现而言worker 侧的任何失败都会成为primary 侧的后台错误background error。也就是说一次纯粹由文件系统时序造成的瞬态失败可能被放大为 primary 上的持续错误状态进而触发后续的错误处理路径如 stop writes。4.2 回退语义由集成方决定CompactionService::Start()的返回值CompactionServiceJobStatus控制失败后的行为。测试实现给出了两种典型选择见 db/compaction/compaction_service_test.cc返回kUseLocal任务回退到 primary 本地执行是“有本地兜底”的集成方式返回kFailure不本地兜底失败直接暴露为后台错误这是压力测试工具DbStressCompactionService的刻意选择。对于后一种集成方式max_secondary_open_retries的重试就是避免无谓后台错误的关键防线。五、与 MANIFEST floor 加固的关系5.1 两个不同层面的保护本修复与既有的remote_compaction_manifest_floor机制include/rocksdb/options.h互为补充解决的问题层面不同机制解决的问题失败处理remote_compaction_manifest_floor默认 trueprimary 调度压缩时把当时的 MANIFEST 位置文件号与大小随请求下发worker 若发现自己基于更旧的MANIFEST 视图如最终一致文件系统返回了过期CURRENT、或 MANIFEST 被截断重建压缩则拒绝执行回退到本地压缩避免基于错误的 LSM 形状产出错误结果max_secondary_open_retries默认 2打开瞬间撞上CURRENT/MANIFEST 替换的瞬态竞态有限次重试后成功继续重试耗尽才返回错误floor 参数还隐含开启了 worker 侧的 “trust the MANIFEST” 恢复模式floor_provided传给OpenAsSecondaryImpl的trust_manifest_recovery见 db/db_impl/db_impl_secondary.cc避免因某个并非压缩输入文件的文件瞬时不可用而失败整个任务。5.2 本修复的定位本文描述的重试逻辑处理的是floor 机制之前的打开阶段先要成功打开并建立 secondary 视图依赖ReactiveVersionSet的MaybeSwitchManifest之后才谈得上 floor 检查。因此两者是同一链路中不同节点的加固重试消化“打开时撞上轮转”的瞬时窗口floor 拒绝“基于过期视图压缩”的正确性风险。六、集成与验证方式6.1 如何设置该参数worker 侧调用DB::OpenAndCompact()时传入自定义的OpenAndCompactOptionsOpenAndCompactOptions options; options.max_secondary_open_retries 2; // 默认值可显式指定 // options.canceled canceled_flag; // 可选支持任务取消 DB::OpenAndCompact(options, db_path, scheduled_job_id, compaction_input, result, options_override);若希望关闭重试以复现/调试竞态可显式设为 0。6.2 测试覆盖测试侧已在 db/compaction/compaction_service_test.cc 中覆盖该参数测试压缩服务把max_secondary_open_retries_传入OpenAndCompactOptions见 db/compaction/compaction_service_test.cc并提供接口调整重试次数max_secondary_open_retries_字段定义见同文件 db/compaction/compaction_service_test.cc默认值与OpenAndCompactOptions一致。通过构造 concurrent CURRENT/MANIFEST 替换的时序利用TEST_SYNC_POINT如DBImplSecondary::OpenAndCompact::BeforeLoadingOptions:0/1、AfterOpenAsSecondary:0等同步点可验证重试后成功与重试耗尽后返回错误的两种路径。相关测试入口还包括 db/db_secondary_test.cc 与 db/compaction/compaction_job_test.cc均引用了OpenAndCompact可用于对照 secondary 打开与压缩任务行为。七、小结与运维建议根因OpenAndCompact()以只读方式打开 primary 实时目录时primary 通过 rename 覆盖CURRENT轮转 MANIFEST在无 read-after-unlink 语义的远程/对象存储上被替换对象立即报告为不存在表现为PathNotFound/NotFound/TryAgain。修复OpenAndCompactOptions::max_secondary_open_retries默认 2对这三类瞬态状态做有界重试避免并发轮转导致压缩失败进而演变为 primary 后台错误。运维建议线上若使用对象存储/远程文件系统承载 RocksDB 数据目录并启用CompactionService遇到TryAgain/PathNotFound类的偶发打开失败属正常竞态可关注OPEN_AND_COMPACT_DB_OPEN_MICROS指标与 INFO/WARN 日志中的 “retry N of M” 信息确认重试生效如竞态频率过高可评估适当增大max_secondary_open_retries但需权衡每次重试的开销。【免费下载链接】rocksdbA library that provides an embeddable, persistent key-value store for fast storage.项目地址: https://gitcode.com/gh_mirrors/ro/rocksdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

ESP32-WROOM-32UE选型与硬件设计:外接天线、引脚及烧录避坑指南

ESP32-WROOM-32UE选型与硬件设计:外接天线、引脚及烧录避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 17:46:17 阅读更多 →
2026凉山电气检测机构排名 TOP5 CMA 资质机构提供防爆设备检测+防爆安全检测 联系方式推荐

2026凉山电气检测机构排名 TOP5 CMA 资质机构提供防爆设备检测+防爆安全检测 联系方式推荐

凉山地区化工园区、油库加油站、矿山厂区、制药企业及危化品仓储场所星罗棋布,防爆电气安全排查与生产验收需求与日俱增。放眼望去,当地电气防爆检测机构虽鳞次栉比,却也鱼龙混杂,大量无资质机构出具的检测报告形同虚设&#xff0…

2026/9/21 9:49:07 阅读更多 →
钢管混凝土叠合柱ABAQUS精细化建模指南

钢管混凝土叠合柱ABAQUS精细化建模指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 7:37:27 阅读更多 →

最新新闻

昂达平板电脑root与汇编语言王爽对比选型

昂达平板电脑root与汇编语言王爽对比选型

昂达平板电脑root实战:避开高频面试题里的3个致命坑 刚接手昂达V818s老机子,想装个Xposed框架,结果刷完机一开机,屏幕炸出满屏红字。 java.lang.SecurityException: Permission denied…

2026/9/22 5:48:45 阅读更多 →
手写实现tcpmp核心协议,3天搞定面试原理难题

手写实现tcpmp核心协议,3天搞定面试原理难题

手写实现tcpmp核心协议,3天搞定面试原理难题 面试被问TCP原理,你只能背三次握手?面试官追问滑动窗口怎么控制,你支支吾吾答不上来?别慌,今天带你 手写实现 一个简化版的 tcpmp…

2026/9/22 5:48:45 阅读更多 →
建筑拆除考证入门到精通:5个致命坑与通过率真相

建筑拆除考证入门到精通:5个致命坑与通过率真相

建筑拆除考证入门到精通:5个致命坑与通过率真相 官方文档翻了三遍还是云里雾里?别慌,这不是你的问题。《注册建造师》或《安全工程师》关于建筑拆除的章节,官方大纲写得像天书,考点散落在全书各章,新手根本抓不住重点。很多人以为背完教材就能过,结果…

2026/9/22 5:48:45 阅读更多 →
3个坑搞懂rhr:新手避坑指南与实战选型对比

3个坑搞懂rhr:新手避坑指南与实战选型对比

3个坑搞懂rhr:新手避坑指南与实战选型对比 配置环境就卡半天,是不是你也经历过这种绝望?下载完依赖, npm install 转了十分钟,最后报一堆红色错误,日志里全是 ERR! 或者 ECONNRESET…

2026/9/22 5:47:44 阅读更多 →
fjtc配置卡壳?3步避坑指南让源码跑通

fjtc配置卡壳?3步避坑指南让源码跑通

fjtc配置卡壳?3步避坑指南让源码跑通 配置环境就卡半天,是不是觉得电脑要炸了?别慌,这不仅是你的问题,更是 fjtc 这类底层工具在集成时的典型“水土不服”。…

2026/9/22 5:47:44 阅读更多 →
西安华为研究所面试避坑 3 个手写实现核心考点拆解

西安华为研究所面试避坑 3 个手写实现核心考点拆解

西安华为研究所面试避坑 3 个手写实现核心考点拆解 报错堆满屏幕,StackTrace 长得像天书,面试官盯着你问底层逻辑?别慌。在西安华为研究所的面试实战中,光背八股文根本过不了关。很多候选人卡在 手写实现…

2026/9/22 5:47:44 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →