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.tomlapp.toml,安装 v1.8.0 模板,然后恢复每个特定于节点的设置。

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

延伸阅读

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

接下来去哪里

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