“我的区块链能跑多少TPS?”“能不能达到‘官方’所说的峰值?”“为啥总是压不上去?是我的机器不够好吗?”
如今,区块链技术被广泛应用在各行各业中,也接受海量用户、海量数据的挑战,越来越多同学开始关注链与合约的性能。
本文分别从原理、实操和技巧三个方面,为大家提供了详尽的FISCO BCOS性能压测指引,结合实例进行演示,总结出压测实用技巧与常见问题,以便大家更好地提升性能。
压测这事,原理其实不复杂,起一个或一堆区块链客户端,先往链上部署一个用来压测的合约或者需要评估性能的智能合约,然后卯足了劲往链上“并发”发送交易,收到区块链返回的交易执行结果(交易回执)后,统计出TPS。
由于区块链分布式网络广播、交易排队打包、共识确认等流程还是比较漫长的,中间充满了技术细节,往往导致结果不如预期,这就需要在环境、参数、压测程序以及合约逻辑等方面下功夫,才能得到理想的结果(把计算资源用到极致)、以及确切的结果(我的环境峰值就这么高了)。
压测前先“调参”
压测这事一般来说是一个长时间的“力气活”,在启动之前,一定要先做好足够的准备。以下一些关键参数,要先调到“最优”。
总交易数:压测程序在一次压测中总共发送的交易数量。强调一下,如果没有达到一定数量级的交易,压测结果没有统计含义。比如实际TPS应该可以达到5000,那么只发几千到一两万交易的话,因为程序启动和停止等边界条件影响,结果意义不大,至少超过两个数量级的交易数(比如10万笔、整个过程持续1分钟以上),才能看出平稳处理阶段的TPS表现。
QPS(Queries Per Second):每秒请求数,即压测客户端发送交易的速率。形象地说就是:压测客户端能不能“喂饱”链节点,比如链的TPS性能在万级,那么一个压测客户端的发送能力是否足够,要具体评估,一个不够,就要起多个压测客户端,而且每个客户端发送的模式应该是异步的,如果每次都是发送一个交易然后同步等结果再发下一个,是很难“喂饱”区块链节点的(如何确保异步,参见SDK的接口定义)。
但是,QPS也不能过大,当QPS过大时,会让交易堆积在交易池中。这些堆积的交易不能被立即执行,使得测出的TPS会小于实际的TPS。
合约复杂度:合约的复杂度对TPS结果会有极大影响。合约复杂度简单的理解就是代码量(对应指令数)、数据量(具体来说就是合约里牵涉的状态数据量),还有很重要的一点是合约是否支持并行事务逻辑。并行才能用尽服务器资源,要达到并行处理效果,除了上一条所说的压测客户端需要异步发送之外,FISCO BCOS的合约是支持DAG并行计算的,一个普通合约,如果在事务上可以支持并行,打开DAG并行设置,才能用尽服务器上所有的CPU计算能力,否则实际上也是在“串行”处理,只用了一个CPU,效果肯定不会太好。
DAG并行合约开发参见:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/transaction_parallel.html)
链参数配置: 有几个关键的链参数和性能表现相关,包括多长时间出一个区块,一个区块里能打包多少个交易。在压测场景里,这几个数字要配置得比较合适,我们默认500ms尝试将交易池(大小:[tx_pool].limit)中的交易打包成一个区块(打包间隔:[consensus]. min_block_generation_time),每个默认最多1000笔交易(区块最大交易数:tx_count_limit)。
同时,节点会自动保证在1秒内出一个块。如果出当前区块的时间大于1秒,下一个区块会少打包一些交易,若小于1秒,会根据设置的区块最大交易数上限尽量打包交易。若单纯为了压测,推荐将打包间隔尽可能调小,并反复调节区块最大交易数,让出块时间均匀稳定的同时,尽量逼近最大值。此处推荐将打包间隔设置为1ms,区块最大交易数最低为10000笔起步,根据实际结果向上调整。可参考文末“FISCO BCOS 配置文档”进行配置。
硬件配置:如果想要得到尽量高的TPS,要采用性能更好的硬件。具体而言就是服务器核数越多越好,内存越宽裕越好;一定要用高速机械硬盘或SSD硬盘,慎用相对低速的网络存储设备,硬盘的IO速度对链的区块和状态写入速度有巨大的影响;网络带宽越大延迟越低越好,保证压测程序和链节点之间的网络,以及节点和节点之间的网络是畅通高效的。
其他调整:压测客户端和链的日志级别最好开到Error级,尽量地减少日志输出量。环境里如有其他占用资源(CPU、内存、硬盘网络等)的程序,不妨暂时退出。之前有开发者的压测把硬盘写满了,所以事先腾一下硬盘也是有必要的。
压测结果含义
正确/错误交易数:如果压测结果包含很多错误或超时的交易,那么本次压测的意义不大。一般来说达到99%及以上的正确率,对业务才有意义。
TPS(Transactions Per Second):每秒处理交易数,即区块链处理此类型交易的性能。
压测操作
使用已有压测程序Java-SDK-Demo
FISCO BCOS提供了基于 Java-SDK实现的压测程序:Java-SDK-Demo。
*旧版本中提供了基于Caliper的压测程序,欢迎各位开发者持续优化Caliper压测程序。在本文,更推荐使用Java-SDK-Demo。
Java-SDK-Demo Github地址
压测 FISCO BCOS 2+ 版本:
https://github.com/FISCO-BCOS/java-sdk-demo/tree/release-2.8.0
压测 FISCO BCOS 3+ 版本:
https://github.com/FISCO-BCOS/java-sdk-demo
压测场景
转账场景
KVTable场景
DMC场景
更多请查看压测程序目录
压测方法
参考项目下的README
操作实例
本操作以 Java-SDK-demo 中的转账场景进行举例。
转账合约:ParallelOk.sol
压测程序:ParallelOkPerf.java
步骤一:查看压测命令
*命令中提示的[tps]实际含义为QPS,即该压测程序的交易发送速率。
$ cd java-sdk-demo/dist/
$ java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf
Usage:
===== ParallelOk test===========
java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [parallelok] [groupId] [add] [count] [tps] [file] [enableDAG].
java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [parallelok] [groupId] [transfer] [count] [tps] [file] [enableDAG].
步骤二:执行压测程序
转账场景压测的操作分为两步:
1. 准备:批量生成转账用户并初始化用户金额(add)
*执行后,生成用户列表文件user1000.txt,下一步会用到。
# java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf parallelok] [groupId] [add] [count] [tps] [file] [enableDAG]
# 参数:压测parallelok合约,群组group0,操作是添加用户add,用户数1000,qps=1000,要生成的用户列表文件名,启动交易并行执行
java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf parallelok group0 add 1000 1000 user1000.txt true
2. 压测:用户间两两转账(transfer)
*可不断重复此步骤,调整参数进行压测。
# java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf [parallelok] [groupId] [transfer] [count] [tps] [file] [enableDAG]
# 参数:压测parallelok合约,群组group0,操作时用户转账transfer,总交易数10000,qps=1000,使用的用户列表文件,启动交易并行执行
java -cp 'conf/:lib/*:apps/*' org.fisco.bcos.sdk.demo.perf.ParallelOkPerf parallelok group0 transfer 10000 1000 user1000.txt true
步骤三:查看结果
TPS
包括错误交易:TPS(include error requests)
不包括错误交易:TPS(exclude error requests)
正确/错误交易数
validation:
user count is 1000
verify_success count is 1000
verify_failed count is 0
完整结果
Total transactions: 10000
Total time: 12676ms
TPS(include error requests): 788.8923950773114
TPS(exclude error requests): 788.8923950773114
Avg time cost: 1221ms
Error rate: 0.0%
Time area:
0 < time < 50ms : 21 : 0.21%
50 < time < 100ms : 1559 : 15.590000000000002%
100 < time < 200ms : 2460 : 24.6%
200 < time < 400ms : 318 : 3.18%
400 < time < 1000ms : 1562 : 15.620000000000001%
1000 < time < 2000ms : 1194 : 11.940000000000001%
2000 < time : 2886 : 28.860000000000003%
===================================================================
validation:
user count is 1000
verify_success count is 1000
verify_failed count is 0
压测自定义合约
开发压测程序,压测自定义合约,与开发一个区块链应用一样,可参考区块链应用开发文档,参考仿写即可。
以Ok.sol为例,该合约包含的是一个基础的链上资产转让逻辑,是比较精简的合约,适合用来检验链的基本处理能力。如果你的业务逻辑较为复杂,首先请清晰地理解这一点:合约逻辑越复杂,TPS越低。(所以我们推荐链上的事务尽量简洁,只包含需要多方共识的核心事务。)
1. 找出被压测的合约(Ok.sol);
2. 编译合约生成java代码(Ok.java),并集成入Java-SDK-Demo中;
3. 编写压测程序(PerformanceOk.java);
4. 编译代码并部署到你的压测环境;
5. 压测,且保证所有的交易结果都是正常的,错误的交易结果使压测意义不大。
所有开发均在Java-SDK-Demo中进行,需开发的三个文件及目录结构如下:
合约:Ok.sol
合约编译出的Java代码:Ok.java
压测程序:PerformanceOk.java
java-sdk-demo/src/main/java/org/fisco/bcos/sdk/demo
├── contract
│ ├── Ok.java
│ └── sol
│ └── Ok.sol
└── perf
└── PerformanceOk.java
性能提升技巧
当你辛辛苦苦地完成了一次压测,发现结果不是很满意,那么就要回过头从“调参”一节重新开始了。这里再强调一些关键技巧,可以让你对压测过程有更强的把控能力。
1. 环境:在压测的过程中,密切观察压测客户端和链的环境参数。包括:
CPU利用率,保证多个CPU的核都尽量跑满;
网络流量,判断网速是否已成为瓶颈;
硬盘IO情况(尤其是IO Wait指标),判断是否达到了存储能力的瓶颈;
内存,一般不会有太大的问题,但极端情况下,如果内存不足,压测进程有可能会挂住。
以上观察方法,都可以用基本的Linux(或对应操作系统)基础指令,作为压测执行者,对操作系统一定要足够熟练,对指令打印的信息要有足够理解。
2. 优化合约逻辑:如减少合约接口参数,慎用数组、Mapping等复杂的数据结构,精简合约里的计算逻辑、判断逻辑等,减少不必要的事件(Event),对大的数据考虑是否可以只将数据的哈希上链;确认是否可以采用DAG并行合约引擎。还有一个大杀器,就是采用FISCO BCOS预编译合约实现合约逻辑,对追求极致性能的开发者,非常管用。
3. 关注日志:包括压测客户端的日志,节点的日志,以及系统日志,尤其是里面是否有发生错误和警告,一旦出现异常,则应立刻针对性地处理,不然有可能影响压测结果。程序日志里一般会有详细描述信息,可以参照描述先做本地分析。
4. 高效交流:如果要在社群里咨询压测问题,建议把上面提到的配置先做充分检查,记录压测过程的软硬件指标,说清楚合约复杂度,先思考一下是否有串行、并行相关的问题和优化空间,并收集相关的日志信息,然后用多个截图或整合文档的方式一次性把问题发给社区小助手或其他专家小伙伴,以便高效和深入地探讨。
「FAQ」
---
Q FISCO BCOS在什么环境下压测达到2万以上TPS?
A 共识节点分别部署在单个服务器上,每台服务器24核32G内存,万兆网的配置,在链参数得到合理优化、合约并行计算的基础上,可以实现数万以上TPS。
Q 我的环境下只能压到1K,如何提升呢?
A 不同的合约对结果影响很大,有的合约在最好的硬件上可能也只能跑几百TPS,或者有一些坑被踩到了,比如是否同步调用合约、交易池开得太小等。可参考本文【压测技巧】,持续优化。
Q 我的CPU没跑满,是什么原因造成的?
A 最常见的原因是QPS没给够,其他的原因可能有:区块打包的交易数太少,可调大区块打包交易数;未采用并行合约;合约逻辑中存储量过大,存储成为瓶颈。
Q 我调大了QPS,但出现了很多错误交易,如何调整呢?
A QPS远大于实际处理的TPS,造成大量交易缓存在交易池中超时了,在压测中只保证QPS仅略大于TPS即可。
Q 采用Raft共识算法是不是比PBFT性能要高一些?
A 共识算法对TPS的影响很小,瓶颈在执行与存储。总的来说,压测过程是对性能的一种极致追求,不仅仅是个力气活,需要对操作系统、区块链系统的原理都有足够了解,熟悉各种参数配置,知道如何去收集数据、分析问题、找瓶颈和突破瓶颈,一次压测里可能会有多次的反复,最终得到理想的结果,会是一种成就和喜悦。祝你的应用速度和规模都插翅腾飞。
咨询交流更多问题,请扫码添加【小助手】加入官方技术交流群,与上万开发达人共同探讨。
压测程序目录:
https://github.com/FISCO-BCOS/java-sdk-demo/tree/main/src/main/java/org/fisco/bcos/sdk/demo/perf
ParallelOk.sol:
https://github.com/FISCO-BCOS/java-sdk-demo/blob/main/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/ParallelOk.sol
ParallelOkPerf.java:
https://github.com/FISCO-BCOS/java-sdk-demo/blob/main/src/main/java/org/fisco/bcos/sdk/demo/perf/ParallelOkPerf.java
区块链应用开发文档:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/tutorial/sdk_application.html
Ok.sol:
https://github.com/FISCO-BCOS/java-sdk-demo/blob/main/src/main/java/org/fisco/bcos/sdk/demo/contract/sol/Ok.sol
PerformanceOk.java:
https://github.com/FISCO-BCOS/java-sdk-demo/blob/main/src/main/java/org/fisco/bcos/sdk/demo/perf/PerformanceOk.java
编译合约生成java代码:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/tutorial/sdk_application.html#id6
FISCO BCOS配置文档:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/configuration.html
预编译合约:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/precompiled_contract.html
并行合约开发方法:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/transaction_parallel.html
了解更多干货内容,请关注FISCO BCOS开源社区公众号,访问FISCO BCOS代码仓库可下载项目所有源代码:https://github.com/FISCO-BCOS/FISCO-BCOS,欢迎点击页面右上角star收藏,获取最新版本。