【C++三方组件】RocksDB:写多读少的嵌入式 KV
【C三方组件】RocksDB写多读少的嵌入式 KV【摘要】RocksDB 是 Facebook 从 LevelDB 演化出的嵌入式持久 KV用 LSM-tree 把写路径变成顺序追加先写内存 memtable 与 WAL再批量落成不可变 SST后台 compaction 分层归并。本篇讲 Put / Get / Status 的日常、WriteBatch 千条成批的实测吞吐差、迭代器范围扫描、快照一致性读、Column Family 的命名空间与「重开必须带全」的坑以及 write_buffer_size 一档入门调参与 GetProperty 观测末尾对照 SQLite 与 LMDB给出写多读少场景的选型边界。【关键词】RocksDB、LSM-tree、嵌入式 KV、WriteBatch、Column Family、compaction【版本基准】RocksDB 11.8.1双许可GPLv2 / Apache-2.0 二选一示例 C20——11.x 起要求 C20GCC ≥ 11 / Clang ≥ 10 / MSVC v143 及以上文中输出与吞吐均为本机实测MSVC v145VS2026Windows数字随机器与磁盘而变1. What为写而生的 KV 引擎RocksDB 是一个嵌入式持久化键值库键值皆字节串rocksdb::Slice按字典序组织单个进程直接打开本地目录使用——没有服务进程数据库就是一个文件夹。它 2012 年从 Google 的 LevelDB fork 而来FacebookMeta为服务端负载持续改造十年多线程 compaction、Column Family、速率限制、备份、事务……今天的用户名单里有 TiKV、MyRocks、Flink 的 state backend——**「写多读少、数据量大、要持久」**是它们的共同点。与第 33 篇 SQLite 的根本分野在写路径的物理形态。SQLite 是 B-tree 页式存储一条 UPDATE 意味着在文件中间某页就地改写——随机写。RocksDB 是 LSM-treeLog-Structured Merge-tree写入只追加到内存 memtable 和磁盘 WALmemtable 写满后一次性顺序刷成不可变的 SST 文件后台 compaction 再把多层 SST 归并压缩。磁盘最擅长的顺序写被放到主路随机写被赶到后台——这就是「写多读少」的物理来源。代价也长在同一处读要跨 memtable 多层 SST 查找读放大删除只是写墓碑、空间要等 compaction 才回收空间放大compaction 占用后台 CPU 与 IO写放大与延迟抖动。三个放大是 LSM 的三角形约束调参第 8 节本质是在三角里挪位置。API 面很窄全是rocksdb::Status通道std::unique_ptrrocksdb::DBdb;rocksdb::DB::Open(Options,path,db);// 打开11.x 出参是 unique_ptrdb-Put(wo,key,value);// 写db-Get(ro,key,value);// 读NotFound 是分支不是错误db-Delete(wo,key);// 删写墓碑db-Write(wo,batch);// 批量原子写db-NewIterator(ro);// 有序扫描db-GetSnapshot()/ReleaseSnapshot();// 快照db-CreateColumnFamily(...)// 列族从旧教程迁移的读者会撞到的第一个变化11.x 的DB::Open出参是std::unique_ptrDB*10.3 弃用、11.0 移除了DB**版本——所有权从此由智能指针表达delete db的手工纪律退场Column Family 句柄仍是裸指针用db-DestroyColumnFamilyHandle(h)归还。注意它不是SQL 数据库没有表、没有查询计划值是一块不透明的字节——需要结构化查询回到第 33 篇需要把 JSON/protobuf 自己塞进 value。2. Why自研持久 KV 的深水区「写个 map 存硬盘」的朴素版本两天就能跑起来然后深水区一个接一个崩溃安全要求每次修改先写日志再改内存结构WALfsync 时机错一步就丢数据或写坏文件memtable 满了要刷盘刷盘期间新的写去哪不可变 memtable 轮换磁盘文件不可变更新与删除只能靠后台归并compaction回收空间而 compaction 的层级策略、触发时机、限速、与前台 IO 的隔离每一项都是论文级的调优对象范围扫描要跨 memtable 与多层 SST 归并出一致视图并发要处理多线程读写同一 memtable 的正确性。RocksDB 把这些全部做好了而且是在 Meta 的生产规模上锤出来的。选它的账本很简单一颗经过十年生产验证的存储引擎树换来你完全不用发明 compaction。成本同样明确编译时间本篇示例在 Windows 上从源码全量编译一次MSVC Ninja -j6 实测约 68 分钟、二进制代价静态库本体数百 MB好在链接器只抽取用到的符号——示例程序链接后仅 5.5 MB、以及不得不学的调参词汇表。3. How接入与运行vcpkgvcpkg install rocksdbCMake 走find_package(RocksDB CONFIG REQUIRED)目标是rocksdb::rocksdb源码GitHub release 下载解压add_subdirectory编静态库。示例工程的CMakeLists.txt预设了一组「最小可用」开关——WITH_SNAPPY / WITH_ZLIB / WITH_LZ4 / WITH_ZSTD / WITH_BZ2全关压缩可后补不影响 API、WITH_TESTS / WITH_TOOLS全关、ROCKSDB_BUILD_SHARED OFF只编静态库。⚠️ 接入前先看语言门槛RocksDB 11.x 要求 C20头文件里已经用上默认比较运算符等特性源码默认CMAKE_CXX_STANDARD 20官方要求 GCC ≥ 11 / Clang ≥ 10。项目还锁在 C17 时有两个选择降级用 RocksDB 8.x / 9.xC17 时代版本API 兼容本篇示例或把它隔离在单独的静态库里、边界只暴露 C 接口。本系列其它示例保持 C17本篇示例单独用 C20——配套 CMakeLists 里两个目标各钉各的标准。完整示例 rocksdb_demo.cpp 一个 main 串七节基础读写、WriteBatch、迭代器、快照、吞吐实测、Column Family、运行时观测。构建与运行入口见 配套说明。4. 基础读写Status 是唯一通道rocksdb::Status sdb-Put(wo,name,rocksdb);if(!s.ok()){/* s.ToString() 看详情 */}sdb-Get(ro,name,value);// 命中sdb-Get(ro,missing,value);// s.IsNotFound() truesdb-Delete(wo,temp);RocksDB 没有异常、没有 errno——一切成败都装在返回的Status里ok() / IsNotFound() / IsCorruption() / IsIOError()分类分支。两个习惯要养成Get查无此键不是错误IsNotFound()是与ok()平级的正常分支不检查 Status 的调用等于把 IO 错误当成功示例的check()小包装即为此。WriteOptions最要紧的一个开关是sync默认 falsefalse 时写只进 WAL 缓冲不强制落盘——进程崩溃不丢机器断电可能丢最近的写true 则每笔写都 fsync持久但慢。这对应 SQLite 的synchronous语义默认档位同样是「快而够用」。5. WriteBatch一批写原子生效rocksdb::WriteBatch batch;for(inti0;i1000;i)batch.Put(key_of(i),value);batch.Delete(old);db-Write(wo,batch);// 一批一次 WAL 追加Batch 把 N 次独立的 WAL 追加与锁竞争合成一次还附带原子性要么全部可见要么全不可见崩溃恢复时按整条 WAL 记录重放。实测吞吐差10 万条key 12 B / value 100 B本机 NVMe逐条 Put : 788.3 ms12.7 万条/秒 千条成批 : 33.8 ms296.1 万条/秒约 23 倍但差距的来源与第 33 篇那次不同RocksDB 逐条Put默认不 fsyncWAL 只进缓冲batch 省掉的是每条一次的锁获取、序列化与 WAL 记录封装。把两组实测放一起看更有意思——同为「逐条写」本篇 12.7 万条/秒第 33 篇 SQLite autocommit 约 108 条/秒差三个数量级因为 SQLite 每条 COMMIT 都在等 fsync而 LSM 把落盘推迟给了后台。数量级结论成批写入值得「逐条 Put」在 RocksDB 上不是灾难在 SQLite autocommit 上才是。6. 迭代器与快照读侧的两件工具迭代器是有序扫描的正门——Seek到第一个大于等于目标的位置Next一路向后rocksdb::Iterator*itdb-NewIterator(ro);it-Seek(batch:2);for(;it-Valid();it-Next())// it-key() / it-value() 是 Slice用 ToString()deleteit;// 迭代器要手动归还两个纪律迭代器用完必须 delete否则挡住底层文件回收遍历结束查一下it-status().ok()——中途 IO 错误会让Valid()提前变 false不查就把错误当「扫完了」。快照给「一边写一边读」的场景一个固定时刻的一致性视图constrocksdb::Snapshot*snapdb-GetSnapshot();db-Put(wo,counter,200);// 快照之后的写rocksdb::ReadOptions ro_snap;ro_snap.snapshotsnap;db-Get(ro_snap,counter,v);// 仍是 100db-ReleaseSnapshot(snap);实测输出快照读 100当前读 200。⚠️ 快照用完必须 Release——它钉住了那一刻的全部数据版本不释放会挡住 compaction 删除旧文件是磁盘空间泄漏的常见来源。这根 「用完归还」的弦与迭代器、Column Family 句柄第 7 节是同一根。7. Column Family一个库里的多张「逻辑表」Column FamilyCF是 RocksDB 的「命名空间」所有 KV 默认住在default新建 CF 得到独立的 memtable、compaction 策略与参数——可以给热数据配大内存、给索引数据开布隆过滤器、给日志数据配 TTL而它们共享一个 WAL 与一份打开的文件句柄。db-CreateColumnFamily(cf_opts,users,users);db-Put(wo,users,alice,1);// 写进 users 列族db-Get(ro,users,alice,v);db-DestroyColumnFamilyHandle(users);// 句柄要手动归还db.reset();// unique_ptr 关库实测输出cf[users].alice 1cf[orders].o-1001 alice 重开前列出 CFdefault users orders 重开后 cf[users].alice 1数据仍在本篇最大的坑在重开打开数据库时必须先ListColumnFamilies列全、把每个 CF 的描述传给DB::Open——漏列一个Open 直接失败“You have to open all column families”。这是新库最常见的一类「升级后打不开」事故加了一个 CF忘了把重开路径上的列表从硬编码换成动态列举。关闭顺序同样有讲究先归还全部 CF 句柄再关 DB。8. 调参入门与运行时观测Options有上百个旋钮入门只需要盯住写路径这一组参数默认作用write_buffer_size64 MB单个 memtable 上限越大 flush 越稀、SST 越大max_write_buffer_number2memtable 槽位写快于 flush 时要加max_background_jobs2flush / compaction 后台线程数compressionSnappy*各层压缩空间与 CPU 的交换*压缩默认 Snappy但编译时未启用 snappy 时静默退化为不压缩示例工程即如此——空间敏感的项目要显式接上压缩依赖再确认Options::compression生效。直觉模型写太快 → flush 跟不上 →write_buffer_size与槽数加倍compaction 跟不上 → 后台任务数加倍。示例第 7 节演示了这些设置。调参不是玄学开工而是先观测再动db-GetIntProperty(rocksdb.estimate-num-keys,keys);// 活键估计db-GetProperty(rocksdb.stats,stats);// 各层文件/读写放大实测rocksdb.stats摘录写入 20 万条后** Compaction Stats [default] ** Level Files Size Score Read(GB) Rn(GB) Rnp1(GB) Write(GB) ... --------------------------------------------------------------------同时estimate-num-keys实测为 200005default 列族 20 万条吞吐数据加几个演示键。注意它是估计值——墓碑与覆盖未即时扣除拿它做监控趋势可以做精确计数不行。9. 使用边界与选型不适合 RocksDB 的信号读远多于写、要求稳定点查延迟LSM 层级查找与 compaction 抖动天然不利于此全库顺序扫描是主负载每次都要归并全部 SST不想引入调参与运维心智三个放大需要长期盯着数据库必须放在网络文件系统上NFS / SMB 不支持与 SQLite 的 WAL 同一物理原因。以及一条工程判断数据量长不大 1 GB、又是结构化查询需求SQLite 一把梭更省——不必为 10 万条配置文件上 compaction。嵌入式存储三路线对照本篇为其中一极SQLite33RocksDB本篇LMDB35模型SQL / B-treeKV / LSM-treeKV / B-tree mmap写吞吐中单写者高低写者串行点查延迟稳定有层级开销极稳空间回收即时等 compaction即时调参负担小大极小需求信号要 SQL / 关系写多读少、量大读多写少、极简一句话选型要 SQL 选 SQLite要写吞吐选 RocksDB要极简稳定读选 LMDB——第 35 篇从 mmap 路线再会。〔关联〕LSM-tree 的分层归并、RocksDB 的读写路径剖析属设计内幕后续在cpp-source-reading专栏展开LSM vs B-tree 的复杂度分析是面试高频见cpp-interview-faq。10. 参考资料官方文档 github.com/facebook/rocksdb/wikiBasic Operations、Column Families、RocksDB Tuning Guide 三篇与本篇对应HISTORY.md从 LevelDB fork 以来的演进时间线完整构建与运行入口examples/33-34/README上一篇第 33 篇SQLite——同一「嵌入式存储」赛道上 SQL / B-tree 路线的对照极。参考facebook/rocksdb v11.8.1双许可 GPLv2 / Apache-2.0。本篇全部输出与吞吐逐条 Put 与 WriteBatch 对比、CF 重开、快照读、stats 摘录均为本机实测MSVC v145VS2026WindowsNVMe SSD数字随机器与磁盘而变。

