本文共 7910 字,大约阅读时间需要 26 分钟。
\\\关键要点
\\
- 这项技术只适用于非常少量的场景。\\t
- 对于去中心化的分类账应用程序来说,Hyperledger Fabric在验证写入批次时使用MVCC(多版本并发控制)已经足够安全,但对于B2C初创公司来说还不够具有吸引力,因为这种方式可伸缩性不足。\\t
- 如果你可以保证所有交易的幂等性,那么就不必使用这项技术。\\t
- 这项技术仍然有些不成熟。\\t
- 尽管这是一个开源项目,但要真正应用到生产环境中,还需要更多云供应商的支持(这种情况可能会发生改变)。\
是一个具有三年历史的开源项目,大约两年前,它的代码库被迁移到GitHub上。我一直在关注这个开源项目。Hyperledger项目由Linux基金会托管,并主要由IBM提供赞助。他们致力于推动使用私有或许可的区块链。在公共区块链中,第一个解决加密难题的匿名矿工可以将分类帐的下一个区块提交到链上,而私有区块链使用诸如或之类的算法解决共识问题。
\\在区块链中,你可以使用CRUD的方式访问分类帐。你还可以在分类帐上存储被称为智能合约的迷你程序。当事务被提交给时,在链代码中执行的所有分类帐状态变更操作都具有原子性——要么所有操作都被提交,要么都不提交。如果链代码访问的底层分类帐数据在链代码提交操作时发生变更,事务将被中止。这个过程是自动发生的,并且是智能合约程序的重要组成部分。
\\发布Hyperledger Fabric的人还发布了另一个开源项目Hyperledger Composer,它让开发人员可以轻松开发Hyperledger Fabric和DApps(去中心化应用程序)的链代码。
\\Thoughtworks是一家技术咨询公司(被Apax Partners收购),它把自己定位为“由一群充满激情的人组成的社区,目的是彻底改变软件的设计、开发和交付”。他们每年发布两次技术雷达报告,为是否暂停、评估、试用或采用某些特定的技术提供建议。第18卷技术雷达(Technology Radar)于2018年5月发布,它将Hyperledger Composer放在试用环中。试用环的定义为“值得追求。非常有必要了解如何建立这种能力。企业应该在可以承担风险的项目上尝试这项技术“。
\\作为软件架构师,我对新兴技术进行了评估,并将Hyperledger Composer放在我自己的技术雷达中。在评估一项新兴技术时,我都会用它来实现一个简单的新闻源微服务。这些微服务提供了相同的功能,并且可以通过完全相同的方式进行负载测试。通过这种方式,我就可以将某项技术与其他技术进行对比,从而总结出它们的性能特征。我选择了新闻源服务,因为它在社交网络中普遍存在,人们也非常熟悉,并且它足够复杂,不是简单的方案就能解决,但又足够简单易懂,不至于迷失在实现细节中。我在上发布了这些微服务的源代码,以及用于对它们进行负载测试、收集和分析性能结果所需的源代码。本着同行评审的精神,我希望你们能够拉取这些代码,并自己尝试重现这些结果。
\\有了Hyperledger Composer,你就可以在服务器端使用JavaScript开发智能合约。它提供了一个原生客户端库,Node.js应用程序可以通过这个库访问分类帐,并将事务提交给智能合约。出于实验的目的,我使用已经开发好的Node.js微服务(请参阅代码库中的)作为统制。我将该微服务的源代码复制到一个新文件夹中(请参阅代码库中的),然后将所有对MySQL、Redis和Cassandra的引用替换为调用Hyperledger Composer客户端API。是这次实验中的测试项目。两个项目都使用了Elasticsearch,因为新闻订阅服务的基本功能之一是基于关键字的搜索,区块链不适合用来实现这项功能。与这个代码库中的其他大多数微服务一样,feed7使用Swagger来定义REST API。该规范可以在文件中找到。
\\你可以使用Hyperledger Composer创建一个由数据模型、操作数据模型的一组事务以及一组供事务访问模型数据的查询组成的业务网络。Hyperledger Composer可以与Hyperledger Fabric配合使用,Hyperledger Fabric的基本网络包括、默认对等体、业务网络对等体、证书认证服务和orderer。feed7微服务在业务网络中访问Hyperledger Fabric,你可以在文件夹中找到这个业务网络。
\\
\\图1:Feed7组件(测试)
\\在这个业务网络模型中,broadcaster是参与者。模型中还有friendship、inbound和outbound元素。friendship用于捕获两个broadcaster之间的联系。每个inbound元素都是相关broadcaster的新闻项,而outbound元素是由broadcaster发出的新闻项。这个业务网络中有两个交易:broadcaster之间可以交互,也可以向其他broadcaster发送新闻项。业务网络内唯一需要的查询是用于访问其他broadcaster的广播事务。
\\\async function broadcastParticipants(tx) {\\tconst factory = getFactory();\\tconst created = Date.now();\\tconst now = new Date();\\tconst k = tx.sender.participantId + '|' + created + '|';\\tconst outboundRegistry = await getAssetRegistry('info.glennengstrand.Outbound');\\tconst ok = 'Outbound:' + k + Math.random();\\tconst inboundRegistry = await getAssetRegistry('info.glennengstrand.Inbound');\\tvar o = factory.newResource('info.glennengstrand', 'Outbound', ok);\\to.created = now;\\to.subject = tx.subject;\\to.story = tx.story;\\to.sender = tx.sender;\\tawait outboundRegistry.add(o);\\tconst friends = await query('broadcasterFriends', { broadcaster: 'resource:info.glennengstrand.Broadcaster#' + tx.sender.participantId });\\tfor (i = 0; i \u0026lt; friends.length; i++) {\ \t\t const friend = friends[i];\ \t\tconst ik = 'Inbound:' + k + Math.random();\ \t\tvar inb = factory.newResource('info.glennengstrand', 'Inbound', ik);\ \t\tinb.created = now;\ \t\tinb.subject = tx.subject;\ \t\tinb.story = tx.story;\ \t\tinb.recipient = friend.to;\ \t\tawait inboundRegistry.add(inb);\\t}\}\\\
代码示例1:智能合约
\\在智能合约中调用的Hyperledger Composer API与Node.js DApp调用的API非常类似,但还是存在一些差别。在智能合约中需要使用async/await机制,而在DApp中需要使用promise。智能合约必须使用预定义的查询,而DApp可以动态构建和运行查询。从DApp中查询或检索参与者或元素时,你必须将常量“PID:”作为密钥的一部分,但通过链代码访问相同的数据时则不需要。
\\\function submitTransaction(bizNetworkConnection, transaction, from, subject, story, callback, retry) {\\tconst elastic = require('../repositories/elastic');\\tbizNetworkConnection.submitTransaction(transaction)\ .then((result) =\u0026gt; {\ \tconst retVal = {\ \t \t\"from\": from,\ \t \t\"occurred\": Date.now(),\ \t \t\"subject\": subject,\ \t \t\"story\": story\ \t};\ \telastic.index(from, story);\ \tcallback(null, retVal);\ }).catch(() =\u0026gt; {\ \tsetTimeout(() =\u0026gt; {\ \t \tsubmitTransactionRetry(bizNetworkConnection, transaction, from, subject, story, callback, 2 * retry);\ \t}, retry + Math.floor(Math.random() * Math.floor(1000)));\ \t });\}\\exports.addOutbound = function(args, callback) {\ const BusinessNetworkConnection = require('composer-client').BusinessNetworkConnection;\ const bizNetworkConnection = new BusinessNetworkConnection();\ bizNetworkConnection.connect(process.env.CARD_NAME)\\t.then((bizNetworkDefinition) =\u0026gt; {\ \t\tconst factory = bizNetworkDefinition.getFactory();\ \t\tvar transaction = factory.newTransaction('info.glennengstrand', 'Broadcast');\ \t\t transaction.sender = factory.newRelationship('info.glennengstrand', 'Broadcaster', 'PID:' + args.body.value.from);\ \t\t transaction.subject = args.body.value.subject;\ \t\ttransaction.story = args.body.value.story;\ \t\tsubmitTransaction(bizNetworkConnection, transaction, args.body.value.from, args.body.value.subject, args.body.value.story, callback, 2000);\\t});\}\\\
代码示例2:DApp调用智能合约
\\你可能已经注意到,在提交事务时使用了重试逻辑。这是因为Hyperledger Fabric在时使用了MVCC(多版本并发控制),很容易引发读取冲突错误,所以需要sleep一段时间,然后重试提交事务。
\\统制和测试使用了相同的负载测试应用程序,你可以在代码库的文件夹中找到它。负载测试在一个循环中创建了10个参与者,并为每个参与者提供两到四个朋友。它让每个参与者广播10个新闻项,每个新闻项由150个随机生成的数字组成。负载测试应用程序会启动三个线程,每个线程将90%的时间用于生成新闻项,另外10%用于测试搜索功能。
\\负载测试应用程序并不会直接调用新闻源微服务,而是调用一个名为的开源API网关,这个网关将负载测试应用程序的请求代理给新闻源微服务。Kong使用了http-log插件,以便将请求和响应日志发送到另一个微服务,后者又将与性能相关的部分批量发送到Elasticsearch。你可以在文件夹中找到Kong日志微服务的源代码。
\\我使用来可视化性能数据,包括吞吐量、平均延迟和百分位延迟。只要有可能,我总是会收集两小时内的性能指标摘要。
\\
\\图2:测试(即Hyperledger Composer和Fabric)outbound请求的每分钟吞吐量
\\ \\图3:测试(即Hyperledger Composer和Fabric)outbound请求的每分钟平均延迟
\\我进行了两次统制部署,每次都使用了m4.xlarge实例。其中有一次feed4服务运行在Docker容器中,而另一次则没有。使用Docker运行时吞吐量降低了6%,但延迟几乎没有差别。我也进行了两次测试部署,使用m4.xlarge实例部署Kong、Cassandra、Elasticsearch和负载测试应用程序。第一次测试在m4.xlarge上部署了Hyperledger Fabric、Composer、feed7业务网络和微服务,第二次测试使用了m4.2xlarge,以便比较扩展之后的性能差异。
\\
\\图4:Feed7部署(测试)
\\为了进行有效的比较分析,也因为生产配置不易获得,所以统制和测试都使用了开发配置。AWS CloudFormation为Hyperledger Fabric提供了一个模板,但它只能用于部署基础网络。除了IBM Cloud的广告之外,我能够找到的有关生产配置的唯一在线文档是VMware的一些人在上发表的博文。博文中提供的生产配置和图表表明,orderer使用了Kafka,但GitHub代码库中的文件显示的却是独立的OrdererType,而不是Kafka。说明那只是开发配置。源代码中有一个写道:“独立共识方案非常简单,一个给定的链只需要一个共识者。它接收通过Order/Configure传递进来的消息,对它们进行排序,然后使用blockcutter将消息切成块,再写入指定的分类账中”。
\\对于Hyperledger来说,在负载测试性能方面,既有好的一面也有不好的一面。不好的一面:Hyperledger版本的新闻源在吞吐量上减少了300多倍,比传统版本慢了三个数量级。好的一面是,增加一倍硬件能力让吞吐量提高了20%,并将延迟几乎减少了一半。
\\统制每分钟(RPM)持续发送超过13,000个outbound请求(即新闻广播),平均延迟为4毫秒,99百分位为9毫秒。对于m4.xlarge,测试平均每分钟有29个outbound请求,而m4.2xlarge则为38。m4.xlarge的平均延迟为4.7秒,m4.2xlarge的平均延迟为3.2秒。对于m4.xlarge,99百分位延迟为10.2秒,对于m4.2xlarge,99百分位延迟为4.9秒。
\\
\\图5:outbound性能比较,延迟以毫秒为单位
\\我还需要提到其他一些与性能低下有关的问题。统制程序的CPU和性能相关的指标很快就进入稳定状态,而测试中的相同指标随着时间的推移变得越来越糟。CPU的最大使用者是Fabric中的默认对等进程。这点令人感到惊讶,因为微服务总是访问新闻源业务网络,但它对应的对等容器并不是CPU密集型的。也许默认对等体被用来支持交易?我找不到从配置中删除它的方法。在生产配置中,你将拥有多个对等方,否则分类帐就不是去中心化的了。
\\对于测试和统制,一旦SSD上的数据库可用空间耗尽,微服务也就随之崩溃。对于统制,在发出近3000万个outbound请求后,Cassandra数据库出现可用空间不足。对于测试,在发出大约4,000个outbound请求后,CouchDB数据库出现可用空间不足。用于统制和测试的SSD存储具有相同的容量,即20GB。显然,存储效率目前不是Hyperledger Fabric项目开发人员的主要关注点。
\\最初,我认为新闻源应用程序将是区块链的一个很好的用例。负载测试应用程序的主要操作是添加新闻项,这看起来非常类似于添加项目到分类帐。然而,现在,我认为这种类比是很肤浅的。区块链的主要问题是防止所谓的双重花费(double-spend)问题——如果区块链不能阻止参与者两次花同一笔钱,那它又有什么用?对于公共区块链,通过未使用的事务输出或UTXO来处理这个问题。Hyperledger Fabric在验证写批次时通过对读取集进行MVCC控制来解决这个问题。Fabric确实有效率问题,但效率问题可以等它发展成熟之后再来解决,不够我认为使用MVCC来防止双重花费是造成低吞吐量和高延迟的主要原因。因此,新闻源事务基本上是幂等的。如果两个参与者以不同的顺序或多次与自己交友,或者以不同的顺序或多次向彼此广播项目,并不会造成不良后果。Fabric分配了大量的CPU时间和内存来防止出现会对新闻源产生重大影响的问题。
\\经过这次评估,我相信软件开发的未来不会被区块链吃掉。只有非常少的场景才需要这种高计算成本的自动化、有保证的分布式并发控制和验证。基本上,你需要一个无法进行幂等交易的市场。现在评估Hyperledger Composer还算不错,但以目前的成熟度来看,想要在不久的将来应用到生产中仍然是有问题的。Hyperledger项目都是开源项目,但在撰写本文时,要想应用到生产环境,云供应商提供的选项仍然很有限。
\\Glenn Engstrand 是Adobe公司的软件架构师。他的工作重点是与工程师合作,提供可伸缩且符合12 factor标准的服务器端应用程序架构。Glenn是2018年和2017年Adobe内部广告云开发者大会以及2012年波士顿Lucene Revolution大会的最受关注演讲者。他专注于将单体应用程序分解为微服务以及与实时通信基础设施的深度集成。
\\查看英文原文:
转载地址:http://ztqax.baihongyu.com/