在这个由三部分组成的系列中,我们将揭示能够显著改善在互联网计算机协议(ICP)上运行的应用程序的数据处理的技术成就。
此次升级是 ICP 路线图中的 Stellarator 里程碑,目前正在全网推广,Stellarator 是链上数据存储方面的一项突破,使每个子网能够承载超过 1TB 的内存,为之前受存储限制的数据丰富型应用程序带来了机遇。
这一进步使开发人员能够构建需要大规模数据处理的复杂应用程序,从而为区块链技术带来新的实用水平。
事不宜迟,让我们先来开始这个系列,看看 ICP 现在如何使用 Stellarator 更新来存储数据。
互联网计算机上的数据持久性
这篇博文概述了存储在互联网计算机的副本机器上的工作原理,特别关注了最近引入的基于日志结构合并树(LSMT)的存储的变化,其中包括在互联网计算机子网上实现更多复制存储,并使它们能够更好地处理繁重的工作负载。
互联网计算机由子网、虚拟机组成,这些虚拟机在 13-40 台副本机器上进行相同复制,每个副本负责执行发送到该子网上的容器的所有消息,并存储所有容器数据,因此,所有副本都具有子网的完整且相同的状态。
开发人员可以将容器部署到互联网计算机,容器与其他区块链上的智能合约类似,但可以执行更通用的计算,并且比其他链上的智能合约存储更多数量级的数据。
容器中保存的数据最终需要存储在某些物理硬件上,得益于最近引入的基于 LSMT 的存储层以及许多其他优化和改进,互联网计算机上的子网可以存储高达 1TB 的容器数据。
容器的大部分数据要么存储在其堆内存中(写入时高达 4GB),要么存储在其稳定内存中(写入时高达 500GB),还有其他形式的数据与容器相关,例如容器代码、飞行中的消息以及各种信息,例如控制器列表和 Cycles 余额。
ICP 的存储层弥合了容器存储(例如堆和稳定内存)与底层副本机的存储硬件(例如磁盘和 RAM)之间的差距。
作为 Stellarator 里程碑的一部分,存储层经过了广泛的重新设计和重新实施,以使 ICP 能够应对未来的可扩展性挑战,并解决旧存储层最重要的可扩展性瓶颈,所有相关更改均已于近期完成,互联网计算机现已运行新的存储层实施几个月。
本篇博文的其余部分介绍了将存储层重新设计为日志结构合并树数据结构的过程,重新设计旨在消除与存储相关的瓶颈,并为存储密集型容器的用户和开发人员带来更好的体验。
对于 ICP 用户来说,最值得注意的是,这项工作使得单个子网上的复制状态最近增加到 1TB,此外,重新设计还使互联网计算机能够更好地处理写入大量数据的容器。
检查点
一般来说,互联网计算机的存储层结合使用了磁盘上的持久存储和 RAM 中的临时存储,互联网计算机如何存储其状态的一个关键概念是所谓的检查点,检查点是整个子网状态存储在磁盘上的逻辑时间点。
检查点每 500 个块或每隔几分钟以确定性方式创建一次,这意味着所有副本都将在相同的高度写入相同的检查点,检查点以文件目录的形式存储在每个副本节点的磁盘上,目录结构如下所示(大大简化):
在这种结构中,每个容器都存储在自己的子目录中,并且每个容器目录包含用于堆内存、稳定内存和其他信息(如飞行中的消息)的单独文件,数据以检查点的形式保存到磁盘的原因有多种。
1. 数据持久性:副本机器可能随时重启,副本代码中可能存在软件错误,或者硬件可能有故障,或者数据中心的电源可能有问题,发生这种情况时,可以重新加载最新的检查点。
请注意,即使每 500 轮才创建一次检查点,副本也可以为非检查点高度重新创建状态,副本只需要最新的检查点以及检查点和最新状态之间的所有最终区块,由于所有执行都是确定性的,因此可以重放这些区块,并且保证重新创建的状态完全相同,必要的区块可以与检查点分开保存到磁盘,也可以从其他副本中获取。
2. 同步:所有(复制的)消息都由所有副本执行,因此,对于任何给定的高度 h,所有副本都应具有相同的状态,该协议通过首先对状态进行哈希处理,然后对生成的哈希进行阈值签名来防止分歧(即当某些诚实副本最终处于与共识状态不同的状态时),只有当至少 ⅔(更准确地说是 2f + 1)的副本同意相同的哈希时,才能创建这样的阈值签名,子网才能继续运行。
但是,互联网计算机的子网可以拥有较大的状态,在撰写本文时,限制为 1TB,在保持每秒最多 2.5 个块(互联网计算机上最快的子网目前做到的)的同时,在每个块之后对这么多数据进行哈希处理是不可行的,因此,互联网计算机仅对非检查点高度的状态的选定部分进行哈希处理,例如,包括每个容器的一些基本信息、对入口消息的最近响应以及发送到其他子网的 XNet 消息。
对于检查点,协议会哈希整个状态以获得名为清单的数据结构,此清单通过哈希检查点目录中的所有文件来计算,并包含分块为 1MB 块的所有单个文件的哈希,在清单计算结束时,将计算清单的根哈希,涵盖清单中的所有单个哈希,然后由子网对其进行阈值签名,计算清单可能需要数十秒,但这项工作只需每 500 个块进行一次,并且在后台与容器执行并行执行。
3. 状态同步:互联网计算机允许通过 NNS 提案更改子网拓扑,当副本节点加入子网时,它可以从其他副本节点获取最新的检查点,回想一下,检查点是文件的集合,因此,在使用其根哈希和子网的阈值签名验证清单后,状态同步协议可以逐块获取文件,同时将获取的块的哈希值与清单中的哈希值进行比较,如果所有检查都成功,则副本可以得出结论,即获取的状态对应于检查点高度处各个子网的商定状态,如果副本因其他原因落后,并且与健康状态的差距太大而无法赶上纯粹的块重放,则也会触发状态同步。
4. 最大状态大小:目前,最大状态大小为 1TB,而副本节点机器的 RAM 为 512GB,因此,不可能将整个状态加载到 RAM 中,互联网计算机使用 RAM 主要用于保存尚未持久化的最新数据,以及缓存数据以提高性能。
PageMap 和非检查点高度
由于每 500 个区块才创建一次检查点,因此 ICP 需要针对非检查点高度为容器提供不同的存储空间,存储层遵循的基本思想是,这些数据以最后一个检查点的组合形式存储在磁盘上,此后的任何更改都存储在 RAM 中。
PageMap 是副本针对子网状态的大部分内容的实现,子网状态的绝大部分是容器状态,特别是容器的堆和稳定内存。
目前,容器最多可以拥有 4GB 的堆内存、500GB 的稳定内存,并且总子网状态限制为 1TB,但所有这些限制将来都可能会发生变化,这两种内存都可以通过复制(更新)和非复制(查询)容器调用读取,也可以通过复制调用进行修改。
PageMap 数据结构旨在实现对内存的高效读写,以及支持高效写入检查点,一个特定目标是使性能与内存的总大小无关,请注意,PageMap 这个名称源于这样一个事实:所有读写的粒度都是 4KB 的页面,这与底层操作系统使用的页面大小相同。
PageMap 将状态存储在两个层中,第一层称为存储,是来自上一个检查点的文件,它们表示上一个检查点高度的状态,第二层,即页面增量,表示自该检查点以来的所有更改,并存储在 RAM 中。
从 PageMap 读取时,返回的数据要么从页面增量中获取,要么从检查点文件中读取(如果缺失),写入 PageMap 是通过使用新数据修改页面增量来完成的。
检查点生命周期
存储层的主要任务是将检查点写入磁盘并使所有 PageMap 保持最新状态,写入新检查点时,所有页面增量都会刷新到磁盘,从而更新所有 PageMap 的存储部分。
为了保证所有数据都得到保存,副本需要始终保留已进行阈值签名的最新检查点,这意味着不可能简单地覆盖旧的检查点文件,因为任何此类修改都会在新检查点完全写入之前更改上一个检查点,从而有丢失数据的风险,同时,每 500 轮将一个完整的检查点写入磁盘(最多 1TB)的成本将非常高昂,相反,创建新的检查点包括 3 个基本步骤:
将旧检查点“复制”到临时文件夹,称为提示;
修改提示以代表新检查点的数据;
将提示重命名为新的检查点目录(以便以原子方式创建新的检查点)。
第一步可能是最昂贵的一步,因为状态越大,复制文件所需的时间越长,因此检查点文件就越大。
然而,这正是检查点和日志结构合并树的文件格式发挥作用的地方,通过使用 LSMT,此步骤成本低廉,并且不会随状态大小而扩展,相比之下,在 LSMT 重新设计存储层之前,此步骤缓慢且不可预测。
日志结构合并树
日志结构合并树(LSMT)是一种广泛使用的数据结构,尤其适用于数据库,在互联网计算机上,它们被用作 PageMaps 存储部分的基础,它可以解决的一个特殊问题是,它简化了检查点生命周期的“复制”步骤,因为所有文件都只写入一次,并且永远不会被修改。
使用 LSMT,通过写入额外的覆盖文件来修改(逻辑)状态,要读取页面的值,算法首先检查最近写入的覆盖文件,看该文件中是否存在该页面,如果存在,则从该覆盖文件中读取页面的值,否则,检查下一个较旧的覆盖文件,在 Internet Computer 使用的实现中,如果页面不存在于任何覆盖文件中,则将其读为全零。
下图显示了一组代表容器状态的三个覆盖文件,垂直箭头显示对数据的不同读取以及最终读取数据的文件。
LSMT 的检查点生命周期如下所示:
将上一个检查点的所有文件硬链接到一个临时文件夹,称为 tip;
写入包含自上次检查点以来所有更改的新覆盖文件;
将提示重命名为新的检查点目录(为了原子性)。
关键在于每个覆盖文件只写入一次,并且永远不会被修改,这样,在磁盘上设置多个检查点并通过硬链接在它们之间共享一些文件是安全的,请注意,如果检查点生命周期尝试修改任何文件,则此相同过程将不起作用,如果文件有多个硬链接,则修改其中任何一个都会更改所有硬链接中的数据,这会篡改先前已认证的检查点。
日志结构合并树可能会存储同一数据范围的多个版本,这会导致存储开销,其定义为所有覆盖文件的大小与所表示数据的逻辑大小之比,此外,数据可能分布在多个文件中。
随着存储开销或覆盖文件数量的增加,存储层实现将安排合并,合并通过获取一组覆盖文件并将其替换为仅包含每条数据的最新版本的单个文件来重新组织数据,合并是为具有特别高的存储开销或文件数量的 PageMap 安排的,并且在后台执行,以便它们不会干扰容器消息的执行。
之前使用 Reflinks 的设计
互联网计算机最初的存储层并不依赖于 LSMT,从 2021 年互联网计算机诞生到 2024 年,存储层严重依赖于重新链接。
重新链接,有时也称为写时复制,是一种用于复制文件的文件系统操作,某些文件系统支持该操作,互联网计算机的副本使用支持该操作的 XFS 文件系统,重新链接与普通文件复制的不同之处在于它不会复制整个文件内容,相反,文件系统会记住原始文件和新文件之间共享哪些数据,重新链接与硬链接的不同之处还在于两个文件都可以彼此独立地修改。
在旧的存储层设计中,检查点生命周期的工作方式如下:
将上一个检查点的所有文件重新链接到一个临时文件夹,称为 tip;
根据自上次检查点以来的所有更改来修改提示中的文件;
将提示重命名为新的检查点目录。
一个潜在的优势是,PageMap 将由单个文件在检查点中表示,从而避免存储开销,但是,要修改文件以适应新的检查点高度,需要重新链接上一个检查点的相应文件,而不是硬链接。
LSMT 相对于 Reflinks 的优势
原则上,重新链接保证了硬链接的速度和复制的可用性,不幸的是,随着互联网计算机的数据需求不断增加(无论是 I/O 吞吐量还是总数据量),由于多种原因,重新链接变成了性能瓶颈。
1. 重新链接速度慢:重新链接文件所需的时间可能相差很大,在某些情况下可能只需要几秒钟,但在实验中,我们还观察到重新链接 370GB 需要长达 10 个小时,在 Internet Computer 的旧检查点逻辑中,10 小时的重新链接步骤会导致整个子网停滞 10 小时。
碎片化会导致较差的重新链接速度,在内部,XFS 文件系统维护将文件的各个部分映射到磁盘上的实际数据块的数据结构,当遍历这些数据结构的成本变得很高时,就会出现碎片化和较慢的重新链接速度。
碎片化尤其可能由以下序列触发:大量写入文件,然后重新链接它,大量写入其中一个副本,再次重新链接它,等等,不幸的是,考虑到互联网计算机上的检查点工作流程,大量使用的容器恰好会触发这种行为。
另一方面,硬链接具有一致的性能,不受任何碎片问题的影响。
在引入日志结构合并树之前,已经实施了许多权宜之计,这些措施包括手动对文件进行碎片整理(通过读取文件并将其写回)以及将文件写入更大的连续部分,这两种方法都以较大的写入放大为代价,并且仍然可能导致长达 30 分钟的停顿。
2. 最大状态大小:除了由于碎片过多而导致的非常长的重新链接时间之外,即使是中等程度的碎片,重新链接时间也会与子网存储的数据总量成比例,在存储层的先前实现中,互联网计算机规定每个子网存储量不得超过 700GB,这个数字在很大程度上取决于最多 20-30 秒内可以重新链接多少中等碎片的数据。
使用硬链接时,检查点时间不会以相同的方式随着数据大小而扩展,从而消除这一瓶颈。
3. 多线程性能不佳:检查点逻辑的目标之一是尽可能避免同步操作,因为在检查点期间,容器执行会停滞,自然,需要考虑的是,是否可以在执行继续的同时在后台执行重新链接(即使速度很慢),不幸的是,经验表明,不可能同时重新链接和读取文件,因此,与执行并行进行重新链接只会导致执行缓慢。
在新的存储层设计中,硬链接与执行并行进行,并且它们不会互相减慢速度。
4. 缓存:如上所述,从容器内存读取数据会同时从 RAM 读取数据和从底层检查点文件读取数据,重复读取同一个文件通常不会导致必须从实际硬盘或 SSD 多次读取数据,相反,这些数据会被操作系统缓存,不幸的是,重新链接会干扰缓存,因为首先重新链接文件然后从新副本读取不会使用缓存,因此,在互联网计算机上,在写入检查点后,人们会看到磁盘读取出现大量(且缓慢)的峰值,因为所有读取都会切换到新文件,此外,显式计算(即为达成共识而计算所有检查点文件的哈希值)也从更好的缓存中受益匪浅。
相反,当硬链接文件时,所有缓存都会被保留,任何最近读取或写入的数据,即使是在之前的检查点间隔内发生的,仍将被缓存,因此可以快速检索。
结果
LSMT 存储层于 2024 年第二季度的几周内推广到互联网计算机的所有子网,下图显示了副本代码升级前后的指标,其中红色垂直线表示启用 LSMT 存储层的时间。
第一张图显示了 w4rem 子网的检查点时间,该子网托管了用于比特币集成的容器,与许多其他子网相比,比特币子网托管的容器的堆和稳定内存都具有写入繁重的工作负载,因此,碎片化是该子网的一个特别令人担忧的问题。
从指标来看,检查点时间从 20 多秒缩短至仅 1-2 秒,这主要是因为消除了重新链接步骤,该步骤占据了 20 秒的大部分时间。
对于比特币容器用户来说,其好处是响应速度更快,在检查点期间,子网不会处理任何更新调用或复制查询,如果用户在检查点开始时向比特币容器发送更新调用或复制查询,则至少需要 20 秒才能收到响应,使用 LSMT 存储层基本上可以消除此类不一致的响应时间。
第二张图显示了 k44fs 子网上的最终确定率,最终确定率或区块率是子网每秒产生的区块数量。
互联网计算机将每轮执行的指令数限制为大致对应于其在一秒钟内可以完成的工作量的值,以便最终确定率可以保持在每秒 1 个区块以上。
在升级到 LSMT 存储层之前,完成率有规律地下降,这与检查点完全对应,检查点影响完成率主要有两个原因,首先是创建检查点所需的时间,在此期间不会执行任何块,升级后,这方面的影响会减少,因为检查点时间通常要短得多。
第二个原因是 LSMT 存储层的缓存行为更好,特别是,旧存储层实现中的重新链接步骤导致缓存失效,因此,在检查点之后,任何从其内存中读取的容器都会导致副本从磁盘获取该数据,这比存储在 RAM 中的缓存中可用的相同数据要慢几个数量级,新 LSMT 存储层不存在此问题。
如指标所示,升级后最终确定率的下降明显变小,这是因为检查点本身速度更快,不再需要重新链接,而且文件缓存也不再无效。
对于该子网上的容器用户来说,这意味着更快的响应时间和更高的吞吐量。
结论
围绕日志结构合并树数据结构重新设计互联网计算机的存储层是平台可扩展性和性能的一项重要投资,它不仅使一些内存密集型工作负载成为可能,还允许互联网计算机为容器提供更大的状态。
在人工智能和链上运行大型语言模型的背景下,对大数据进行操作的容器尤其有趣,此类容器不仅依赖于大量数据存储,还严重依赖 I/O 吞吐量。
此外,它还为后续改进奠定了基础,例如通过更好地利用并发性来减轻关键路径上的繁重工作量,从而使互联网计算机的响应速度更快,原始存储层的经验表明,避免重新链接对于实现这一点至关重要,而 LSMT 数据结构可以做到这一点。
您喜欢这篇文章吗?在 DFINITY Developers X 频道上分享您的想法,明天加入我们的 Stellarator 之旅第 2 部分,与 Luc Bläser 一起探讨增强正交持久性。
你关心的 IC 内容
技术进展 | 项目信息 | 全球活动
收藏关注 IC 币安频道
掌握最新资讯