[原创] 如何理解EOS的性能设计 - 主链部分

最近看3.0源码发现跟之前理解有点出入,目前代码实现上跟白皮书上也有所出入,该文章需要更新修正

前言

EOS作为blockchain 3.0的代表,他的设计是比较超前的,也是目前最被看好的项目之一
本文从传统互联网码农思维,尝试讲述下EOS的性能方面的设计
本文只是涵盖了基础主链部分,暂不包括off-chain,side/sharding chain等类似技术

系列文章开篇,也欢迎大家关注我的币乎

EOS的一些基础

在理解EOS的性能之前,我们需要先回顾下EOS的数据结构和一些核心的设计,以便更好的理解

Block

​  Cycles (sequential)

​    Threads/Shards (parallel)

​       Transactions (sequential)

​           Messages (sequential)

​               Receiver and Notified Accounts (parallel)

EOS中 Cycles和Thread的概念是比较新颖的
下面我们重要看下Block,Cycle和Thread,其他概念可以参考EOS白皮书

今天看到EOS的白皮书更新了,把Threads名称改成了Shards(一个意思),Cycle上面加了Region层

Block

这里Block就是传统意义上的区块
不一样的是EOS中每个块生产者在自己的time slot中是批量生产多个块的(目前为6个)

demo
《[原创] 如何理解EOS的性能设计 - 主链部分》

Cycles

Cycles的概念是EOS中引入的,Block被分割成多个cycle组成,块生产者可以在他的当前块中,生产多个Cycle, 也可以称Cycle为Block中的“小链”

懒人画图:
Block[Cycle,Cycle,Cycle…] <—
Block[Cycle, Cycle,Cycle…]

这样做的好处是

  1. 提升了消息交互的效率,后面的Cycle可以依赖前面Cycle的数据,而不需要等完整的block(Cycle生成完会立刻异步广播出去)
  2. 使网络资源的使用更平滑,降低传输毛刺,是的块生产者的交接开销在1~2 TCP RTT,不管块有多大

demo (下图user_input中就是trasaction,一个trasaction对应多个messages/actions)
《[原创] 如何理解EOS的性能设计 - 主链部分》

Threads/Shards

引入Threads的概念,主要是为了并行执行,BlockProducer在打包Cycle的时候,可以利用多core资源进行并行打包,相关(参考trasaction的scope字段)的交易/消息调度路由到同一个Thread,由单独的core处理,Thread与Thread之间数据不共享,EOS主网刚上的时候是所有的交易由单个core进行打包

OK,数据结构方面就不再展开了,下面我们进入本文的重点,
性能,一般是在指定use case,指定资源消耗,指定并发的情况下,系统的吞吐和延迟
下面我们看看EOS是如何最优化区块链的性能的

如何最大化吞吐量 – TPS

有了上面的概念,我们开始讲讲影响区块链吞吐的一些因子,以及EOS是如何优化这些因子的

优化数据密度

优化数据结构(比如merkel tree branch的优化),编码等,待整理EOS的优化点

最大化打包效率

打包效率直接影响了单位时间Block内的交易数量(或Cycle数量)
对于几乎Non-Blocking的EOS来说,是吞吐的最直接最重要因子,为什么btc等打包效率不是最重要的?因为有太多的blocking time(共识开销)
EOS会分多次迭代来优化打包效率

  • 单线程优化
    这里主要是处理流程、热点函数、异步、批量、网络、协议、执行引擎(解析->JIT)等的优化,EOS 6月主网上线时主要为该阶段的优化
  • 多线程共享内存
    初步提升打包并行度,利用多core的资源提升吞吐,估计做到N/2倍的单线程性能,N为core的数量

    因为EOS中,需要对多租户进行带宽、计算、存储、数据库等资源的限流,而这个限流策略是针对整个链来说的,所以多core上运行的线程/进程一般情况下需要进行相关的原子操作及一些memory barrier

  • 多线程不共享内存
    多core并行处理没有资源竞争(没有cas没有memory barrier),这种是最理想的情况了,把之前多core需要共享的context,进行分片,每个core/Thread都使用自己独有的context,共享数据进行多core分片后,性能都会比不分片要好的多

目前eos中,mongodb用来存储block/trasaction,主要用于查询(如eostracker)

chainbase 支持无限undo的高性能内存数据库,存储合约状态数据等

ipfs 存储文件,其中chainbase内存数据库是重点,目前多core并发write貌似会加mutex锁?

