(账户与合约是相关的,下文中提到账户是指账户下的合约)
EOS.IO的性能目标是要做到支持数百万的用户,要达到每秒百万级别的交易量(tps)。要达到这样级别的性能,除了需要硬件支持,还需要软件设计上的支持。
我们已经知道EOS.IO使用DPOS共识算法。目前使用DPOS算法的区块链有bitshares、steem、yoyow……他们的性能都还不错,能达到几千PTS甚至能达到一万PTS。像基于Steem的社交媒体平台Steemit,几乎可以媲美中心化的应用了,基本上可以说不用感知到区块链。
除了共识算法,还有权限设计,我在《重读EOS白皮书——权限》里介绍EOS.IO的权限设计。权限在一个区块里是只读的,如果用户的权限修改消息正在这个区块里执行,修改后的权限是要在下一个区块才起做用。EOS.IO把权限与具体的业务逻辑解耦,使得权限可以有更大的优化空间,也使得性能优化也有更大的空间。
想要提高性能,多线程是重要的优化点。把原本单线程执行的功能,使用多线程设计、执行可以巨大地提高系统性能。EOS.IO的白皮书里提到了多线程提升EOS.IO的性能。我们来看下EOS.IO的多线程设计。
要实现多线程执行某个功能、事务,就需要对共享资源、数据进行加锁,或使用互斥的技术实现对数据的准确修改。比如说某电商平台上有某个产品要举办秒杀活动,产品的数量是有限的,而人民群众的热情是无限的,要对共享数据——产品的数量——上锁,已避免被秒杀购买的产品数量大于实际设定的产品数量。如果没有锁,将可能导至商家出现亏损或信誉问题。
区块链共识依赖于确定的、可重复的行为( deterministic (reproducible) behavior)。区块链是由成千上万的节点共同维互,每个节点都会把事务执行一遍,执行事务的结果必须是一致,所以叫共识。这也意味着在区块链上不能使用锁、互斥的多线程技术。如果把这些技术用到区块链上,那么会出现不同的节点的状态不一致的情况。比如上面的秒杀例子,张三在某个节点秒杀成功了,而在另一个节点却秒杀失败了。
提高性能就要用多线程技术,但却不能使用几乎和多线程伴生的锁、互斥技术。EOS.IO如何解决这个问题呢?EOS.IO的多线程是在账户层面上,每个账户的消息是顺序执行的,这就报保证了账户相关的状态的一致性,又可以使用多线程技术来提高EOS.IO的性能。
EOS.IO的合约也可以产生一条新消息,这条消息并不会立即执行,正如上面提到的,多线程并行是在账户层面上的。新生成的消息的相关账户可能正在别的线程中执行。新生成的消息会并安排到下一个cycle或block中执行。
EOS.IO使用了一种数据结构来实现这样的多线程并发执行。每一区块中包含多个Cycle,EOS.IO将会顺序执行每一个Cycle。Cycle下是Thread数据结构,对应上面说的,每一个Thread其实对应的是一个账户。Thread这个结构是可以并发执行的。每一个Thread结构里包含了一定的事务,这些事务将顺序执行。每一个事务结构是有消息集合组成。在执行过程中可能会生成新的消息,这些将会被打包到下一个Cycle或者下一个区块,这取决于区块生产者的调度。(一个事务里包含了多个消息,这个不是很理解,难到不是一个消息一个事务吗?有明白的请不吝赐教)
(eos 的区块结构)
EOS.IO的这样的区块结构,不但能实现账户层面上的并行,还可以实现最小消息延迟。这里的延迟是指从一个账户(合约)发送消息到另一个账户(合约),并接到这条消息响应的时间。执行脚本生成的消息可以被包含在下一个Cycle中执行,也就是实现了通常说的区块内部通信。
除了会修改状态的消息,有些消息是只读类型的,脚本执行这些消息的时候只是简单的判断是否可以通过,而不会修该该账户的内部状态。这些消息将会打包到一个线程执行或多个线程中并行执行。(这些账户可能同时执行会修改状态的事务)白皮书里没有讲到如标识一条消息是只读或者标识某个合约不修改状态。
EOS.IO的设计里还将支持跨账户的原子事务,一个事务可以同时修改多个账户的状态,要保证这修事务同时成功或者同时失败。跨账户的消息将会被包含在一条事务中,相关联的账户也会被指派到同一个线程,此时相关联的账户只能处理这个消息,不能并行处理别的消息,不然账户可能会其他线程的修改状态。
尽管可以使用跨账户原子操作的方式,但EOS.IO并不建议使用这种方式。必须要用的话,也应该将相关的账户减到最小。这种方式对性能会有比较大的影响。
人们说EOS.IO要做区块链的操作系统,看起来的确是这样,它提供来账户、权限管理、以及消息调度、性能优化等等基础功能。当EOS.IO开发完成、实现了白皮书的设计目标,区块链创业公司只需要一个idea以及开发业务相关的合约,不在需要处理账户、权限等基础功能。
(如果你注册了steemit账户,请关注我)
(如果文章对你有用,请关注我的公众号)