打开 lmdb.tech 的文档首页,顶上有一行提示:这是 LMDB 1.0 的文档,0.9 版本的文档已经归档,之前用 0.9 的用户请看专门的升级指南。看上去跟大多数开源项目按部就班的版本迭代没什么两样。

但去查发行证据,事情没那么干净。FreshPorts 上能装到的 LMDB 核心 C 库,最新还是 0.9.35 系列。PyPI 上倒是真有一个叫 lmdb 的 1.0.0,可那是 Python 绑定包 py-lmdb,不是 LMDB 本体。文档标题和实际能装到的软件,对不上号。

LMDB 的老本行没变

先把技术底子摆清楚,这部分文档写得很扎实,值得复述一遍要点:

  • 整个数据库直接映射进内存,读数据不用 malloc、不用 memcpy
  • B+ 树结构,写时复制(COW),崩溃后不需要专门的恢复流程
  • 多版本并发控制让读操作完全无锁,写操作单线程串行,天然不会死锁
  • 空闲页自动回收,不像 WAL 或 append-only 方案那样需要定期 compaction

这套设计十几年没大改过,读密集、低延迟的场景一直是它的强项。1.0 文档里重申的这些机制,跟 0.9 时代基本一致,变化更多在文字组织,不在底层行为。

文档写1.0,发行卡在哪? 官网文档标注 LMDB 1.0 含0.9→1.0升级指南 外部发行证据 0.9.35 FreshPorts核心库现状 PyPI lmdb 1.0.0 实为Python绑定包,非核心库

谁会被这个版本号绕进去

真正容易踩坑的是两类人。一类是拿 LMDB 做底层存储的项目——OpenLDAP、区块链客户端、消息中间件——如果照着 1.0 文档里的说法去规划升级,却发现能装到的还是 0.9.35,特性对不上就得回头核实。另一类是用 Python 绑定 py-lmdb 的开发者,看到 pip 装出来是 1.0.0,容易顺手把这个版本号当成 LMDB 核心引擎的版本,实际上两者编号完全独立。

  • 风险.按文档里的1.0特性写代码,却部署的是0.9.35的库,版本预期和实际行为可能对不上。

值得一提的是,OpenLDAP 社区确实有讨论面向 1.0 的具体功能(比如子树排序支持),说明 1.0 不是空标题,而是有真实规划在推进。但规划和正式发布之间,还隔着一个 changelog、一个 tag。文档先走一步,库还没跟上,这在开源世界不算新鲜事,只是这次的落差被包管理器数据坐实了。

文档写的是终点,发行证据停在半路。

老运维坑还在,选型看场景

版本号之争之外,LMDB 那些长期存在的运维痛点,并没有因为文档改名就消失。stale reader 阻塞空闲页回收、数据库跟着膨胀,lockfile 权限出问题导致多进程协调失败——这些是 0.9 时代就写在文档里的坑,1.0 文档原样保留,说明它们还是要靠运维自己规避,不是版本升级能解决的。

场景选型上,LMDB 的优势边界其实很清楚。读密集、需要低延迟、不想维护 compaction 的场景,LMDB 的单写者串行模型够用;写密集、高并发写入的场景,RocosDB 这类 LSM 树方案吞吐更高,这也是它们在服务器端 flash 存储的 IO 密集测试里表现更好的原因。如果需要 SQL,那是 SQLite 的地盘,它的 mmap 优化本身也只帮读,不帮写。

  • 结论.选型前别只看文档标题,去包管理器和源码仓库交叉核实发行状态,再决定要不要按1.0的说法写代码。