Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

存储 (StableDB)

Stable v1.4.0 使用 MemIAVL 替代了基于 LevelDB 的状态存储。MemIAVL 将一个状态快照存储在内存映射文件中,并在顺序写入预警日志中记录每个新区块的更改。

磁盘 I/O 为何成为瓶颈

每个区块都会改变应用程序状态。节点必须完成两个相关任务:

  1. 状态提交:计算并提交新状态的根哈希。
  2. 状态持久化:将更改的数据写入存储,以便节点以后可以恢复。
耦合的状态提交和存储

以前的 LevelDB 后端存储将这些任务耦合在一起。它还在后台压缩期间重写数据,以重新组织存储的记录,从而提高后续读取效率。

一次逻辑上的状态更新可能导致 10-50 倍的物理磁盘写入。这称为写入放大。执行必须等待一个由随机写入和压缩主导的存储路径。

MemIAVL 如何改变存储

内存映射文件 (mmap) 允许操作系统通过内存地址暴露文件内容。节点可以通过指针读取状态,而操作系统将所需的页面加载到其页面缓存中。

MemIAVL 结合了两种结构:

  • 快照:持久化状态树的内存映射表示。
  • 写入预警日志 (WAL):快照后所做原始更改的仅追加记录。
解耦的状态提交和存储

写入路径

每个区块按顺序将其更改集追加到 WAL 中。MemIAVL 不会将更新路由到 LevelDB 或触发压缩。因此,写入放大从 10-50 倍大约下降到一次写入。

MemIAVL 还将树节点分为两类:

  • PersistedNode 表示已存储在快照中的未更改子树。
  • MemNode 表示当前更新在内存中更改的子树。

当 MemIAVL 计算下一个根哈希时,它会停止在未更改的 PersistedNode 子树处。它仅哈希包含新 MemNode 数据的路径。

读取路径

当前状态读取遵循指向内存映射快照的指针。经常访问的页面保留在操作系统的页面缓存中,因此节点避免了为每个树节点进行单独的数据库查找。

历史状态和 VersionDB

MemIAVL 服务于当前状态和节点保留的快照。一个配套的 VersionDB 将历史版本存储在 RocksDB 副车中。

当节点必须回答比其最早保留的 MemIAVL 快照更早的历史状态查询时,您需要 VersionDB。这对于需要公开长期查询的归档节点和 RPC 服务尤为重要。

迁移注意事项

现有节点在采用 v1.4.0 时必须迁移其 LevelDB 状态。推荐的方法是本地快照导出和恢复。

基准测试显示,标准恢复每个验证器平均停机时间为 19.4 秒。并行恢复方案将平均时间缩短至约 2.6 秒。

验证器可以逐个以轮询方式进行迁移。保持至少三分之二的投票权在线,可以在迁移期间让网络继续生成区块。

进一步阅读

有关更多技术深度解析和实现细节,请参阅:

接下来去哪里

  • 高性能 RPC:了解 RPC 层如何公开状态读取,而不会与写入冲突。
  • 执行:了解执行如何写入此处介绍的存储层。
  • 升级节点:在协调升级后准备备份并验证节点。
  • 网络升级:查看完整的 v1.4.0 范围和推出状态。