EOS在年底之前会进行多次的迭代,因为并不会改变区块的协议,而且整个网络可以平滑的进行升级

EOS并行化的挑战 之限流

《[原创] 如何理解EOS的性能设计 - 主链部分》

  • 对多个core/thread进行context分片后,无法做到不依赖全局统计数据
  • 在并行计算的时候为了性能,不会实时全局统计,必须要以一种相对大粒度的方式来更新统计数据,如Block粒度或Cycle粒度,事实上EOS中是以Cycle维度,交易先打包,Cycle处理完发送前进行limit统计校验,如果有账户超过了限制,通过修正的方式(类似于branch miss-prediction),来UNDO这些交易,分支预测失败是会明显损失性能的,如何抵御此类攻击?

EOS并行化的挑战 之热点

热点问题是任何分布式系统绕不过去的话题,比如一般关系型数据库的热点行事务问题,EOS中同样也存在这个问题,热点账户只能分配一个thread进行处理,从而限制了该账户相关的tps

最大化打包时间占比

打包时间就是BP真正干活的时间

    打包时间*打包效率/块间隔 = 整个链的吞吐
    打包时间/块间隔 = 打包时间占比
    (块间隔 - 打包时间)/出块间隔 = blocking时间

EOS中块生产者等到快到出块间隔了才停止生产cycle(Block),几乎没有块大小限制,一个Time Slot可以出6个块,然后再交接到下一个区块,而这个交接因为异步传输和地理感知的编排,延迟会很小
所以EOS中整个链的blocking时间占比很小,几乎做到non-blocking block chain !

最小化块间隔

出块间隔当然越小越好,毕竟块的数据承载量/出块间隔就是单链的吞吐嘛
另外,出块间隔缩小可以降低交易确认时间
EOS的出块间隔是0.5秒,主要依赖如下技术

  1. 21个BP地理感知的编排出块顺序,当前BP与下一个BP的io latency小
  2. 当前BP在块处理完后可以在1 RTT传输到下一个BP
    因为Cycle已经异步传输了
  3. 当前的BP不会同步依赖任何其他BP

以上可以保证当前BP和下一个BP的交接时间最小,从而保证了即使是0.5秒的间隔,系统一样会比较稳定
而其他pow/dpos+随机投票/pbft,下一个节点的随机属性,和块本身可能需要多个RTT传输,就算没有其他共识开销,也做不到0.5秒的间隔,大家可以估算下中美延迟*2RTT,光是网络开销就0.5秒了,而且还是直连的模式,事实上存在多跳传播,这类系统,降低块间隔到秒级会大幅增加分叉和不稳定性

如何最小化延迟

块传输延迟 I/O Latency

块传输延迟指的是区块链使用的p2p网络,在传输block时消耗的时间
EOS不需要等待block生产完毕,而是基于Cycle的粒度进行广播,在生产块的同时进行异步传输,所以块生产结束到下一个节点收到块的latency,可以降低到一个1 RTT
同时又充分平滑的利用网络资源
如果不是生产块和传输块同时进行的模式,对于大块,需要多个RTT才能传输完毕(在充分优化TCP网络的基础上),而且在传输大块的过程中,可能会产生网络的抖动

可见延迟 Visibility Latency

可见延迟表示用户A发起一笔交易,用户B最短什么时间在区块中可见
这个延迟在一般的区块链系统中,就是等待打包+打包时间(块生成完)+广播的IO延迟
EOS中,可见延迟 = 打包时间(入Cycle,无需等block完毕)+广播的IO延迟

这里可能有些同学会问,为啥EOS的可见延迟没有等待打包这一说?

上面的章节(见最大化块生产时间)我们已经描述了EOS的BlockProducer其实是一直在打包(生成Cycle)中的,交易可以几乎无需等待打包入当前BlockProducer中的当前Cycle中,并在Cycle处理完毕就广播出去

当然,如果某些DAPP可以接受不入块的数据,那么可见延迟就是传统P2P的网络延迟了
我们这里还是指入块的可见延迟

共识延迟 Consensus Latency

