ZoneTree:实践指南

作者:袖梨 2026-09-10

在项目中评估ZoneTree,可以先看清用途边界:ZoneTree 是持久性、高性能、事务性、ACID- 兼容的有序键值数据库和适用于 .NET 的 LSM-tree 存储引擎。一旦进入数据与知识处理环节,数据结构、更新策略和可追溯性会决定结果是否可信会直接影响交付,这也是我最关心的风险。我建议用一份规模可控且答案已知的数据集试跑,重点记录模式兼容、增量更新、查询结果和来源追踪,再与现有方案比较。它更像给需要保留数据来路与变更记录的使用者准备的可审查方案,是否长期使用应由试跑数据决定。

ZoneTree

严肃的.NET数据系统之下的引擎。

ZoneTree是一个用于有序、持久数据的高性能存储引擎。它专为在 .NET 生态系统中创建数据库、索引、搜索系统、队列、事件存储、本地优先应用程序和自定义数据平台的团队而构建。

缺失的层

现代数据系统不仅仅建立在功能之上。 它们构建在影响性能、可靠性和产品架构的存储层上。

在具有单独写入、二级索引、点读取、有序扫描、查询和更新的实时 2M 配置文件基准测试中,对于此嵌入式配置文件存储场景,ZoneTree 比 RocksDB、SQLite 和 MySQL 更快地完成测量的工作负载阶段。请参阅 zonetree.dev/docs/benchmark 上的完整基准说明和参考报告。

.NET拥有优秀的数据库和框架,但可以作为构建新数据系统基础的原生存储引擎很少。

ZoneTree 填充该层。

它为 .NET 系统提供了快速、可编程的有序数据基础,这些数据必须快速写入、可预测地读取、可靠地持久化,并围绕产品进行塑造,而不是强迫产品进入固定的数据库模型。

ZoneTree 提供什么

ZoneTree 为您提供了真正的存储引擎所需的核心部分:

  • 有序键值存储
  • 高吞吐量写入
  • 持久存储
  • 预写日志记录
  • 实时备份和恢复
  • 可配置的 durability/performance 权衡
  • 正向和反向迭代器
  • 可搜索范围扫描
  • 原子读-修改-写操作
  • 交易乐观
  • 自定义序列化器
  • 自定义比较器
  • 后台维护和压实
  • 内存中和磁盘支持的操作
  • 针对大于 RAM 的数据集的内存敏感操作
  • MIT 授权开源

ZoneTree可以直接作为有序键值数据库使用,也可以作为上层系统的存储基础。

安装

dotnet add package ZoneTree

快速启动

using ZoneTree;

using var zoneTree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/my-zone-tree")
    .OpenOrCreate();
using var maintainer = zoneTree.CreateMaintainer();

zoneTree.Upsert(1, "Hello ZoneTree");

if (zoneTree.TryGet(1, out var value))
{
    Console.WriteLine(value);
}

有序迭代

ZoneTree 按顺序存储密钥。这使得它适用于索引、前缀布局、时间序列模式、范围扫描和自定义数据模型。

using var iterator = zoneTree.CreateIterator();

iterator.Seek(100);

while (iterator.Next())
{
    Console.WriteLine($"{iterator.CurrentKey}: {iterator.CurrentValue}");
}

还支持反向迭代:

using var iterator = zoneTree.CreateReverseIterator();

iterator.Seek(1000);

while (iterator.Next())
{
    Console.WriteLine($"{iterator.CurrentKey}: {iterator.CurrentValue}");
}

原子添加或更新

ZoneTree 为跨 LSM-tree 段的读取-修改-写入场景提供原子操作。

zoneTree.TryAtomicAddOrUpdate(
    key: 42,
    valueToAdd: 1,
    valueUpdater: (ref int value) =>
    {
        value++;
        return true;
    },
    result: (in int value, long opIndex, OperationResult result) =>
    {
        Console.WriteLine($"{result}: {value} at {opIndex}");
    });

Plain Upsert 是最快的写入路径。原子方法与其他原子方法同步,适用于必须将读取、决定和写入作为一个逻辑操作的操作。

对于普通并发写入,请使用常规写入 APIs。它们专为高通量使用而设计。仅当新值取决于现有值时才选择原子方法。

需要 使用
设置或替换值 Upsert
仅当 key 不存在时添加 TryAdd
删除键(如果存在) TryDelete
写入删除标记而不检查存在性 ForceDelete
从当前值递增、追加、比较并设置或更新 原子方法
协调多个键之间的坐标变化 交易

您可以在同一个 ZoneTree 中混合使用这些写入模式。例如,热计数器键可以使用原子读-修改-写操作,而普通记录继续使用快速 Upsert。这使得每个工作流程只需为其所需的协调付费。

交易

对于协调的多密钥更改,请打开事务 ZoneTree。

using var zoneTree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/transactional-zone-tree")
    .OpenOrCreateTransactional();

var tx = zoneTree.BeginTransaction();

zoneTree.Upsert(tx, 1, "first");
zoneTree.Upsert(tx, 2, "second");

var result = zoneTree.PrepareAndCommit(tx);

Console.WriteLine(result.Result);

当您的数据模型需要跨多个键进行协调时,请使用事务。对于简单的高吞吐量写入,非事务性 API 通常是更好的路径。

删除

ZoneTree 使用删除标记。这在基于 LSM-tree 的存储引擎中很常见:首先写入删除,然后在压缩期间删除过时的数据。

对于许多原始类型和可为 null 的类型,ZoneTree 可以提供默认删除行为。您还可以定义自己的删除标记。