相关新闻

2026五款树洞隐私终极横评|不绑手机、不读通讯录、不存聊天!全网仅两家做到后台零记录

2026五款树洞隐私终极横评|不绑手机、不读通讯录、不存聊天!全网仅两家做到后台零记录

2026年树洞平台乱象依旧泛滥,很多用户踩坑的核心原因只有一个:误把“匿名显示”当成“真隐私保护”。看似无人知晓的匿名倾诉,实则后台绑定手机号、偷偷读取通讯录、全程储存聊天记录,你的每一段emo心事、私密秘密,都被…

2026/10/12 4:55:53 阅读更多 →
SCA逐次凸近似:非凸优化问题的工程实践与避坑指南

SCA逐次凸近似:非凸优化问题的工程实践与避坑指南

简介:这份资源聚焦SCA(Sequential Convex Approximation)凸优化算法的实现,面向具备一定数学优化基础、希望将非凸问题转化为连续凸近似求解的学习者与工程人员,可用于无线通信、信号处理、能源系统优化等场景的算法验…

2026/10/12 4:55:53 阅读更多 →
json.loads 报 JSONDecodeError: Expecting value: line 1 column 1 (char 0),先加一行 print 看返回内容

json.loads 报 JSONDecodeError: Expecting value: line 1 column 1 (char 0),先加一行 print 看返回内容

