Cloudbreak——Solana状态横向扩展架构

554 阅读4分钟

在这篇文章中,我们将介绍Cloudbreak,Solana的横向扩展状态架构

概述:内存、SSD和线程

在没有分片的情况下扩展区块链时,只扩展计算是不够的。用于追踪账户的内存在大小和访问速度上都很快成为瓶颈。一般来说,许多现代链使用的本地数据库引擎LevelDB不能在单台机器上支持超过约5000 TPS,这是因为虚拟机无法通过数据库抽象利用对账户状态的并发读写访问。

一个简单的解决方案是在RAM中维护全局状态。然而,期望消费级机器有足够的RAM来存储全局状态是不合理的。下一个选择是使用SSD。虽然固态硬盘将每个字节的成本降低了30倍或更多,但它们比RAM慢了1000倍。下面是最新的三星SSD的数据表,它是市场上最快的SSD之一。

0_rjRPk_av77fMNZbK.png

一次消费交易需要读取2个账户并写入1个账户。账户密钥是加密的公共密钥,而且完全是随机的,没有真正的数据定位。一个用户的钱包会有很多账户地址,每个地址的位数与其他地址完全没有关系。因为账户之间没有定位,所以我们不可能把它们放在内存中,使它们有可能彼此接近。

由于每秒最多有15,000次独特的读取,一个使用单个固态硬盘的账户数据库的简单的单线程实现将支持每秒7500次交易。因此,现代固态硬盘支持32个并发线程,因此可以支持每秒370,000次读取,或大约每秒185,000次交易。

Cloudbreak

Solana的设计原则是设计出脱离硬件的软件,以追求100%的利用率。

组织账户数据库,使32个线程之间可以并发读写是一个挑战。像LevelDB这样的普通开源数据库会导致瓶颈,因为它们没有针对区块链环境中的这一特定挑战进行优化。Solana并没有使用传统的数据库来解决这些问题。相反,我们使用操作系统所利用的几种机制。

首先,我们利用了内存映射的文件。内存映射文件是一个文件,其字节被映射到一个进程的虚拟地址空间中。一旦一个文件被映射,它的行为就像任何其他的内存。内核可以在RAM中保留部分或全部的内存缓存,但是物理内存的数量是由磁盘的大小而不是RAM的大小所限制。读取和写入显然仍然受到磁盘性能的限制。

第二个重要的设计考虑是,顺序操作要比随机操作快得多。这不仅对SSD来说是如此,对整个虚拟内存栈也是如此。CPU很擅长预取按顺序访问的内存,而操作系统很擅长处理按顺序的页面故障。为了利用这种行为,我们将账户数据结构大致分解如下:

  1. 账户和分叉的索引被存储在RAM中。
  2. 账户存储在内存映射的文件中,大小不超过4MB。
  3. 每个内存映射只存储来自单个已提交分叉的账户。
  4. 内存映射是随机分布在尽可能多的SSD上的。
  5. 使用写时复制(Copy-on-write)语义。
  6. 写入被附加到同一分叉的随机内存映射上。
  7. 索引在每次写入完成后被更新。

由于账户更新是写时复制,并附加到一个随机的SSD上,Solana获得了连续写的好处,并在许多SSD上横向扩展写,用于并发交易。读取仍然是随机访问,但由于任何给定的分叉状态更新都分布在许多SSD上,读取最终也是水平扩展的。

Cloudbreak还执行了一种垃圾收集的形式。随着分叉的最终确定和账户的更新,旧的无效账户会被垃圾回收,内存也被放弃了。

这种架构至少还有一个很大的好处:计算任何给定分叉的状态更新的Merkle根,可以通过连续读取来完成,这些读取是在SSD上横向扩展的。这种方法的缺点是失去了对数据的通用性。由于这是一个定制的数据结构,具有定制的布局,我们无法使用通用的数据库抽象来查询和操作数据。我们不得不从头开始建立一切。幸运的是,现在已经完成了。

Cloudbreak基准测试

1_k_JFp7vmxdp0IOSgURJNug.png

当账户数据库在RAM中时,我们看到了与RAM访问时间相匹配的吞吐量,同时随着可用核心数量的增加而扩展。在1000万个账户时,数据库不再适合放在RAM中。然而,我们仍然看到在单个固态硬盘上每秒读取或写入的性能接近100万。