优化互联网计算机内存系统的性能
互联网计算机区块链使得使用完全在链上运行的高级容器智能合约创建世界系统和服务成为可能,容器实现了自主服务可组合性,可以推动非凡的网络效应,几乎可以从根本上重新构想任何企业。
自 5 月网络创世以来,DFINITY Canister SDK 已被用于在互联网计算机上创建数千个容器智能合约,其中许多是完整的 Web 3.0 dapp。
互联网计算机区块链上容器和用户的快速增长提出了有趣的工程挑战,最近内存密集型容器的增加表明内存系统在重负载下存在性能瓶颈。
这篇博文描述了 NNS 20461 提案的性能优化,提供了有关扩展和 WebAssembly (Wasm) 内存的详细信息。
结果
在 9 月 14 日通过 NNS 20461 提案后,这些优化逐步部署到所有互联网计算机子网。图 1-3 显示了升级时优化对重负载子网的影响,您可以看到两个主要改进:
增加和更稳定的终结:断断续续的终结率从每秒 0.5 个区块恢复到每秒 1 个区块的预期水平。
改进消息执行时间:平均消息执行时间提高了约 3 倍,最大值提高了约 10 倍。
图 2. 优化推出前后的平均消息执行持续时间。
图 3. 优化推出前后的最长消息执行持续时间。
背景:正交持久性
容器可以接收和执行两种类型的消息:查询和更新。查询是只读的,因为查询在 Wasm 内存中执行的所有修改在执行后都会被丢弃。相比之下,更新消息的成功执行会自动保留所有内存更改,并使它们可用于后续更新消息和查询。这个概念被称为正交持久性。
任何正交持久化的实现都必须解决两个问题:
如何将持久内存映射到 Wasm 内存
如何跟踪 Wasm 内存中的所有修改,以便以后可以持久保存
当前实现使用页面保护来解决这两个问题,当消息开始执行时,我们将 Wasm 内存的整个地址范围划分为 4KiB 大块,称为页面。最初,使用操作系统的页面保护标志将所有页面标记为不可访问。
这意味着第一次内存访问会触发页面错误、暂停执行并调用我们的信号处理程序,然后信号处理程序从持久内存中获取相应的页面并将该页面标记为只读。对该页面的后续读取访问将成功,无需信号处理程序的任何帮助。
然而,第一次写入访问将触发另一个页面错误,并允许信号处理程序记住该页面已修改并将该页面标记为可读和可写,对该页面的所有后续访问(读取和写入)都将成功,而无需调用信号处理程序。
调用信号处理程序和更改页面保护标志是昂贵的操作,读取或写入大块内存的消息会导致此类操作的风暴,从而降低整个系统的性能,这是在重负载下观察到的性能瓶颈。请注意,信号处理程序是在互联网计算机推出之前编写的,其主要优先事项是正确性而不是性能。
背景:并发查询执行
容器一个接一个地按顺序执行更新消息,相比之下,查询可以相互并发运行并更新消息,对并发执行的支持使得内存实现更具挑战性。
想象一下,一个容器正在区块高度 H 执行更新消息,同时,仍然可能有一个在区块高度 HK 较早开始的长时间运行的查询,这意味着同一个容器可以同时激活多个版本的内存。
这个问题的一个简单的解决方案是在每个更新消息后复制整个内存,这会很慢,并且会使用大量存储空间。因此,当前的实现采用了不同的路线。它将修改后的内存页面保存在名为 PageDelta 的持久树数据结构中,该结构基于 Fast Mergeable Integer Maps。
每隔一定时间(即每 N 轮),就会有一个检查点事件,在克隆文件以保留其以前的版本后,将修改的页面提交到检查点文件中。图 4 显示了 Wasm 内存是如何从 PageDelta 和检查点文件构建的。
图 4. a) 检查点文件存储最后一个检查点的 Wasm 内存;b) 自上次检查点以来修改的页面存储在称为 PageDelta 的持久数据结构中;c) Wasm 内存是由信号处理程序通过复制检查点文件页面和修改页面来懒惰地构建的。
优化 1:内存映射检查点文件
第一个优化是内存映射检查点文件页面,这通过在同时运行的多个消息之间共享页面来减少内存使用,这种优化还通过避免读取访问时的页面复制来提高性能。信号处理程序调用次数保持不变,因此优化后信号风暴问题仍然存在。
优化 2:查询中的页面跟踪
查询修改的所有内存页在执行后都会被丢弃,这意味着信号处理程序不必跟踪查询的修改页面,但是信号处理程序的旧实现没有区分更新消息和查询。我们为查询引入了快速路径,在第一次访问时将页面标记为可读和可写,这种简单易行的优化使查询速度平均提高了 1.5 到 2 倍。
优化3:分摊预取页面
最有影响力的优化背后的想法很简单:如果我们想减少页面错误的数量,那么我们需要为每个信号处理程序调用做更多的事情。新的信号处理程序不是一次获取一个页面,而是尝试推测性地预获取更多页面。此处需要适当的平衡,因为预取太多页面可能会降低仅访问少数页面的小消息的性能。
优化计算紧接在当前页面之前的最大连续访问页面范围,它使用范围的大小作为预取更多页面的提示。通过这种方式,预取的成本由先前访问的页面分摊。因此,优化将内存密集型消息中的页面错误数量减少了一个数量级。
结论
最初的信号处理程序是在互联网计算机推出之前编写的,重点是正确性而不是性能,该区域需要针对性能进行优化也就不足为奇了。然而,互联网计算机的快速增长需要比预期更早地进行优化。这些优化消除了一个瓶颈,但随着互联网计算机的不断增长,可能会发现更多的瓶颈。
如果您对性能感兴趣 - DFINITY 正在招聘:
https://dfinity.org/careers/
致谢
感谢 Akhi Singhania、Alin Sinpalean、Dimitris Sarlis、Dominic Williams、Johan Granström、Kiran Joshi、Roman Kashitsyn、Saša Tomić、Stefan Dietiker、Stefan Kaestle 讨论想法和审查代码更改,还要感谢 Diego Prats 审阅了这篇博文。
作者:Ulan Degenbaev
(DFINITY 首席软件工程师)
翻译:Catherine
- 往 期 推 荐 -
DFINITY 开发者资助计划奖授予 102 项资助,价值 204 万美元
长按关注 DFINITY 微信公众号
随时答疑解惑
*添加小助手微信 comiocn 进交流社群