共识延迟在区块链里是非常重要的,尤其对金融领域,这个延迟代表交易被网络确认的时间
说到共识延迟之前,需要简单回顾下EOS中的DPOS+BFT的共识算法

  1. 每一轮(主节点遍历一遍代表一轮,EOS中为63秒)选出21个主节点(BlockProducer)和100个备份节点
    // 当前轮的投票结果是取的上上轮的最后一个区块的结果
  2. 基于IO延迟感知,编排出块顺序(每个节点分配有自己的出块时间片)
    // 这个可以保证相邻出块节点间的io latency降低到最小
    // 因为需要2/3的主节点确认,所以这种伪随机编排并没有带来安全影响
  3. 主节点根据自己的time slot进行打包出块
  4. 其他主节点收到块后进行投票,这个过程是异步并行的
  5. 投票结果会写入到后面的区块中,当2/3个主节点通过通过后,就代表区块不可逆
    不可逆表示节点无法忽略不可逆的区块而从之前的位置分叉,也就可以保证后面所有的分叉都可以看到该区块

完全不可逆

在上面的过程中,每个块都会由21个BlockProducer异步并行的进行BFT投票,大约1.5秒后,就可以被大于2/3个BlockProducer确认,也就是共识延迟为1.5

99%不可逆

EOS中官方给的平均99.9%不可逆是0.25秒

共识延迟在EOS中是可预测的,而不像别的DPOS机制或POW机制,共识延迟可能会大幅抖动

尤其是POW,首先他的共识延迟也不能叫共识,比如比特币,只需要6个矿工确认,6个矿工的确认时间是相对不稳定的,而且6个矿工可能有些来自于同一个矿池,所以并不是共识,而是暂时(几乎)不可逆而已

1.5秒的共识延迟对EOS来说是个非常大的优势,因为其他区块链都是数量级上的差距(包括pos/DPOS的其他变种)

我之前看到过一篇
Tendermint跟EOS的对比文章,这篇国内也有人翻译了,里面描述的eos的出块等数据应该是有问题的

EOS的数据,我们以BM的为准,具体可以参考
peer-review-of-cardano-s-ouroboros

长尾延迟 Trail/Peak Latency

长尾延迟是指可见延迟/共识延迟的毛刺
大家可能都遇到过长时间打包中甚至超时的转账交易
EOS中长尾延迟主要在入块(Cycle)阶段,比如你发的交易超过了你对于的资源占比
EOS中,因为是多账户资源隔离的,所以Peak Latency只会受自己的影响,而不会影响其他用户,另外,这种长尾延迟是可预期的

其实可预期延迟对于区块链来说也非常重要,我们这里怼一下大姨太

ETH中,可以用稍高的gas来阻塞其他用户正常的请求,这对其他用户来说,就是不可预期的延迟,有时入块很快,有时又超时,虽然一些客户端会提示gas设置,但是没有解决这个问题

总结

EOS 是 non-blocking 的区块链,异步、批量、并行机制最大化整个网络的吞吐,
就性能扩展方面,目前我没有发现其他项目可以媲美的,如果有,那么机制应该也是差不多的

本文只是粗略的理解EOS的性能设计,详细得看EOS源码,个人因为业余时间不多,另外同时在研究别的项目,如出现理解错误,希望指正,非常感谢

附几个问题的看法

EOS真能做到百万QPS吗

我觉得可以
EOS在打包速度上有着非常明显的提升空间,在网络和带宽不是瓶颈下,打包速度翻一倍,吞吐基本就翻一倍(因为打包时间/总时间接近1:1)
目前基于解释器执行的单线程版本已经可以做到QPS 1000,那么按预期,年底实现JIT执行多core并行不共享内存的版本,在128 CORE的机器下,不会偏离百万QPS太远
而这个性能迭代更新,不会影响整体协议部分,整个网络可以无感平滑升级

EOS会影响传统后端开发吗

我觉得
未来两年一半的初创公司会基于高性能区块链来开发,就好比现在基于云计算一样,前者不光是硬件成本,人力成本,运维成本,更低一筹
另外,区块链可以简化系统复杂度,为什么呢,举个例子,一般的局域网分布式系统中,需要避免脑裂,也就是同时多个master,这会带来严重的问题,需要专业的运维恢复所以对于强一致的系统,会牺牲可用性来保证同时只出现一个master, 区块链中,设计上就考虑了脑裂问题,也就是分叉问题,可以自动从分叉中修复过来而且,交易不会丢失不会报错,只会影响延迟,交易的处理都是异步的而一些基于同步调用模型的db(对于大多数关系型数据库,都是这类)来说,master挂了等于当时的交易全部失败,这需要依赖其他的机制来重试等

所以,赶紧学习智能合约开发DAPP吧~

以上属于个人观点,不构成投资建议呵

    原文作者:fish24k
    原文地址: https://segmentfault.com/a/1190000013906600
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