代码跑到 json.loads() 这行报错: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)先别动解析那行。在它上面加一行,把拿到的东西打出来看: raw resp.text # 你原本要解析的东西 print(repr(raw[:100]))…

2026/10/12 4:55:53 阅读更多 →

最新新闻

mediamtx v1.21.2发布:UDP、JWT、RTSP、RTMP、HLS、WebRTC全面修复,稳定性与安全性再提升

mediamtx v1.21.2发布:UDP、JWT、RTSP、RTMP、HLS、WebRTC全面修复,稳定性与安全性再提升

2026年10月10日,mediamtx 发布 v1.21.2 最新版本。本次更新以“修复与改进”为主,覆盖通用逻辑、API、Media-Over-QUIC、RTSP、RTMP、HLS、WebRTC 以及依赖库升级等多个方向。 v1.21.2 没有引入新的功能模块,而是集中处理实际运行中可能出现的…

2026/10/12 5:43:21 阅读更多 →
哪个品牌密码锁最安全 高端市场占比领先全维安防更靠谱安心

哪个品牌密码锁最安全 高端市场占比领先全维安防更靠谱安心

在智能家居全面普及的今天,智能密码锁已经成为了家庭安全防护的核心入口。哪个品牌密码锁最安全,不仅关乎家庭财产安全,更影响着日常进出的便捷体验与全场景安防体验。2026年以来,国内智能门锁行业技术迭代加速,市场格…

