数据库对外承诺的隔离级别、客户端实际走到的执行路径,以及磁盘恢复后的数据,可能是三件不同的事。Jepsen 对 ParticleDB 的测试值得关注,不只是因为问题数量多,更因为大量严重错误在单节点、单客户端、没有故障注入时就能触发。复杂的分布式故障并不是可靠性验证的起点。
原文:Jepsen: ParticleDB 1.1.4 · Kyle Kingsbury · 2026-10-31。研究由 Orkes 资助,按 Jepsen 的伦理政策开展。
先确定报告究竟测了什么
ParticleDB 希望把事务 SQL、键值、向量检索、实时分析等能力合并到一个面向 AI 应用的引擎中。Orkes 原本为 Conductor 的特定查询构建了 1.0.0,随后进行了大规模重构。本报告测试的是 1.1.4 至 1.1.18.11.rc-22,不是所有历史和后续版本。
提供给 Jepsen 的构建不包含复制功能,因此测试只覆盖单节点。运行环境为 Debian 13 容器及 EC2 虚拟机;访问路径包括 Postgres JDBC 42.7.11 和 ParticleDB Java SDK 1.0.0–1.0.2。测试遍历事务模式与三种 WAL 同步模式,并能杀进程、通过 LazyFS 模拟未同步写丢失,以及破坏磁盘文件。不能把这份报告当作 Raft 复制正确性的评估。
报告汇总 96 个问题,到 rc-22 时其中 86 个看起来已解决、10 个仍未解决。作者同时说明,Orkes 后来发布 1.1.19-rc.13,声称解决报告全部剩余问题;Jepsen 没有测试该版本。这一声明应与实际回归测试结果分开,也不能将旧版本的问题直接写成新版本仍必然存在。
为什么“设了隔离级别”还不够
受测版本会拒绝或忽略标准 SQL 隔离级别设置,真实行为由启动时的 --txn-mode 控制。文档对模式的解释又存在冲突:内部操作指南将 occ-v3 和 zero-copy-occ 对应到 Snapshot Isolation,将 serializable-ssi 对应到 Serializable,将 table-2pl 对应到 Strong Serializable;但其他页面使用“并发安全”等不够精确的表述。
这直接影响测试判定。若不知道实际配置承诺禁止哪些异常,成功提交和返回结果本身不足以证明隔离性。sync 与 groupsync 的耐久性描述也不一致,因此不能仅看模式名推定确认写入已经受到怎样的保护。报告还指出,测试合作期间未获得所宣传的 TLA+ 规范,无法判断证明覆盖哪些性质、是否对应实际实现;这并不等价于推翻形式化方法本身。
三类工作负载把问题逐步缩小
第一类是随机读写与列表追加事务。rw 让事务读写唯一键对应的值,append 把唯一整数追加到列表。列表保留了可追踪的写入痕迹,Elle 利用观察到的版本顺序与事务依赖寻找环及其他异常。测试还改变数据类型、主键与非索引次键访问、连接路径,避免只覆盖一种实现分支。
第二类检查单个事务的内部一致性:事务写过的内容,之后的读是否能看到?这类检查不需要先解释复杂的跨事务交错,就能识别基本状态管理问题。
第三类 compare 随机生成表结构与 SQL,在 ParticleDB 和 Postgres 上执行并比较结果。它只检查顺序行为,却以约两千行生成测试发现了大量错误。两种数据库可以存在合法差异,所以差分不是自动正确的裁判;作者也观察到,后期细微兼容差异会反复占据最小化过程,反而遮住更严重的问题。测试生成器需要不断整理已知差异,而非把“结果不一样”全算成同等级缺陷。
从简单反例到已确认写入丢失
一个直观案例是旧版本中事务内删除一行后,直接查询已看不到它,带谓词的聚合却仍能观察到它。另一些版本改变插入列的顺序,会使行无法正常扫描、值错位,甚至难以删除。这些案例说明,表面上相同的数据可能通过不同算子走到不一致的内部表示。
更接近应用风险的是报告的 #110:在 1.1.18.11.rc-18 至 rc-22,健康单节点也会丢弃已确认写入。一个使用 sync WAL 的 append 测试中,约两万个键有 31 个发生写丢失;某键的列表先被多次读为 [1,2,3],随后出现不含这些元素的另一条增长链。该现象不需要磁盘故障,不能简单归结为没有调用 fsync。报告末尾特别指出 rc-22 默认 occ 仍在正常运行中丢数据,较强的 serializable 模式则仍有正常运行时陈旧读,以及杀进程后的内部异常与 Lost Update。
故障注入提供另一层证据。一个 WAL 位翻转案例中,恢复程序检测到校验和错误,却继续重放有效前缀并开放服务,已确认的列表元素随后消失。这里的问题不只是“是否检测到损坏”,还包括检测后是否允许以不完整状态继续提供成功响应。模拟错位读写时也出现过整个数据库状态丢失。这些故障各自有版本与配置边界,不应混成一个所有版本共享的故障机制。
对系统可靠性工作的启发
这份报告最可迁移的做法,是把验证层级从基础 SQL 语义、单事务状态、并发历史,一直推进到磁盘恢复。即使最终关注混沌工程,正常路径也需要先有能失败的测试。随后再变化数据编码、客户端接口和访问路径,检查同一语义是否真的共享正确实现。
对 Agent 后端尤其如此:一次工具调用成功可能只说明请求被接受,工作流接下来依赖的状态仍可能不一致。性能数字也需要建立在明确的隔离与耐久性条件上;以弱化语义换得的吞吐,不能直接与更强保证下的系统比较。这是从报告机制得到的工程判断。
Jepsen 还讨论了 LLM 辅助开发中的修复声明和难以解释的变更,但该审计并非有对照组的开发方式实验,不能据此估计 AI 编码导致缺陷的因果效应。对读者更有操作价值的证据,是具体版本、事务历史、反例和修复后的重测。建议先读 Test Design 与 Discussion,再沿 #110 和 WAL 损坏案例查看安全性质如何被实际观察否定。