fabric压力测试
文档链接:https://hyperledger.github.io/caliper/v0.4.2/fabric-config/new/
测试搭建1:https://blog.csdn.net/weixin_44029550/article/details/115708344
测试搭建2:https://blog.csdn.net/bean_business/article/details/108937601#comments_17089484
轻量级tape进行测试:https://github.com/Hyperledger-TWGC/tape
安装Caliper
使用Hyperledger Caliper来进行压力测试,支持fabric等多种区块链。
1、创建并初始化fabric网络
fabric的使用可以去参考其他教程。
cd test-network
./network.sh up createChannel
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
2、创建并安装
当前在test-network目录下,test-network目录下,也就是fabric-sample文件夹内。
#创建caliper工作区,并且创建三个文件夹
mkdir -p caliper-workspace/{networks,benchmarks,workload}
cd caliper-workspace
#创建package.json
npm init -y
# 安装caliper-cli
npm install --only=prod @hyperledger/caliper-cli@0.4.2
# 查看是否安装成功
npx caliper --version
# 绑定fabric SDK的版本
npx caliper bind --caliper-bind-sut fabric:2.2.3
1.0版本的测试标准
1、构建网络配置文件
vi networks/networkConfig.json
networkConfig.json
{
"version" : "1.0",
"name": "Caliper test",
"caliper" : {
"blockchain": "fabric"
},
"clients": {
"Admin@org1.example.com": {
"client": {
"credentialStore": {
"path": "/tmp/org1",
"cryptoStore": {
"path": "/tmp/org1"
}
},
"organization": "Org1",
"clientPrivateKey": {
"path": "../test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk"
},
"clientSignedCert": {
"path": "../test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
},
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
}
}
},
"channels": {
"mychannel": {
"created" : true,
"contracts": [
{
"id":"basic",
"version":"1.0.0"
}
]
}
},
"organizations":{
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
]
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\n<UNIQUE CONTENT>\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com"
}
}
}
}
其中"pem": "-----BEGIN CERTIFICATE-----\n<UNIQUE CONTENT>\n-----END CERTIFICATE-----\n"中的内容需要根据自己网络中生成的证书内容来更改。更改的内容为test-network/organizations/peerOrganizations/org1.example.com/connection-org1.json中的内容,如下。
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICWTCCAf6gAwIBAgIRAJ+VTDHrRJOm5VqlK9Htc+wwCgYIKoZIzj0EAwIwdjEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHzAdBgNVBAMTFnRs\nc2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjEwOTAyMDkyOTAwWhcNMzEwODMxMDky\nOTAwWjB2MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE\nBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0G\nA1UEAxMWdGxzY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFa47bwuy/7yiBMUhWyGS5NHrlgMuaifD5PB7pBcYuuvfVLJAcXIkakN\naaRoXHFdGGgcgUQaqNwVPgeGmt32gnejbTBrMA4GA1UdDwEB/wQEAwIBpjAdBgNV\nHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zApBgNV\nHQ4EIgQgBcgTzPtcCbjFrjQzY8d7BGRSDV3ZN0zN2FbTmBO8qw8wCgYIKoZIzj0E\nAwIDSQAwRgIhANTnKkm92hvPBU9QhjrWtNM7AjS9OgV03SgjQGlGHDwZAiEAsYQL\nnA+hCCSX7cEw5z/EUvWfZu8pfK6WVqKDxaa32p0=\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com"
}
}
},
2、构建测试工作负载模块
vi workload/readAsset.js
'use strict';
const { WorkloadModuleBase } = require('@hyperledger/caliper-core');
class MyWorkload extends WorkloadModuleBase {
constructor() {
super();
}
async initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext) {
await super.initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext);
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Creating asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId,
contractFunction: 'CreateAsset',
invokerIdentity: 'Admin@org1.example.com',
contractArguments: [assetID,'blue','20','penguin','500'],
readOnly: false
};
await this.sutAdapter.sendRequests(request);
}
}
async submitTransaction() {
const randomId = Math.floor(Math.random()*this.roundArguments.assets);
const myArgs = {
contractId: this.roundArguments.contractId,
contractFunction: 'ReadAsset',
invokerIdentity: 'Admin@org1.example.com',
contractArguments: [`${this.workerIndex}_${randomId}`],
readOnly: true
};
await this.sutAdapter.sendRequests(myArgs);
}
async cleanupWorkloadModule() {
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Deleting asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId,
contractFunction: 'DeleteAsset',
invokerIdentity: 'Admin@org1.example.com',
contractArguments: [assetID],
readOnly: false
};
await this.sutAdapter.sendRequests(request);
}
}
}
function createWorkloadModule() {
return new MyWorkload();
}
module.exports.createWorkloadModule = createWorkloadModule;
3、构建基准测试配置文件
vi benchmarks/myAssetBenchmark.yaml
test:
name: basic-contract-benchmark
description: test benchmark
workers:
type: local
number: 2
rounds:
- label: readAsset
description: Read asset benchmark
txDuration: 30
rateControl:
type: fixed-load
opts:
transactionLoad: 2
workload:
module: workload/readAsset.js
arguments:
assets: 10
contractId: basic
monitors:
resource:
- module: docker
options:
interval: 5
containers:
- all
4、运行Caliper基准测试
在已有的网络上进行测试。
npx caliper launch manager \
--caliper-workspace ./ \
--caliper-networkconfig networks/networkConfig.json \
--caliper-benchconfig benchmarks/myAssetBenchmark.yaml \
--caliper-flow-only-test \
--caliper-fabric-gateway-enabled \
--caliper-fabric-gateway-discovery
在caliper-workspace目录下生成report.html的性能测试报告。
2.0版本的测试标准
1、构建网络配置文件
vi networks/networkConfig.yaml
name: Calier test
version: "2.0.0"
caliper:
blockchain: fabric
channels:
- channelName: mychannel
contracts:
- id: basic
organizations:
- mspid: Org1MSP
identities:
certificates:
- name: 'User1'
clientPrivateKey:
path: '../test-network/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk'
clientSignedCert:
path: '../test-network/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem'
connectionProfile:
path: '../test-network/organizations/peerOrganizations/org1.example.com/connection-org1.yaml'
discover: true
2、构建测试工作负载模块
vi workload/readAsset.js
'use strict';
const { WorkloadModuleBase } = require('@hyperledger/caliper-core');
class MyWorkload extends WorkloadModuleBase {
constructor() {
super();
}
async initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext) {
await super.initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext);
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Creating asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId,
contractFunction: 'CreateAsset',
invokerIdentity: 'User1',
contractArguments: [assetID,'blue','20','penguin','500'],
readOnly: false
};
await this.sutAdapter.sendRequests(request);
}
}
async submitTransaction() {
const randomId = Math.floor(Math.random()*this.roundArguments.assets);
const myArgs = {
contractId: this.roundArguments.contractId,
contractFunction: 'ReadAsset',
invokerIdentity: 'User1',
contractArguments: [`${this.workerIndex}_${randomId}`],
readOnly: true
};
await this.sutAdapter.sendRequests(myArgs);
}
async cleanupWorkloadModule() {
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Deleting asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId,
contractFunction: 'DeleteAsset',
invokerIdentity: 'User1',
contractArguments: [assetID],
readOnly: false
};
await this.sutAdapter.sendRequests(request);
}
}
}
function createWorkloadModule() {
return new MyWorkload();
}
module.exports.createWorkloadModule = createWorkloadModule;
3、构建基准测试配置文件
vi benchmarks/myAssetBenchmark.yaml
test:
name: basic-contract-benchmark
description: test benchmark
workers:
type: local
number: 2
rounds:
- label: readAsset
description: Read asset benchmark
txDuration: 30
rateControl:
type: fixed-load
opts:
transactionLoad: 2
workload:
module: workload/readAsset.js
arguments:
assets: 10
contractId: basic
4、运行Caliper基准测试
在已有的网络上进行测试。
npx caliper launch manager \
--caliper-workspace ./ \
--caliper-networkconfig networks/networkConfig.yaml \
--caliper-benchconfig benchmarks/myAssetBenchmark.yaml \
--caliper-flow-only-test \
--caliper-fabric-gateway-enabled
在caliper-workspace目录下生成report.html的性能测试报告。
文件详解
1、网络配置文件
文档链接:https://hyperledger.github.io/caliper/v0.4.2/fabric-config/new/
name: Calier test #配置的名称,在本例中为“Caliper test”。
version: "2.0.0" #正在使用的配置文件的版本。“2.0.0”确保使用新的结构连接器
caliper: #向 Caliper 指示目标 SUT,并且可能包含本教程中不需要的其他开始/结束命令或 sut 特定选项。我们的目标是fabric网络。
blockchain: fabric
channels: #描述 Hyperledger Fabric 通道和部署在这些通道上的智能合约以进行基准测试。
- channelName: mychannel
contracts: #合约可以有 1 个以上感兴趣的合约(链码)ID。
- id: basic #实例化的合约名称
organizations: #具有与每个组织关联的身份和连接配置文件的 Hyperledger Fabric 组织的列表
- mspid: Org1MSP
identities: #需要实例身份
certificates:
- name: 'User1'
clientPrivateKey: #私钥
path: '../test-network/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk'
clientSignedCert: #公共证书
path: '../test-network/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem'
connectionProfile: #连接配置文件
path: '../test-network/organizations/peerOrganizations/org1.example.com/connection-org1.yaml'
discover: true
2、测试工作负载模块
文档:https://hyperledger.github.io/caliper/v0.4.2/workload-module/
工作负载模块在基准轮次期间与部署的智能合约进行交互。工作负载模块在@hyperledger/caliper-core/lib/worker/workload/$WorkloadModuleBase. 工作负载模块提供三个覆盖:
-
initializeWorkloadModule– 用于初始化基准测试所需的任何项目, -
submitTransaction– 用于在基准的监控阶段与智能合约方法交互 -
cleanupWorkloadModule– 用于在基准测试完成后进行清理
有关更多信息,查看Workload Configuration配置信息。
我们将推动的工作负载旨在对世界状态数据库中现有资产的查询进行基准测试。因此,我们将使用工作负载模块中可用的所有三个阶段:
-
initializeWorkloadModule– 创建可以在submitTransaction阶段中查询的资产 -
submitTransaction– 查询initializeWorkloadModule阶段中创建的资产 -
cleanupWorkloadModule– 用于删除initializeWorkloadModule阶段中创建的资产,以便可以重复基准
'use strict';
const { WorkloadModuleBase } = require('@hyperledger/caliper-core');
class MyWorkload extends WorkloadModuleBase {
constructor() {
super();
}
// 函数在每一轮之前由工作进程调用,为模块提供上下文参数:
/*
* workerIndex ( Number ) 实例化工作负载模块的从 0 开始的索引。
* totalWorkers ( Numberv ) 参与该轮次的工人总数。
* roundIndex( Number ) 当前执行回合的从 0 开始的索引。
* roundArguments( Object ) 基准配置文件中用户为该轮提供的参数。
* sutAdapter( BlockchainConnector ) 底层 SUT 的连接器。
* sutContext( Object ) SUT 连接器提供的自定义上下文对象。
*/
async initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext) {
await super.initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext);
// 要创建的资产数量将作为roundArguments.assets
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Creating asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId, //contractId,要使用的智能合约的名称,它存在于 Caliper 网络配置文件中
contractFunction: 'CreateAsset', //智能合约调用的指定函数
invokerIdentity: 'User1', //存在于 Caliper 网络配置文件中的要使用的身份。这可以是可选的,并且 caliper 将为您选择一个身份(来自适当的调用组织或默认组织),并且在本教程中将只选择 1 个身份,但为了完整性,示例明确定义了身份。
contractArguments: [assetID,'blue','20','penguin','500'], //传递给智能合约函数的参数
readOnly: false //是否执行查询操作,这里为false是因为要写入吧?
};
await this.sutAdapter.sendRequests(request);
}
}
// 该方法在基准测试阶段反复运行
async submitTransaction() {
const randomId = Math.floor(Math.random()*this.roundArguments.assets);
const myArgs = {
contractId: this.roundArguments.contractId,
contractFunction: 'ReadAsset',
invokerIdentity: 'User1',
contractArguments: [`${this.workerIndex}_${randomId}`],
readOnly: true
};
await this.sutAdapter.sendRequests(myArgs);
}
// 此函数用于在测试后进行清理
async cleanupWorkloadModule() {
for (let i=0; i<this.roundArguments.assets; i++) {
const assetID = `${this.workerIndex}_${i}`;
console.log(`Worker ${this.workerIndex}: Deleting asset ${assetID}`);
const request = {
contractId: this.roundArguments.contractId,
contractFunction: 'DeleteAsset',
invokerIdentity: 'User1',
contractArguments: [assetID],
readOnly: false
};
await this.sutAdapter.sendRequests(request);
}
}
}
function createWorkloadModule() {
return new MyWorkload();
}
module.exports.createWorkloadModule = createWorkloadModule;
3、基准配置文件
benchmark configuration:https://hyperledger.github.io/caliper/v0.4.2/bench-config/
rate controllers:https://hyperledger.github.io/caliper/v0.4.2/rate-controllers/
Monitors and Observers:https://hyperledger.github.io/caliper/v0.4.2/caliper-monitors/#observers
基准配置文件定义基准轮次并引用定义的工作负载模块。它将指定在生成负载时使用的测试工作人员数量、测试轮数、每轮的持续时间、每轮期间应用于事务负载的速率控制以及与监视器相关的选项。
基准配置文件可能以 yaml 或 json 格式提供:这里我们将使用 yaml 格式。请注意,yaml 文件区分大小写,所有标签均为小写。
test: #包含基准测试信息的根级别块。
name: basic-contract-benchmark #测试的名称
description: test benchmark #基准的描述,在本例中为“测试基准”。
workers: #一组键,用于定义后续基准测试中使用的 worker(单独的 worker 客户端实例)的数量。
type: local #目前未使用
number: 2 #指定用于执行工作负载的工作进程数。
rounds: #将按顺序进行的一组不同的测试轮次。轮次可用于对不同的智能合约方法或以不同方式的相同方法进行基准测试。
- label: readAsset #用于回合的唯一标题标签。
description: Read asset benchmark #正在运行的回合的描述。
txDuration: 30 #测试持续时间的规范,以秒为单位
rateControl: #速率控制类型,带有选项。
type: fixed-load
opts:
transactionLoad: 2 #使用fixed-load旨在保持 2 的恒定交易压力的速率控制器?
workload: #要使用的工作负载模块,带有要传递给模块的参数。传递的所有参数都可以roundArguments在工作负载模块中使用。
module: workload/readAsset.js
arguments:
assets: 10 #就是测试工作负载模块的assets数量
contractId: basic
4、基准测试结果
生成的报告将详细说明每一轮基准测试的以下项目:
- 名称 – 基准配置文件中的轮名
- Succ/Fail – 成功/失败交易的数量
- 发送速率 – caliper 发出交易的速率
- 延迟 (max/min/avg) – 与发出事务和接收响应之间所用时间相关的统计信息(以秒为单位)
- 吞吐量 – 每秒处理的平均事务数
您已经成功地对智能合约进行了基准测试。您可以改变基准参数并添加资源监视器来重复测试。
使用fabric-sample进行性能监控
监测并推送(不推荐)
参考链接:https://hyperledger.github.io/caliper/v0.4.2/caliper-monitors/#prometheus-monitor
不推荐推送到Prometheus,会造成性能直接下降,瓶颈应该在push-prometheus,所以还是不要使用了,拉得很。
如何使用fabric进行性能监控可以查看fabric性能监控这篇文章。
将Caliper推送给Prometheus。
编辑prometheus.yml
#下面这个是给caliper使用的
- job_name: pushgateway
static_configs:
- targets: ['pushgateway:9091']
编辑prometheus和grafana的docker-compose.yaml文件。
#下面这个是给caliper使用的
pushgateway:
container_name: pushgateway
image: prom/pushgateway
restart: always
ports:
- 9091:9091
networks:
- test
depends_on:
- prometheus
benchmark下的文件也需要进行修改。
test:
name: basic-contract-benchmark
description: test benchmark
workers:
type: local
number: 2
rounds:
- label: readAsset
description: Read asset benchmark
txDuration: 30
rateControl:
type: fixed-load
opts:
transactionLoad: 2
workload:
module: workload/readAsset.js
arguments:
assets: 10
contractId: basic
observer:
type: prometheus
interval: 5
monitors:
transaction:
- module: prometheus-push
options:
pushInterval: 5
pushUrl: "http://localhost:9091"





