SirixDB 1.0 Beta发布:类Git版本控制、差异比对与时间旅行查询
速览
SirixDB 1.0 Beta正式发布,这是一款支持类Git版本控制的数据库,提供版本差异比对和时间旅行查询功能。用户可以像操作Git一样对数据进行版本管理,回溯历史状态。该版本标志着SirixDB进入beta阶段,为开发者和数据管理场景提供了新的时序数据解决方案。
AI 深度解读
背景
传统数据库在更新一行数据时,旧值会直接消失。要追溯历史,通常需要额外搭建审计表、变更数据捕获(CDC)或事件溯源(Event Sourcing)系统,结果变成两套系统:一套管当前状态,一套管历史。查询过去意味着重放事件或扫描日志,原本简单的审计需求演变成一个基础设施项目。Git 为文件解决了版本控制问题,但无法直接查询 Git 仓库。事件溯源保留了历史,但重建过去状态需要从头重放所有事件。
SirixDB 正是为解决这一矛盾而生:它让每个修订版本都成为数据库中的一等公民,而非事后添加的附属品,也不是需要重放的日志。1.0.0-beta 版本已可实际使用,并正在积极开发中。其磁盘格式和公开 API 正趋于稳定,向 1.0 正式版迈进,开发团队期待来自真实使用的反馈。
核心内容
SirixDB 的核心创新在于:每个修订版本都是可直接访问的快照,而不是需要重放才能恢复的日志。用户可以通过两种方式直接查询任意历史版本:
- 按修订号查询:
session.beginNodeReadOnlyTrx(1)直接打开修订版 1,无需重建。 - 按时间戳查询:
session.beginNodeReadOnlyTrx(Instant.parse("2024-01-15T03:00:00Z"))返回该时刻对应的快照。
这两种查询都返回可读的快照,速度与查询“当前版本”一样快。
这一能力源于 结构共享(Structural Sharing) 与 子页版本控制(Sub-Page Versioning)。具体机制:
- 不变页面在修订间通过写时复制(Copy-on-Write)共享。
- 版本控制细化到页面内部:一次提交只写入包含变更记录的页面片段(page fragments)。
- 滑动快照算法(Sliding-Snapshot Algorithm)保证任何页面最多只需从 N 个片段重建(N 为可配置的快照窗口,默认 3)。
- 对比传统方案:块级 COW(如 ZFS)在页面中一个字节改变时也要复制整个页面;基于增量的系统则让读操作不断重放不断增长的差异链。SirixDB 避免了这两种代价。
存储效果:
- 存储空间正比于每个修订版本变更的记录数,而非总大小乘以修订数,也不是变更的页面数。
- 读取任意修订版本的任意页面,最多需要读取 N 个页面片段(N 为默认 3)。
- 无需事件重放或日志扫描,直接页面访问。
双时态(Bitemporal)支持:大多数数据库(如果支持版本化)只追踪一条时间线——数据写入时间。SirixDB 追踪两条:
- 事务时间(Transaction Time):系统管理,记录提交时间。
- 有效时间(Valid Time):用户管理,记录该数据在真实世界中何时为真。
举例说明其意义:
- 1 月 15 日:记录“价格 = $100,有效从 1 月 1 日开始”。
- 1 月 20 日:发现 1 月 1 日实际价格是 $95。
- 修正后可以问:
- “1 月 16 日我们认为价格是多少?” → $100(事务时间)
- “1 月 1 日价格实际是多少?” → $95(有效时间) 两个问题都有正确且不同的答案。没有双时态支持,修正会破坏审计轨迹。
架构特点:
- 仅追加存储:数据永不覆盖,新修订写入新位置。
- 结构共享:未改变的页面和节点通过写时复制在修订间引用。
- 快照隔离:读取者看到一致视图,每个资源只有一个写入者。
- 可嵌入:单个自包含 JAR 文件(第三方依赖已 shade 打包),可进程内嵌入,也可作为 REST 服务器运行。
性能实测(来自开发团队发布的基准测试,方法见 WHY-SIRIX.md 和 BENCHMARKS.md):
- 并发读取:在 12,800 修订版本的数据库上,16 个读取线程 + 1 个写入线程通过 REST 访问,在修复页面生命周期 bug 和 O(历史) 打开成本后,读取速度从 361 提升到 11,198 读/秒,p99 延迟从 334 ms 降至 4.8 ms,零错误。老化数据库甚至优于修复前的新鲜数据库。
- 语义差异:在两个修订版本之间进行节点级插入/更新/删除(使用稳定键)只需约 0.3 ms,而非文本差异。
- 分析查询:向量化、失败闭合的执行路径,在 1 亿记录上与 DuckDB 1.5.2 正面交锋:9 种查询形状中 3 种领先,其余除 count-distinct(约 4.2 倍差)外都在 1.1–2.5 倍以内(sum 16 ms,双键 group-by 240 ms)。GraalVM 原生编译的二进制在热分析查询上比 JVM 快 7–17 倍。
- 独立查询引擎 brackit 在自身基准测试中运行分析型 JSON 查询的速度比 jq 快数倍。
- 与 PostgreSQL 17 的诚实对比:PG 在原始小文档写入(约 4015 vs 430 提交/秒)和总存储上胜出;SirixDB 在进程内嵌入读取、0.3 ms 语义差异和子文档时间旅行上胜出(这些是 PG 不具备的能力)。测量前已验证耐久性设置等效。
失败闭合(Fail-Closed)机制:每个快速路径都保证正确性——内核仅在优化器能证明查询形状与其输出匹配时运行,差分测试套件要求输出字节与通用路径完全一致。错误但快速被视为 bug 类别,而非可配置选项。
页面版本策略(可针对每个资源配置):
- FULL:每个页面存储完整数据,读取快,存储高。
- INCREMENTAL:增量存储,定期全量快照。每个修订仅存储与前一个修订的差异,读成本随窗口内修订数线性增长。
- DIFFERENTIAL:差异存储,定期全量快照。每个修订存储与最近快照的差异,读成本最多一次差异应用,但差异会随时间增大。
关键要点
- 直接历史访问:任何修订版本都可像读最新版本一样直接页面查找,无需重放事件或扫描日志。会话打开成本恒定(10,000 修订版本时约 0.18 ms),与历史深度无关。
- 结构共享 + 子页版本控制:未修改页面在修订间共享,修改只写变更的页面片段,存储空间正比于实际变更量,而非总数据量乘以修订数。
- 双时态模型:同时追踪事务时间和有效时间,支持审计场景中“我们当时认为什么”与“实际是什么”的区分,修正不会破坏历史。
- 仅追加存储:数据永不覆盖,新修订写入新位置,天然支持时间旅行。
- 可嵌入与高性能:单 JAR 可嵌入或作为 REST 服务运行。并发读取性能优异,语义差异毫秒级,分析查询与 DuckDB 和 PostgreSQL 可比较。
- 失败闭合设计:所有快速路径都经过正确性验证,避免错误但快速的情况。
- 多种页面版本策略:支持 FULL、INCREMENTAL、DIFFERENTIAL 三种策略,用户可根据读写模式权衡存储和读取性能。
- 开源与社区:可通过 Demo、文档、Discord、论坛等渠道参与,1.0 正式版正在稳定中,欢迎真实使用反馈。
意义与影响
SirixDB 从根本上重新思考了数据库