相同的机制可用于 TTL-style 记录。在值中存储过期时间戳,并在值过期时使删除谓词返回 true。 ZoneTree 会将过期的记录视为已删除的记录,并且 maintenance/compaction 可以稍后删除过时的数据。

using var zoneTree = new ZoneTreeFactory<int, int>()
    .SetDataDirectory("data/deletable")
    .SetIsDeletedDelegate((in int key, in int value) => value == -1)
    .SetMarkValueDeletedDelegate((ref int value) => value = -1)
    .OpenOrCreate();

zoneTree.Upsert(42, 100);
zoneTree.TryDelete(42, out var opIndex);

如果你的数据库不需要删除并且你想正常存储默认值,可以禁用删除:

using var zoneTree = new ZoneTreeFactory<int, int>()
    .DisableDeletion()
    .OpenOrCreate();

维护保养

CreateMaintainer() 返回可选的、即用型后台维护 协调员。它响应ZoneTree事件,启动并跟踪合并操作 根据可配置的策略,定期释放非活动读 缓冲区和缓存条目。

using var zoneTree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/app")
    .OpenOrCreate();

using var maintainer = zoneTree.CreateMaintainer();

zoneTree.Upsert(1, "value");

维护者是调用者拥有的并且是一次性的;处置等待其跟踪 合并操作即可完成。没有维护者,调用者负责 通过状态、事件和操作来定义和协调维护 由 zoneTree.Maintenance 曝光。

内存使用情况

ZoneTree 专为大于内存的数据集而设计。它不需要将整个数据库加载到RAM中。

内存使用主要来自活动的可变段、等待合并的冻结内存段、磁盘块缓存、稀疏索引、固定活动段的迭代器以及合并或 WAL 处理期间使用的临时缓冲区。

最重要的写入端内存控制是可变段大小。默认情况下,ZoneTree 在 1_000_000 记录之后开始将可变段移向磁盘。对于小键和值来说,这是一个很好的默认值,但是存储大字符串、文档或有效负载对象的应用程序应该降低可变段记录限制,以保持内存使用可预测。

ZoneTree 作为本机 .NET 存储引擎构建,并使用 .NET 垃圾收集器作为其设计的一部分。 GC 针对现代应用程序工作负载进行了高度优化,有助于保持 ZoneTree 简单、安全和快速,而无需手动内存管理。

观察内存使用情况时,请记住 .NET 可能会保留释放的内存以供重用,而不是立即将其返回给操作系统。即使在合并或释放段后,进程内存也可能保持较高水平,因此当您需要精确测量实时 ZoneTree 数据时,请使用 .NET 内存诊断。

using var zoneTree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/app")
    .SetMutableSegmentMaxItemCount(10_000)
    .OpenOrCreate();

对于读取密集型工作负载,内存主要由缓存行为和活动工作集决定。对于写入密集型工作负载,内存主要由可变段大小以及维护将冻结段移动到磁盘的速度决定。

耐用性和存储

ZoneTree通过磁盘段和预写日志来持久化数据。最近的写入进入可变段并根据配置的 WAL 模式受到保护。稍后的维护会将数据移动并合并到磁盘段中。

ZoneTree 默认使用异步压缩 WAL。这是大多数持久性数据库的推荐起点,因为它可以启用 WAL 保护,同时保持非常高的写入吞吐量。

需要 考虑
推荐高吞吐量持久WAL模式 异步压缩 WAL
普通同步 WAL 写入路径 同步 WAL
压缩 WAL 具有同步调用者写入路径和尾部持久性权衡 同步压缩WAL
cache/temp/rebuildable 数据的故意 no-WAL 边界 无 WAL

磁盘段还可以使用压缩和不同的段布局。这些选项有助于调整磁盘空间、读取模式、合并行为和文件大小边界。

对于长时间运行的服务,ZoneTree还支持内置非事务树的实时备份。实时备份创建完整的备份代,同时树保持打开状态以供读取和写入,并且可以通过 ZoneTreeFactory 恢复本地备份代。

ZoneTree 可以构建什么?

ZoneTree 是从头开始设计的,作为可扩展系统的存储引擎基础。它本身并不是一个分布式数据库;相反,它提供了在其之上构建分区、复制或特定于域的数据平台所需的有序键空间、持久性控制、迭代器、操作索引、事务和维护挂钩。

它可以为:

  • 定制数据库
  • 索引层
  • 全文搜索引擎
  • 文件存储
  • 图店
  • 活动商店
  • 时间序列存储
  • 持久队列
  • 本地优先数据层
  • 专门的存储系统
  • 服务器端数据平台

引擎提供有序、持久的核心;您的产品定义了其上方的模型。

ZoneTree.FullTextSearch

ZoneTree.FullTextSearch 是一个基于 ZoneTree 构建的全文搜索库。

它为需要通过 ZoneTree-backed 存储进行快速文本搜索的应用程序提供索引和搜索功能。

存储库:

  • ZoneTree.FullTextSearch

文档

官方文档:

  • 文档主页
  • 入门
  • 读写
  • 值可变性
  • 内存使用情况
  • WAL 模式
  • 生产清单
  • zonetree.dev

官方支持

在ZoneTree上构建生产系统?

需要有关架构、性能、可靠性、存储设计、故障排除和生产准备情况直接指导的组织可以使用官方支持。

支持服务可以包括优先问题处理、已确认缺陷的优先错误修复、私人技术沟通、升级指导和预定的咨询会议。

从这里开始:

  • zonetree.dev/support

相关文章

精彩推荐