2026/10/12 5:43:21 阅读更多 →
2026家用智能锁品牌推荐:德施曼热门产品深度解析

2026家用智能锁品牌推荐:德施曼热门产品深度解析

随着智能家居行业的快速发展,智能门锁已经成为了千家万户的入户安防首选。相较于传统机械锁,智能门锁不仅提供了更加便捷的多种解锁方式,还集成了猫眼可视、AI安防、远程对讲等功能,全方位提升家庭入户安全与使用体验。在2026年上…

2026/10/12 5:43:21 阅读更多 →
本地化企业知识库方案拆解:8 步把文档变成知识库

本地化企业知识库方案拆解:8 步把文档变成知识库

## 背景在项目复盘场景里,企业文档散落各处、找人问半天是效率的主要损耗点。## 核心能力- 全程本地运行,原始文档与知识数据不出电脑- 8 步流水线自动化:解析→结构化→质检→复核→分片→向量库→验收- 内置本地大模型,离线推理…

2026/10/12 5:43:21 阅读更多 →
81 极物科技 | KNX调试 - 个体地址过滤与报文隔离

81 极物科技 | KNX调试 - 个体地址过滤与报文隔离

极物科技 | KNX调试 - 个体地址过滤与报文隔离 前言 工程品质是 KNX 国际标准三十年立足全球的根基,而可观测性是品质的前提。 报文追踪把“看不见的总线”变成“看得见的证据”:每一次收发都有记录、每一次异常都有据可查。本文围绕报文追踪的接收链路、…

2026/10/12 5:43:21 阅读更多 →
百万级缺陷样本开源:工业视觉的「地基」被补上了

百万级缺陷样本开源:工业视觉的「地基」被补上了

1.工业质检的两道坎 ▍坎一:数据各管各的现成的工业缺陷数据集,几乎都窝在单一行当里。VisA、3CAD 盯着 3C 电子,PKU-GoodsAD 盯着包装,Real-IAD、MulSen-AD 盯着材料。覆盖面稍宽些的 VISION、MVTec AD、MMAD,又卡在…

2026/10/12 5:42:21 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/11 14:36:54 阅读更多 →