写在前面
在文字出现之前,绑绳子是人类储存知识和信息的主要方式。此后,从竹简和纸的发明,到工业时代的磁盘存储,再到信息时代的数据库,存储方式不断创新,“存储力”不断提升。
11月3日,在2022云起大会上,蚂蚁链区块链存储引擎LETUS(日志结构化高效可信通用存储)经过4年的技术研究和测试验证,正式发布。
这款面向区块链可信数据存储的技术产品,不仅用于解决当前蚂蚁链和区块链行业的规模化发展问题,也为Web3时代提供“可信生存”支持。
我们认为,随着大量数据和数字资产在数字世界中流通,可信数据的“生存能力”将与电力网络的承载能力一样重要。
本文希望通过对LETUS的深度技术解读,回答读者普遍关心的关键问题:LETUS是什么?要解决的主要问题是什么?为什么坚持“可验证的结构”?为什么要自学?以及未来何去何从?
文|乐途网技术总监田世坤
01背景是什么?
从2009年序号为0的创世街区诞生至今,十多年过去了,“中本聪”依然神秘。而区块链技术的发展,因为公链、token、开源的推动,已经没有了神秘感。
经过几代技术演进,基于比特币的UTXO模型,诞生了应用更广泛、支持可编程智能合约的区块链技术:通过密码学、共识算法、虚拟机、可信存储等技术,多个参与者执行相同的“指令”,完成相同的业务逻辑,如账户转账或合约调用,维护不可篡改或伪造的业务数据。
简单来说,这种账本数据库可以看作是一个去中心化的复制状态机,可以防恶防篡改。它执行智能契约描述的业务逻辑,状态机通过日志(块数据)生成新的状态(状态数据):
Block:包括交易、收据、世界状态根Hash等信息,类似于数据库系统中的日志,但blocks通过Hash锚定,防止篡改,不会被删除。(块数据记录了区块链的每一笔交易,比如Alice给Bob xx转账)
状态:记录账户、资产、业务合同数据等状态信息,类似于数据库系统中的表格数据,需要可验证、可追溯。(状态数据记录区块链中每个账户或智能合约的当前状态,例如Bob账户的剩余xx)
上行链路数据的特征可以概括为以下三个:
持续增长:从创建块开始,账簿数据随交易持续增长,保存期长;
多版本:交易修改状态数据生成新版本,系统提供版本历史查询和校验功能;
可验证:交易和账户状态由Merkle Root Hash锚定在块头,存在证明由SPV(简单支付验证)提供;
区块链应用可以通过经过认证的数据结构(比如Merkle tree)进行验证和溯源。我们认为,Web3的“生存性”中一个非常重要的元素就是可验证性,而我们今天看到的区块链存储的瓶颈,大多来自于可验证结构广告(如Merkle tree)的低效访问和查询,这也正是蚂蚁链LETUS重点解决的难题。
我们想要什么?
随着时间的推移和连锁交易的增加,对存储容量的需求也在增加,随之而来的是块数据存储成本的大幅增加;与此同时,在线状态数据的规模也不断增加,可验证的数据结构不断扩大,导致交易性能随着账户规模和历史状态数据的增加而不断下降。
2019年,蚂蚁金服推出了供应链金融业务,大家都很兴奋。然而,这种兴奋并没有持续多久。随着程序运行的时间越来越长,问题逐渐暴露出来。
供应链是面向ToB的,不像ToC一直有数据。在某个时刻(比如每天晚上),可能会有一个状态数据非常大的事务进来。跑了一个星期,发现表现越来越慢。
平台TPS的衰减与存储直接相关,与共识和虚拟机无关。随着业务合同中数据的不断写入,存储性能大大衰减。
要想在技术上长期支持数十亿账户,稳定支持每天数十亿的交易,存储规模和性能的问题是必须要克服的。
期间团队也尝试了各种技术方法优化他,得到了一些缓解。但经过多次尝试后发现,随着数量的增加,性能下降是不可避免的瓶颈,需要从本质上解决。
我们需要从问题的表象去分析问题背后的原因。
区块链应用可以通过可验证数据结构进行验证和溯源,但可验证数据结构会带来读写放大(问题1)和数据局部性(问题2)。
为了实现数据管理,存储系统需要对数据进行分页/分层和排序。比如KV数据库基于LSM树分层有序存储数据,MySQL数据库基于B树数据结构对数据进行分页和索引排序。
业内现有的实现方式多采用基于LSM架构的通用键值数据库,在数据库之上运行独立的Merkle树来实现可验证性,比如:
以太坊:MPT(Merkle Patricia Tree)
Diem:JMT(水母Merkle树)摇滚
背后的核心矛盾是:
每修改一次0merkle树的状态数据,哪怕只改变一千伏,都需要从叶节点到根节点。每一层节点被重新编码后,都被写入KV数据库。比如上图中,爱丽丝给鲍勃转账,需要写到Merkle树的两个叶子节点和三个中间节点,最坏的情况下需要写到几十个中间节点。
2MERKLE树的节点的键是完全随机的(比如内容哈希,然后哈希就是键),数据局部性非常不友好。比如在RocksDB中,为了使sst文件在Level中有序,即使没有垃圾,仍然需要逐层进行数据压缩,从而消耗大部分的磁盘读写带宽;
03数据规模越大,Merkle树本身的层数越多,需要额外写入的key-value就越多,DB中的数据越多,后台数据管理(比如压缩流量)的成本就越大,消耗大量的磁盘和CPU资源。
除此之外,吞吐量、延迟等存储性能(问题3)、持续增长下的存储成本(问题4)、单机存储下的规模瓶颈(问题5)也是需要解决的问题。
你面临什么样的挑战?
随着过去几年的快速发展,区块链的业务场景对交易吞吐量和响应时间的要求越来越高,很多技术也在向迭代开发推进,比如PBFT、HoneyBadger、MyTumbler等高性能共识算法,BTN等网络基础设施,JIT加持的WASM虚拟机,高效的并行执行技术。
但是相比较而言,存储的性能对区块链平台的整体性能影响很大。对于面向2C的数字采集业务(如捕鲸,需要支持spike),交易TPS和延迟要求极其严格;但是对于需要存储链中大量数据的存证业务来说,大容量存储的成本是相当可观的。
为了支持业务的长期可持续发展,我们总结了区块链存储面临的核心挑战:
规模:业务账户规模可达数十亿,状态数据和版本历史规模分别需要支撑到数十亿和数十亿;
性能:传输事务需求可达10万TPS,100毫秒延迟,要求性能不能受单机瓶颈制约,数据规模持续增长时性能不会下降;
成本:随着事务的增长,存储容量不断增加,对存储空间和节点间带宽的占用居高不下。持续的业务增长需要低成本的存储。
这些问题在业内普遍存在。业内主要有三条技术路线:
路线a:削弱可核查性和可追踪性
路线b:优化KV数据库的存储,如实现键值分离和哈希索引的KV数据库(BadgerDB,ParityDB),访问通用分布式数据库(MySQL);
路线c:优化Merkle树,事务ID用作版本和树结构细化,如Diem JMT。
根据公开资料,主流存储架构如MPT LevelDB、JMT RocksDB、MySQL等。在区块链的产品中,目前还没有能完全解决上述五个问题的解决方案。在支持多版本、可验证的同时,很难满足10亿账户规模下的高性能、易扩展、低成本的业务需求。
我们做了什么?
我们自己开发了一套区块链存储引擎LETUS(日志结构高效可信通用存储),保证了完全可验证性和多版本能力。它不仅满足了块数据不可更改、可追溯、可验证的要求,还提供了对合同数据的友好访问、可扩展的存储规模、高性能和低成本。同时也满足通用性,统一管理块数据和状态数据。
LETUS在2022年云起会议上发布。
4年前不敢想象的能力现在都有了(以下数据是统一环境下的测试结果):
01大规模:通过存储集群的扩展支撑十亿账户规模,TPS超过12万,平均事务延迟小于150ms;
02高性能:与以太网MPT LevelDB等架构相比,存储层IO吞吐量提升10~20倍,IO延迟降低90%以上。平台端到端TPS在7×24高压压力测量时不随数据量的增加而衰减;
03低成本:与MPT LevelDB架构相比,磁盘带宽减少95%,空间占用减少60%;与Diem JMT RocksDB架构相比,磁盘带宽减少约60%,空间占用减少约40%。
04进一步降低成本方案供用户选择:
(a)针对块数据容量和成本的持续增长,提供智能温控分层存储容量,并应用于押金、证书等业务,降低存储成本70%左右,同时降低运维成本。
(b)针对版本历史容量和状态数据成本的不断增加,提供范围扫描的批量切割能力,实现版本历史中状态数据的切割和背景空间的回收。当账户规模为十亿时,使用链式原生存储可以减少近90%的状态存储空间。
但这背后是技术架构的飞跃。从下图左边的可验证数据结构KV数据库架构,升级到现在的LETUS存储引擎,架构更简单,系统更高效。
比如Alice给Bob转账,只需要写增量数据,而不是7个Merkle树节点,所以数据局部性更友好。比如Alice和Bob的账户数据是按照块号排序的,而不是hash random。
你是怎么做的?
回顾这四年,我们经历了三大阶段。
阶段1:优化开源思想
第一年,为了满足业务的迫切需求,需要在有限的时间内实现百亿账户规模,交易TPS。从现有系统入手,基于开源MPT到自研FDMT,对状态树进行深度优化。同时优化了RocksDB数据库,增加了并发,提高了媒体性能。
一系列优化措施缓解了问题,但仍无法从根本上解决。比如数据量增大后,写放大还是几十倍,数据在底层存储还是随机分布的。
第二阶段:自主开发存储引擎
为了彻底解决上述所有问题,我们不得不重新思考存储引擎的设计。
核心设计
针对读写放大(问题1)、数据局部性(问题2)和性能(问题3),我们结合区块链特性重新设计了存储引擎的架构层次、关键组件和索引数据结构,如可验证数据结构的读写行为、链上数据的多版本需求、仅追加和防篡改等。
根据区块链的特点,根据可验证数据结构的读写行为,重新设计了存储引擎的体系结构、关键组件和索引数据结构
02多版本Merkle树节点聚合成页面,提高了磁盘友好性。页面存储采用Delta编码思想,避免原地更新(结合Bw-tree思想)。修改状态数据时,主要是保存增量,定期保存基线,减少写放大和空间占用。
03对页面存储实现基于版本的存储和检索,索引页按块号顺序写入,在索引文件中排序,核心数据结构为B树变体,实现有序数据局部性;
04利用区块链场景数据的附加写入和不可变的特点,架构采用日志结构化的思想,通过日志文件组织数据;
05数据与索引分离,数据按块号顺序写入数据文件,通过异步IO、协同并发等提高系统并发性。索引多模,块状态通用,除Merkle树支持状态数据,有序B树支持块数据;
06当前最新版本的Merkle tree缓存在内存或全部内存中。链上的契约在执行时,如果存在,可以直接读取,不需要访问page来重放,加快了契约执行的速度。
基于这些核心设计,在性能提升的同时降低了成本,链平台交易的TPS、延迟等性能指标不会随着数据规模的增大而衰减。
成本降低
虽然存储资源占用大幅减少,但链上的数据仍然面临持续增长带来的高成本问题(问题4)。
基于LETUS架构的后台数据治理框架,我们可以轻松扩展和实现数据迁移/压缩/垃圾收集等治理策略。基于这些策略,我们可以为用户提供进一步降低成本的能力,并根据他们自己的业务特点选择使用它们:
(1)智能温控分层存储:根据性能和成本对存储介质进行分层,通过对不同介质中数据分布的智能温控调度,在后台自动将冷数据迁移到廉价介质(如NAS)上,从而降低整体存储成本,实现容量扩展,不受单个磁盘空间的限制。
(2)范围扫描批量切割:对于版本历史Merkle树和状态对象,基于版本排序和内置Merkle树,用户可以指定目标块号范围切割,通过页面边界扫描、批量索引、数据切割和垃圾收集释放存储空间,进一步降低状态数据的开销。
刻度扩展
为了解决问题5,LETUS采用分布式存储架构,将单个共识参与者的计算和存储分开。计算层和存储层可以部署独立的集群,通过高性能的网络通信框架访问数据读写。
为了对海量状态数据进行灵活切片,保证每个区块链参与者哈希计算的一致性,将数据切片成256个最小存储单元(MSU),一个或多个MSU组成一个状态数据分区,所有数据分区调度到多个物理机。从而实现规模弹性扩展,解决单机存储的容量瓶颈和带宽瓶颈。
第三阶段:生产着陆
为了让业务在全面铺开的同时平稳运行,为了能够开飞机换发动机,在这几年的研发过程中,我们做了充分的准备,并分阶段逐步落地:
2021年5月,基于乐视存储引擎的块数据冷热分层,版权存管业务灰度上线,降低存储成本71%,解决了容量瓶颈,降低了运维成本。
2021年8月,基于乐途存储引擎的状态数据,数字采集平台“鲸探”双写灰度上线,成功支持秒杀场景;
2022年2-6月,历史状态数据切割、存储服务架构升级等乐途引擎生产准备就绪,在数字化采集、版权存管方面全面实施,从灰色双写切割为单写;LETUS单写意味着对硬件资源的要求大大降低。我们全面缩减了《鲸探》制作环境的云资源。缩减后,链台性能水位提升200%,存储成本降低75%。
06总结与展望
蚂蚁总是坚持
蚂蚁坚持技术自研,确保在共识协议、智能合约、网络传输、存储引擎、跨链技术、区块链隐私计算等领域处于世界领先水平我们始终认为,自主研发技术是建立长期可持续竞争力的关键。
在“可信生存”的赛道上,还需要提前布局进一步的技术壁垒,比如契约结构化查询语言,实现对链式契约的结构化、可验证的查询能力,提升开发者体验;快速同步和多形态节点提高了组网效率和节点成本的灵活性;以及Web3等潜在的技术生态。
创新永远在路上。接下来继续沿着硬核技术方向突破,啃一些硬骨头,继续为整个价值互联网提供可靠的、可持续的生存能力。
-结束-