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.8.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 sidecar 中。

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

升级注意事项

Stable 主网在区块 36,976,000 激活了 v1.8.0。文档中的升级替换了二进制文件和两个配置文件,没有进行状态导出或快照重置。

v1.8.0 配置文件增加了新存储和提案路径使用的设置。备份 config.toml 和 app.toml,安装 v1.8.0 模板,然后恢复每个特定于节点的设置。

归档节点操作员还必须恢复其以前的修剪设置。分发的 app.toml 模板使用默认修剪,并且修剪的历史记录无法从本地节点恢复。

延伸阅读

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

接下来去哪里

  • 高性能 RPC:了解 RPC 层如何公开状态读取而无需与写入竞争。
  • 执行:了解执行如何写入此处介绍的存储层。
  • 升级节点:准备备份并在协调升级后验证节点。
  • 网络升级:查看 v1.8.0 的范围和激活详情。