1. 程式人生 > 實用技巧 >hyperledger caliper的使用(以Hyperledger Fabric為例)

hyperledger caliper的使用(以Hyperledger Fabric為例)

hyperledger caliper的使用(以Hyperledger Fabric為例)

目錄

1. 準備好被測試的Fabric 網路

此網路(Fabric的GitHub上給的樣例:fabric-samples)由兩個組織和一個單獨排序者組成,智慧合約使用javascript,已建立好並且準備進行智慧合約的效能測試

在預先存在的Fabric網路上使用Caliper對智慧合約進行效能測試

fabric-sample的安裝:

# 克隆Hyperledger Fabric samples repo的固定版本
git clone https://github.com/hyperledger/fabric-samples.git
cd fabric-samples
git checkout 22393b629bcac7f7807cc6998aa44e06ecc77426

# 安裝Fabric工具並將其新增到PATH
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.2.0 1.4.8 -s
export PATH=$PATH:$(pwd)/bin

# 建立並初始化網路
cd test-network
./network.sh up createChannel
./network.sh deployCC -ccn basic -ccl javascript

2. 使用caliper對被測試的網路進行效能測試

2.0 The Architecture of Caliper

2.0.1 Overview

Caliper是針對不同區塊鏈平臺執行基準測試的通用框架。Caliper的設計考慮到了可伸縮性和可擴充套件性,可以輕鬆地與當今流行的監控和基礎設施解決方案整合。因此,Caliper的結構乍一看可能有點複雜。

這一頁的目的是逐步讓你進入錯綜複雜的Caliper的架構,採取一步在一個時間。在本頁結束時,您應該熟悉Caliper的一般概念和API。隨著閱讀的深入,您會發現其他更技術性的參考資料

2.0.2 Bird’s eye view

就其最簡單的形式而言,Caliper 為被測試的系統產生工作負載,並持續監視這個SUT處理這個負載時的執行情況。負載處理完成後Caliper generates a report based on the observed SUT responses

下圖描述了這個簡單的檢視:

報告:

為了執行benchmark,Caliper需要幾個獨立於被測試的系統SUT的輸入

接下來將對這些 inputs做一個簡單的描述:

1. Network configuration file

根據測試系統(需要被測試的區塊鏈網路的情況進行填寫)

網路配置檔案(Network configuration file)的內容是SUT-specific(由被測試系統的不同而不同)。

該檔案通常描述SUT的拓撲結構:

  1. SUT的節點在哪裡(their endpoint addresses一般用域名錶示)
  2. 網路中存在哪些 identities/clients(網路中存在哪些節點)
  3. Caliper應該部署或互動怎麼樣的smart contracts

要了解 Network configuration file 的確切結構,請參閱相應的SUT connector documentations(我們將在本頁後面討論聯結器connector):

2. Workload modules

Caliper為SUT產生workload,然後這裡有一個module(模組)叫做工作負載模組:Workload modules,你說這個模組是幹什麼用的?

工作負載模組(Workload modules)是基準測試( benchmark)的大腦。

因為Caliper是一個通用的基準測試框架,所以它不包括任何具體的基準測試實現。

也就是說可以根據你的需求對測試需求進行個性化設定

注:Caliper負責給SUT提供工作負載,與之相對應的自然會為為SUT提供一些相關資訊,比如安排交易

當Caliper為一個給定的rounds安排TXs時,此round的workload module的任務是去產生這個交易的內容,並且去提交這些交易(Tx)

每個round可以有一個不同的與這一輪相關聯的workload module(工作負載模組),so separating your workload implementation based on phases/behavior should be easy.

因此基於階段或者行為設定你每一輪的工作負載模組是很方便的

因為每個round都可以設定與這個round相對應的Workload modules

Workload modules是一個簡單的Node.JS模組,這個模組必須輸出一個給定的 factory function。

除此之外,工作負載模組從邏輯上來說可以是任意的。實際上Workload modules可以是任何用Node.JS編寫的程式碼。

Note: For a more technical introduction to workload modules, see the corresponding page.

3. Benchmark configuration file

benchmark configuration 檔案描述了benchmark如何被執行。

benchmark:個人以為benchmark就是指的這次測試

benchmark configuration file告訴Caliper

  1. 它應當執行多少rounds
  2. 交易(TXs)應當以怎麼樣的rate被提交
  3. 並且哪一個 module將會產生交易(TX)的內容
  4. 它也包含監視monitoring SUT的一些設定

您可以將此檔案視為benchmark的“flow orchestrator”【流動的指揮者】

Benchmark configuration file:就是這次測試的指揮者,從全域性的角度進行指揮

在大多數情況下,這些 Benchmark configuration file的設定獨立於SUT,因此你可以輕易的複用這個檔案against different SUT types or versions.

Note: For a more technical introduction to the benchmark configuration file, see the corresponding page.

4. Benchmark artifacts

執行benchmark可能需要額外的 artifacts,這些 artifacts(構件)在不同的benchmark和runs之間可能有所不同。這些通常包括以下內容:

  • Crypto materials necessary to interact with the SUT.
  • Smart contract source code for Caliper to deploy (if the SUT connector supports such operation).
  • Runtime configuration files.
  • Pre-installed third party packages for your workload modules.

請參閱SUT connector configuration pages以獲取其他 necessary artifacts.

Note:
From here on out, we will refer to the introduced Caliper inputs simply as benchmark artifacts and denote them with the database symbol seen in the first figure.

注意:

從這裡開始,我們將會把上面介紹的Caliper的輸入作為benchmark artifacts

並且使用資料庫的符號表示他們,就像之前鳥覽圖裡的那樣

2.0.3 Multi-platform support

在進一步深入Caliper的架構之前,讓我們看看Caliper如何支援不同的SUT型別。

Caliper使用connector modules(聯結器模組)來隱藏不同SUT型別的特性,併為Caliper模組(和外部)模組提供一個統一的介面。

一個SUT聯結器為內部 Caliper modules以及workload modules提供了一個簡化的介面。

A SUT connector provides a simplified interface towards internal Caliper modules, as well as towards the workload modules.

因此,Caliper可以請求執行一些簡單的事情,比如“初始化connector/SUT”,而connector implementation將處理其餘的事情。

在初始化期間要執行的具體任務通常由network configuration file的內容(以及SUT支援的遠端管理操作)決定。

Note: For the technical details of how to implement a connector, refer to the corresponding page.

2.0.4 Caliper processes

Caliper 的程序

Caliper認為可擴充套件性scalability 是它最重要的目標之一(除了擴充套件性/靈活性extensibility/flexibility)。

從單個機器生成的工作負載可能會很快達到該機器的資源限制。

如果我們希望workload rate與被評估的SUT的scalability and performance characteristics匹配,那麼我們需要一種分散式方法!

因此,Caliper(作為一個框架)由兩種不同的services/processes組成:

  1. 一個manager process
  2. 許多 worker processes
  • manager process

    • 初始化:初始化SUT(如果支援的話),協調benchmark的執行(例如,schedules the configured rounds)

      benchmark:個人以為benchmark就是指的這次測試

    • 監視:handles the performance report generation based on the observed TX statistics.

      基於交易的資料生成報告

    • 協調:協調worker process

  • worker processes彼此獨立地為被測試的SUT產生workload(工作負載)

    即使一個worker process達到了其host machine的極限,使用更多的more worker processes(on multiple machines)也可以進一步增加Caliper的工作負載 rate

    增加Caliper的工作負載 rate:使得Caliper可以為被測試的SUT產生更多的工作負載,從而可以測試到相關SUT的效能資料

    因此,worker processes是Caliper可伸縮性的支柱。

    因為workload是由worker processes產生的

    The described setup is illustrated in the next figure.

對上圖的解釋:

Manager process:

  1. 初始化SUT
  2. 監視SUT
  3. 全域性協調各個Worker processes

Worker process:

為SUT產生Workload(工作負載)

注意:目前,我們將忽略分散式體系結構的技術細節,比如在不同程序之間的訊息傳遞。我們將在後面的一節中討論這個問題。

Note: For the time being, we will ignore the technical details of the distributed architecture, like the messaging between the processes. We will come back to it in a later section.

1. The manager process

Caliper的 manager process 流程是整個benchmark 的指揮者。它經歷如下圖所示的幾個預定義階段。

benchmark:個人以為benchmark就是指的這次測試

  1. 在第一階段,Caliper從network configuration file中執行startup script啟動指令碼(如果存在的話)。

    這個步驟主要用於本地Caliper和SUT部署,因為它提供了一種一步到位的方式啟動區塊鏈network and Caliper

    Note:SUT的部署不是Caliper的責任。

    從技術上講,Caliper只連線到一個已經執行的SUT,即使它是通過啟動指令碼啟動的。

    Caliper本身不啟動或者部署網路,網路的啟動和部署是由指令碼做到的。Caliper只負責和一個已經執行的網路進行連線

  2. 在第二階段,Calipe初始化SUT。

    這裡執行的任務高度依賴於SUT和SUT connector的capabilities。

    例如,he Hyperledger Fabric connector使用這個階段來create/join channels and register/enroll new users.

  3. 在第三階段,如果SUT和SUT connector支援這種操作((like with the Hyperledger Fabric connector【Fabric 的connector支援這種操作】),Caliper將smart contracts部署到SUT上。

    認為connector就是圖中的Adapter

  4. In the fourth stage Caliper schedules and executes the configured rounds through the worker processes.

    This is the stage where the workload generation happens (through the workers!)

    正如同之前所說Caliper的工作負載是 由worker processes產生的

    configured rounds:事先配置好的rounds

  5. In the last stage, after executing the rounds and generating the report, Caliper executes the cleanup script (if present) from the network configuration file.

    This step is mainly useful for local Caliper and SUT deployments as it provides a convenient way to tear down the network and any temporary artifacts.

If your SUT is already deployed an initialized, then you only need Caliper to execute the rounds and nothing else.

已經部署初始化好的網路只需要執行第四步

you only need Caliper to execute the rounds

幸運的是,您可以一個一個地配置每個階段,無論它是否應該執行。See the flow control settings for details.

The above figure(圖片) only shows the high-level steps of executing a benchmark.

high-level steps :比較巨集觀的步驟

為了簡單起見,省略了一些元件,比如monitor和worker progress observer元件。要了解有關這些components的用途和配置的更多資訊,請參閱監視器和觀察者文件頁面。

Monitors and Observers

2. The worker process

有趣的事情(從使用者的角度來看)發生在 worker processes內部。

A worker process starts its noteworthy tasks when the manager process sends a message to it about executing the next round (the 4th step in the previous section).

worker process 的important components如下圖所示

Caliper Workers的機制解析:

  1. 等待rate controller允許下一個Tx的提交
  2. 當rate controller允許後 worker process 將會把控制權交給 workload module
    • workload module 收集產生Tx所需要的引數
    • 收集完成後呼叫SUT connector的簡單API從而將 TX request 傳送給 SUT
  3. Main loop結束後Work Process向Manager Process傳送Process report

worker process的大部分時間都花在workload generation loop

workload generation loop:一個用來生成工作負載的迴圈

迴圈包含兩個重要步驟:

  1. 等待rate controller去允許下一個Tx的提交

    把rate controller(速率控制器)看作一個delay circuit延遲電路。

    Based on what kind of rate controller is used, it delays/halts the execution of the worker process (in an asynchronous manner) before enabling the next TX.

    基於你所選擇使用的的rate controller,在允許下一個交易之前,這個速率控制器將會以非同步的方式延遲或者暫停work process

    For example, if a fixed 50 TXs per second (TPS) rate is configured, the rate controller will halt for 20ms between each TX.

    比如,如果你設定了一個固定的交易提交速率(每秒50個交易),那麼rate controller將在每個TX之間暫停20ms

    每一輪的rate controllers可以在benchmark configuration file裡面設定

    對於你能夠區選的rate controllers,看 see the Rate Controllers page.

    Note: The rate controllers of each round can be configured in the benchmark configuration file. For the available rate controllers, see the Rate Controllers page.

  2. Once the rate controller enables the next TX, the worker process gives control to the workload module.

    The workload module assembles the parameters of the TX (specific to the SUT and smart contract API) and calls the simple API of the SUT connector that will, in turn, send the TX request to the SUT (probably using the SDK of the SUT).

    workload module

    1. assembles(收集) TX的引數(這些引數取決於相應的SUT和SUT的智慧合約的API),
    2. 呼叫SUT connector的簡單API,該API將依次向SUT傳送TX請求(probably using the SDK of the SUT)

Caliper Workers的機制解析:

  1. 等待rate controller允許下一個Tx的提交
  2. 當rate controller允許後 worker process 將會把控制權交給 workload module
    • workload module 收集產生Tx所需要的引數
    • 收集完成後呼叫SUT connector的簡單API從而將 TX request 傳送給 SUT

之前提到的round指的就是worker process的一次loop(迴圈)

每一個迴圈所使用的workload modules可以在benchmark configuration file裡進行設定

Note: The workload modules of each round can be configured in the benchmark configuration file. For the technical details of workload modules, see the Workload Modules page.

During the workload loop,the worker process向manager process傳送progress report。

注:Progress reporting在Manager Process端是可以設定的

Progress reporting on the manager side can be enabled and configured with the

  1. caliper-progress-reporting-enabled
  2. caliper-progress-reporting-interval

setting keys.

For details, see the Basic Runtime Settings.

2.0.5 Process distribution models

程序的分散式模型

The last part of the architecture discussion is demystifying the worker process management.

闡明如何對 worker process 進行管理

基於

  • worker processes的 產生 方式

  • manager process和worker processes之間使用的訊息傳遞方法(messaging method)

我們可以區分以下distribution/deployment 模型:

    • 自動產生 worker processes在同一臺主機上
    • worker processes和manager process使用程序間通訊(IPC)
    • 自動產生 worker processes在同一臺主機上
    • worker processes和manager process使用遠端訊息傳遞機制(remote messaging mechanism)
    • 手動啟動 worker processes在任意數量的主機上
    • worker processes和manager process使用遠端訊息傳遞機制(remote messaging mechanism)

儘管第三種方法適用於更復雜的情況,但前兩種方法可以幫助你熟悉Caliper,並逐漸幫助你過渡到第三種方法。

1. Modular message transport

模組間的資訊傳遞

The different deployment approaches are made possible by how Caliper handles messaging internally

Caliper處理 internal Moudles 之間的訊息傳遞的不同方式將導致不同的部署方式

如下圖所示:

Caliper中的internal modules只處理預定義的訊息,這個預定義的訊息的內容與訊息的傳送方式無關。

The internal Caliper modules only deal with predefined messages whose content is independent of how the messages are sent.

在程序之間通訊的模組是可替換的,因此支援不同的通訊方法。

部署模型可以通過以下兩個設定鍵進行配置:

  • caliper-worker-remote:

    如果設定為 false (the default)

    那麼 manager process 將會產生 the required number of worker processes locally, resulting in the models 1 or 2.

    也就是上面的方法1,2的情況

    總結一下:

    1. caliper-worker-remotefalse (the default),則自動產生 worker processes在同一臺主機上
    2. caliper-worker-remotetrue ,則手動啟動 worker processes在任意數量的主機上
  • caliper-worker-communication-method:

    can take the values process (the default) or mqtt and determines the message transport implementation to use.

    總結一下:

    1. caliper-worker-communication-methodprocess (the default),則worker processes和manager process使用程序間通訊(IPC)
    2. caliper-worker-communication-methodmqtt,則worker processes和manager process使用遠端訊息傳遞機制(remote messaging mechanism)

    The process communication corresponds to the first model, while mqtt denotes models 2 and 3.

下表總結了不同的模型以及如何選擇:

remote value method value Corresponding deployment model
false process 1.worker processes和manager process在同一臺主機上使用程序間通訊
false mqtt 2. Remote messaging-based communication with local workers
true mqtt 3. Remote messaging-based communication with remote workers
true process Invalid, since IPC does not apply to remote communication

Note: For the technical details on configuration the messaging transport, see the Messengers page.

2. 程序間通訊Interprocess communication

Install & Usage page 上的示例都使用IPC方法,因為 it is the default behavior。

該設定如下圖所示。

  1. The caliper launch manager命令啟動manager process
  2. manager process將自動生成configured number of worker processe (using the caliper launch worker CLI command).

caliper launch worker CLI command沒使用過

The communication between the processes is IPC, utilizing the built-in Node.JS method available for the parent-children process relationships.

這是Caliper最簡單的部署模型,不需要additional configuration和 third party messaging components

因此這是非常理想的:當您第一次開始使用Caliper時,或者當您仍然在為您的專案assembling the benchmark artifacts ,並且只是快速地想要測試它們時

Unfortunately, this model is constrained(受限於) to a single host, 由於在這個場景中存在 scalability issues只有vertical scalability of the host 是可行的

3. Local message broker communication

本地訊息代理通訊

作為實現完全分散式設定的跳板,第二個部署模型用third party messaging solution取代IPC,同時仍然向用戶隱藏worker process management。

該設定如下圖所示:

Like before, the caliper launch manager CLI command starts the manager process, which in turn will automatically spawn the configured number of worker processes (using the caliper launch worker CLI command).

However, the messaging(資訊傳遞) happens through a separate component(分開的元件), which could be deployed anywhere as long as its endpoint is reachable by the Caliper processes.

只要Caliper程序可以達到這個component,這個component可以部署到任何一個地方。

不幸的是,從Caliper程序的角度來看,這個模型也被限制在 a single host。

然而,一旦benchmark artifacts就緒,它是一個useful模型,taking your deployment to the next level 。

一旦您成功地集成了messaging component,您就可以準備轉移到完全分散式的Caliper設定了。

4. Distributed message broker communication

分散式訊息代理通訊

當你將worker processes的management掌握在自己手中時,Caliper的全部潛力就被釋放出來了

此時,您可以使用 caliper launch worker CLI 命令在儘可能多的host上啟動儘可能多的worker process

該設定如下圖所示:

完全分散式部署支援worker processes的水平擴充套件,極大地提高了可實現的workload rate

為了簡化對Caliper 中的 process的管理,您可能會使用一些自動 部署/管理(deployment/management) 解決方案,如Docker Swarm或Kubernetes。幸運的是Caliper已存在相關的Docker映象

Luckily, the flexibility of the Caliper Docker image makes such integration painless.

然而,有一些注意事項你必須記住:

  1. 將必要的benchmark artifacts分發給Caliper processes是您的責任。

    不同的infrastructure solutions(基礎設施解決方案:比如Fabric)對此提供了不同的方法,所以請檢視您喜歡的供應商的文件。

  2. 在分散式系統中建立適當的網路一直是一個挑戰。確保Caliper流程可以訪問configured messaging component和SUT元件。

  3. 單個主機可以執行多個Caliper worker processes。

    A single host may run multiple Caliper worker processes. When planning the worker distribution (or setting resource requirements for container management solutions) make sure that enough resources are allocated for workers to keep the configured TX scheduling precision.

2.1 建立Caliper工作區

2.1.1資料夾的建立

fabric-samples目錄的同一級別建立一個名為caliper-workspace的資料夾,然後在caliper-workspace資料夾中

分別建立三個名為networksbenchmarksworkload的資料夾

2.1.2 caliper CLI的安裝

Caliper的安裝和使用將基於當地的npm安裝

(也可以使用Docker進行安裝,推薦使用Docker,因為無需配置相關環境)

caliper-workspace目錄中,使用以下終端命令安裝caliper CLI:

npm install --only=prod @hyperledger/[email protected]

2.1.3 繫結相關網路的SDK

注:當前caliper支援的各平臺的SDK如下,caliper目前只支援四種區塊鏈的解決方案

The following SUT name and SDK version combinations are supported:

  • besu: 1.3.2, 1.3, 1.4, latest
  • ethereum: 1.2.1, latest
  • fabric: 1.1.0 [1.1], 1.4.11 [1.4, latest], 2.1.0 [2.1, latest-v2]
  • fisco-bcos: 2.0.0, latest

Caliper需要兩個配置檔案:

  • 網路配置檔案,它描述被測網路並提供要使用的測試標識。
  • 基準檔案,它定義了要通過一組有序的測試迴圈來完成的效能測試,每個測試輪都指定了一個工作負載模組和一系列選項,以在一個時間間隔內驅動工作負載。

現在我們將用Caliper所需的資源填充這些資料夾。

由最終命令格式易知

此例中:

網路配置檔案:networkConfig.json

基準檔案:myAssetBenchmark.yaml

npx caliper launch manager 
--caliper-workspace ./   # 工作目錄
--caliper-networkconfig networks/networkConfig.json   # 網路配置檔案位置
--caliper-benchconfig benchmarks/myAssetBenchmark.yaml   # 基準配置檔案位置
--caliper-flow-only-test # 智慧合約已經安裝和例項化,Caliper只需要執行測試階段
--caliper-fabric-gateway-enabled # 使用Hyperledger Fabric閘道器
--caliper-fabric-gateway-discovery # 使用Hyperledger Fabric閘道器

2.2 構建網路配置檔案(networks資料夾下)

網路配置檔案是Caliper工作人員建立到現有Fabric網路的連線所需的檔案,以便他們可以提交交易。

它類似於Fabric公共連線配置檔案,並添加了其他必需欄位。檔案可以是YAML或JSON格式,本教程顯示JSON格式。

2.2.1 建立模板網路配置檔案

在“networks”資料夾下建立一個名為networkConfig.json包括以下內容:

{
    "version" : "1.0",
    "name": "Caliper test",
    "caliper" : {
        "blockchain": "fabric"
    },
    "clients" : {
    },
    "channels" : {
    },
    "organizations" : {
    },
    "peers" : {
    }
}

1. 版本:正在使用的配置檔案的版本。只接受“1.0”。
2. 名稱:配置的名稱,在本例中為“Caliper測試”。
3. Caliper:指示對目標的SUT進行Caliper,可能包含本教程中不需要的其他開始/結束命令。在本教程中,我們以Fabric網路為目標。

SUT: 被測試系統specific system under test

4. 客戶端:列出要在效能測試中使用的標識

以下是Fabric的相關概念:

5. 通道channel:描述可用的Hyperledger Fabric通道、它們的狀態以及在這些通道上部署的智慧合約
6. 組織:要在基準測試中使用的超級賬本Fabric組織
7. peer節點:要在基準測試中使用的Hyperledger Fabric節點

2.2.2 對模板檔案networkConfig.json進行填充

在安裝fabric-samples網路的時候將生成一個公共連線配置檔案(CCP)

公共連線配置檔案(CCP):common connection profile

使用CCP對networkConfig.json進行填寫

在本例中我們使用的ccp的位置:

qwe@ubuntu:~/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com$ 

內容如下:

{
    "name": "test-network-org1",
    "version": "1.0.0",
    "client": {
        "organization": "Org1",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "300"
                }
            }
        }
    },
    "organizations": {
        "Org1": {
            "mspid": "Org1MSP",
            "peers": [
                "peer0.org1.example.com"
            ],
            "certificateAuthorities": [
                "ca.org1.example.com"
            ]
        }
    },
    "peers": {
        "peer0.org1.example.com": {
            "url": "grpcs://localhost:7051",
            "tlsCACerts": {
                "pem": "-----BEGIN CERTIFICATE-----\nMIICWTCCAf6gAwIBAgIRAPX6VzjvtPTMgsWXzlqKQ5gwCgYIKoZIzj0EAwIwdjEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHzAdBgNVBAMTFnRs\nc2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAxMjI3MTAyMzAwWhcNMzAxMjI1MTAy\nMzAwWjB2MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE\nBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0G\nA1UEAxMWdGxzY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABDFSvd28DmJAD2L8m6JAGcao3sMhFfjzKrbPehq2K/F0teSrRrhx2hjX\njXAJuZG9fqIu4KB0m839J9smFGLxoOajbTBrMA4GA1UdDwEB/wQEAwIBpjAdBgNV\nHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zApBgNV\nHQ4EIgQg2JBB5jaFMz0b0MIZLcsJcrOh8UjuwL3fo3cLtUoaE+QwCgYIKoZIzj0E\nAwIDSQAwRgIhANmb0iDSUr+he19S+prj6ZcqTcZTqqsjA+aKMCXv4vaAAiEAxPC+\nfGyCS6jGDEyQ/uugsS/laoYbkYs32FwRwcm+rwk=\n-----END CERTIFICATE-----\n"
            },
            "grpcOptions": {
                "ssl-target-name-override": "peer0.org1.example.com",
                "hostnameOverride": "peer0.org1.example.com"
            }
        }
    },
    "certificateAuthorities": {
        "ca.org1.example.com": {
            "url": "https://localhost:7054",
            "caName": "ca-org1",
            "tlsCACerts": {
                "pem": ["-----BEGIN CERTIFICATE-----\nMIICUTCCAfigAwIBAgIRAPUo4wcnf0pvyuWrhe/wyPQwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAxMjI3MTAyMzAwWhcNMzAxMjI1MTAyMzAw\nWjBzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UE\nAxMTY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBH/MCEqdRGllC8o2KCqumfjMROO6yRErGirWIiwEpB45xghpEcHLfM2KQqXLilET\ngQQRDdmHotGk5Fhg/IT8gPyjbTBrMA4GA1UdDwEB/wQEAwIBpjAdBgNVHSUEFjAU\nBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zApBgNVHQ4EIgQg\nsX/bzajXzmyXmKlqHGt77gfEMc1gkedXKsOKkSvulOgwCgYIKoZIzj0EAwIDRwAw\nRAIgXc/u9KP5brJ3w+p7pSCNwKRIbzQ1DOc4cxp+W8Cai6gCIFJdEvDhlo6WPB93\nGdQDQWpNTaPuGl3iVa59TJXlyVxQ\n-----END CERTIFICATE-----\n"]
            },
            "httpOptions": {
                "verify": false
            }
        }
    }
}
1. peers和Org部分填寫

使用CCP的內容進行填充:

將CCP的organizationspeers元素複製到Caliper網路配置檔案中。

organizations.Org1物件,刪除certificateAuthorities列表。這樣做有兩個原因:

i) 我們不會使用證書頒發機構註冊或註冊
ii)向CCP提交的變更與配置檔案中的驗證Caliper不相容。

填寫結果如下:

{
    "version" : "1.0",
    "name": "Caliper test",
    "caliper" : {
        "blockchain": "fabric"
    },
    "clients" : {
    },
    "channels" : {
    },
    "organizations": {
        "Org1": {
            "mspid": "Org1MSP",
            "peers": [
                "peer0.org1.example.com"
            ]
        }
    },
    "peers": {
        "peer0.org1.example.com": {
            "url": "grpcs://localhost:7051",
            "tlsCACerts": {
                "pem": "-----BEGIN CERTIFICATE-----<UNIQUE CONTENT>-----END CERTIFICATE-----\n"
            },
            "grpcOptions": {
                "ssl-target-name-override": "peer0.org1.example.com",
                "hostnameOverride": "peer0.org1.example.com"
            }
        }
    }
}

2.客戶端clients部分填寫

指定執行基準測試時Caliper要使用的標識。

身份必須有效,這意味著它們必須為Fabric網路所知,並且具有相應的加密材料以供使用。

標識在clients節中列出。這裡我們使用單一身份[email protected],我們在其中巢狀來自CCP的client物件,以指示標識所屬的組織,並提供基本的連線超時資訊。

"clients": {
    "[email protected]": {
        "client": {
            "organization": "Org1",
            "connection": {
                "timeout": {
                    "peer": {
                        "endorser": "300"
                    }
                }
            }
        }
    }
}

在client物件下,新增一個名為credentialStore的屬性,在該屬性下新增一個名為path的屬性,該屬性具有一個字串變數,該變數指向工作區中名為/tmp/org1的臨時檔案。另外,在credentialStore屬性下新增一個名為cryptoStore的屬性,並在該屬性下新增另一個指向上面相同臨時檔案/tmp/org1的路徑屬性。

以下是應該新增到client的內容:

"credentialStore": {
    "path": "/tmp/org1",
    "cryptoStore": {
        "path": "/tmp/org1"
    }
}

client物件下新增一個名為clientPrivateKey的屬性,在此屬性下新增一個名為path的屬性,該屬性具有一個字串變數,該變數指向標識的私鑰。請注意,提供的路徑是相對於工作區的。在本例中,私鑰位於fabric-samples -> test-network -> organizations -> peerOrganizations -> org1.example.com -> users -> [email protected] -> msp -> keystore -> priv_sk

client應新增到的物件是:

"clientPrivateKey": {
    "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/priv_sk"
}

另外,在client物件下新增另一個名為clientSignedCert的屬性,並在該屬性下新增一個名為path的屬性,該屬性具有一個字串變數,該變數指向標識的簽名證書。再次注意,提供的路徑是相對於工作區的。在本例中,它位於fabric-samples -> test-network -> organizations -> peerOrganizations -> org1.example.com -> users -> [email protected] -> msp -> signedcerts -> [email protected]

client應新增到的物件是:

"clientSignedCert": {
    "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]"
}

clients物件現在應該如下所示:

	"clients": {
	    "[email protected]": {
	        "client": {
	            "organization": "Org1",
	            "connection": {
	                "timeout": {
	                    "peer": {
	                        "endorser": "300"
	                    }
	                }
	            },
	            "credentialStore": {
	                "path": "tmp/hfc-kvs/org1",
	                "cryptoStore": {
	                    "path": "tmp/hfc-kvs/org1"
	                }
	            },
	            "clientPrivateKey": {
	                "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/priv_sk"
	            },
	            "clientSignedCert": {
	                "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]"
	            }
	        }
	    }
	}

3. channel部分填寫

在建立與Fabric網路的連線時,Caliper的fabric聯結器需要幫助。必須提供一個channels物件,該物件列出可能與之互動的智慧合約。

將由test-network建立的已知通道mychannel新增到Caliper網路配置檔案的channels部分,並賦予它一個布林值true建立的屬性。我們必須將此通道上可用的智慧合約列為名為contracts的陣列中的物件。每個智慧合約物件都有兩個屬性,idversionid指定合同ID;在本例中,它是basic。版本是特定的合同版本;在本例中是1.0.0。將其作為陣列中的一個物件新增,以使Caliper網路配置檔案中的結果通道物件變為:

    "channels": {
        "mychannel": {
            "created" : true,
            "contracts": [
                {
                    "id":"basic",
                    "version":"1.0.0"
                }
            ]
        }
    }

4. 完整的網路配置檔案

Caliper網路配置檔案現在應該完全填充。花點時間檢查並確保證書和金鑰的路徑是正確的,這是很有用的。

{
    "version" : "1.0",
    "name": "Caliper test",
    "caliper" : {
        "blockchain": "fabric"
    },
    "clients": {
        "[email protected]": {
            "client": {
                "credentialStore": {
                    "path": "/tmp/org1",
                    "cryptoStore": {
                        "path": "/tmp/org1"
                    }
                },
                "organization": "Org1",
                "clientPrivateKey": {
                    "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/priv_sk"
                },
                "clientSignedCert": {
                    "path": "../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]"
                },
                "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"
            }
        }
    }
}

2.3 構建工作負載檔案(workload資料夾下)

在基準測試期間,工作負載模組與部署的智慧合約進行互動。workload模組從Caliper-core擴充套件了Caliper類WorkloadModuleBase。工作負載模組提供三個覆蓋:

  • initializeWorkloadModule-用於初始化基準測試所需的任何項
  • submitTransaction-用於在基準的監視階段與智慧合約方法互動
  • cleanupWorkloadModule—用於在完成基準測試後進行清理

我們將推動的工作負載旨在對世界狀態資料庫中現有資產的查詢進行基準測試。因此,我們將使用workload模組中提供的所有三個階段:

  • initializeWorkloadModule-建立可在submitTransaction階段查詢的資產
  • submitTransaction-查詢在initializeWorkloadModule階段建立的資產
  • cleanuWorkloadModule-用於移除在initializeWorkloadModule階段建立的資產,以便可以重複基準測試

2.3.1 建立模板工作負載模組

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);
    }
    
    async submitTransaction() {
        // NOOP
    }
    
    async cleanupWorkloadModule() {
        // NOOP
    }
}

function createWorkloadModule() {
    return new MyWorkload();
}

module.exports.createWorkloadModule = createWorkloadModule;

2.3.2 對模板檔案readAsset.js進行填充

填充此檔案時,我們引用已部署智慧合約中的可用方法資產轉讓可在以下位置找到的檔案:fabric-samples -> asset-transfer-basic -> chaincode-javascript -> lib -> assetTransfer.js

/*
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

const { Contract } = require('fabric-contract-api');

class AssetTransfer extends Contract {

    async InitLedger(ctx) {
        const assets = [
            {
                ID: 'asset1',
                Color: 'blue',
                Size: 5,
                Owner: 'Tomoko',
                AppraisedValue: 300,
            },
            {
                ID: 'asset2',
                Color: 'red',
                Size: 5,
                Owner: 'Brad',
                AppraisedValue: 400,
            },
            {
                ID: 'asset3',
                Color: 'green',
                Size: 10,
                Owner: 'Jin Soo',
                AppraisedValue: 500,
            },
            {
                ID: 'asset4',
                Color: 'yellow',
                Size: 10,
                Owner: 'Max',
                AppraisedValue: 600,
            },
            {
                ID: 'asset5',
                Color: 'black',
                Size: 15,
                Owner: 'Adriana',
                AppraisedValue: 700,
            },
            {
                ID: 'asset6',
                Color: 'white',
                Size: 15,
                Owner: 'Michel',
                AppraisedValue: 800,
            },
        ];

        for (const asset of assets) {
            asset.docType = 'asset';
            await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
            console.info(`Asset ${asset.ID} initialized`);
        }
    }

    // CreateAsset issues a new asset to the world state with given details.
    async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
        const asset = {
            ID: id,
            Color: color,
            Size: size,
            Owner: owner,
            AppraisedValue: appraisedValue,
        };
        return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
    }

    // ReadAsset returns the asset stored in the world state with given id.
    async ReadAsset(ctx, id) {
        const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
        if (!assetJSON || assetJSON.length === 0) {
            throw new Error(`The asset ${id} does not exist`);
        }
        return assetJSON.toString();
    }

    // UpdateAsset updates an existing asset in the world state with provided parameters.
    async UpdateAsset(ctx, id, color, size, owner, appraisedValue) {
        const exists = await this.AssetExists(ctx, id);
        if (!exists) {
            throw new Error(`The asset ${id} does not exist`);
        }

        // overwriting original asset with new asset
        const updatedAsset = {
            ID: id,
            Color: color,
            Size: size,
            Owner: owner,
            AppraisedValue: appraisedValue,
        };
        return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
    }

    // DeleteAsset deletes an given asset from the world state.
    async DeleteAsset(ctx, id) {
        const exists = await this.AssetExists(ctx, id);
        if (!exists) {
            throw new Error(`The asset ${id} does not exist`);
        }
        return ctx.stub.deleteState(id);
    }

    // AssetExists returns true when asset with given ID exists in world state.
    async AssetExists(ctx, id) {
        const assetJSON = await ctx.stub.getState(id);
        return assetJSON && assetJSON.length > 0;
    }

    // TransferAsset updates the owner field of asset with given id in the world state.
    async TransferAsset(ctx, id, newOwner) {
        const assetString = await this.ReadAsset(ctx, id);
        const asset = JSON.parse(assetString);
        asset.Owner = newOwner;
        return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
    }

    // GetAllAssets returns all assets found in the world state.
    async GetAllAssets(ctx) {
        const allResults = [];
        // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
        const iterator = await ctx.stub.getStateByRange('', '');
        let result = await iterator.next();
        while (!result.done) {
            const strValue = Buffer.from(result.value.value.toString()).toString('utf8');
            let record;
            try {
                record = JSON.parse(strValue);
            } catch (err) {
                console.log(err);
                record = strValue;
            }
            allResults.push({ Key: result.value.key, Record: record });
            result = await iterator.next();
        }
        return JSON.stringify(allResults);
    }


}

module.exports = AssetTransfer;
1. 填充initializeWorkloadModule

此方法用於在基準完成時準備主submitTransaction方法所需的任何項。

要建立的資產數量將給出如下roundArguments.assets。我們通過填充arguments物件(定義交易體)和使用Caliper API sendRequests(需要了解以下知識)來建立資產:

  • contractId,要使用的智慧合約的名稱,它存在於Caliper網路配置檔案中
  • contractFunction,智慧合約中要呼叫的特定函式
  • contractArguments,傳遞給智慧合約函式的引數
  • invokerIdentity,Caliper網路配置檔案中存在的要使用的標識
  • readOnly,如果是否執行查詢操作

方法應該如下所示:

    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: '[email protected]',
                contractArguments: [assetID,'blue','20','penguin','500'],
                readOnly: false
            };

            await this.sutAdapter.sendRequests(request);
        }
    }

在上面的示例中,將建立具有相同引數的不同資產(blue,20,penguin,500)。將上述內容與智慧合約方法本身相比較,可以明顯看出,契約引數與方法引數之間存在1:1的對映關係。

2. 填充submitTransaction

此方法在基準測試階段重複執行。我們將通過查詢在initializeWorkloadModule方法中建立的資產來評估ReadAsset智慧合約方法。

首先,為要查詢的資產建立一個字串標識,該標識由worker索引和一個介於0和已建立資產數量之間的隨機整數串聯而成。

然後等待對sendRequests的呼叫,傳遞一個物件,該物件包含:從round引數傳入的contractId集;設定為ReadAssetcontractFunction;設定為invokerIdentity[email protected];和chaincodeArguments設定為一個數組,其中包含要在此執行中查詢的資產。

方法應該如下所示:

    async submitTransaction() {
        const randomId = Math.floor(Math.random()*this.roundArguments.assets);
        const myArgs = {
            contractId: this.roundArguments.contractId,
            contractFunction: 'ReadAsset',
            invokerIdentity: '[email protected]',
            contractArguments: [`${this.workerIndex}_${randomId}`],
            readOnly: true
        };

        await this.sutAdapter.sendRequests(myArgs);
    } 

3. 填充cleanupWorkloadModule

此函式用於在測試後進行清理,因為它通過使用智慧合約函式DeleteAsset刪除在initializeWorkloadModule函式中建立的資產。該實現類似於initializeWorkloadModule中的實現。注意可以重構initializeWorkloadModulecleanupWorkloadModule,以使用執行建立/刪除操作的通用方法,這將留給感興趣的讀者。

   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: '[email protected]',
                contractArguments: [assetID],
                readOnly: false
            };

            await this.sutAdapter.sendRequests(request);
        }
    }

4. 完整的工作負載模組
'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: '[email protected]',
                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: '[email protected]',
            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: '[email protected]',
                contractArguments: [assetID],
                readOnly: false
            };

            await this.sutAdapter.sendRequests(request);
        }
    }
}

function createWorkloadModule() {
    return new MyWorkload();
}

module.exports.createWorkloadModule = createWorkloadModule;

2.4 構建基準配置檔案(benchmarks資料夾下)

基準配置檔案定義基準輪次並引用定義的工作負載模組。

它將指定在生成負載時

  • 要使用的測試工作者的數量

    the number of test workers to use when generating the load

  • 測試輪的數量

    the number of test rounds

  • 每輪的持續時間

    the duration of each round,

  • 在每輪期間應用於交易負載的速率控制

    the rate control applied to the transaction load during each round

  • 與監視器相關的選項

    options relating to monitors

基準配置檔案可能以yaml或json格式提供:這裡我們將使用yaml格式。請注意,yaml檔案區分大小寫,所有標籤都是小寫。

基準配置檔案有一個必需的節:

test:

2.4.1 建立模板基準配置檔案

benchmarks資料夾下建立一個名為myAssetBenchmark.yaml包括以下內容:

test:
    name: basic-contract-benchmark
    description: A test benchmark
    workers:
    rounds:

test:包含基準測試資訊的根級塊。

The root level block that contains the benchmark test information

name:測試的名稱,在本例中為“基本合同基準”。

The name of the test, in this case “basic-contract-benchmark”.

description:對基準的描述,在本例中為“測試基準”。

A description for the benchmark, in this case “A test benchmark”.

workers:一組鍵,用於定義後續基準中使用的worker(獨立的worker客戶端例項)的數量。

A set of keys used to define the number of workers (separate worker client instances) used in the subsequent benchmark.

rounds:將按順序進行的不同測試回合的陣列。輪次可用於對不同的智慧合約方法進行基準測試,或以不同的方式對同一方法進行基準測試。

An array of distinct test rounds that will be progressed sequentially. Rounds may be used to benchmark different smart contract methods, or the same method in a different manner.

2.4.2 對模板檔案myAssetBenchmark.yaml進行填充

我們現在將填充模板檔案從而確定worker的數目和測試的輪數

測試輪數使用的是2.3結建立的workload module檔案

1. Populate Workers

填充workers部分

We will be using two separate workers, this is accomplished through the workers specification:

  type: local
  number: 2
2. Populate Rounds

填充round部分

每個round塊包含以下內容:

  • label - 用於回合的唯一標題標籤。

    the unique header label to use for the round

  • description - 正在執行的round的描述。

    a description of the round being run.

  • txDuration - 定義測試持續的時間,以秒為單位

    the specification of the test duration, in seconds

  • rateControl - 一種速率控制型別,帶有選項。

    a rate control type, with options.

  • workload - 要使用的工作負載模組(workload module),帶有要傳遞給模組的引數。

    傳遞的所有引數都可以作為roundArguments(工作負載workload的一個引數)在workload模組中使用。

    the workload module to use, with arguments to pass to the module. All arguments passed are available as roundArguments within the workload module.

    我們將指定一個被標記為readAsset的 benchmark round (測試輪)執行30s

    這個測試輪被描述為Query asset benchmark

    這個benchmark round使用一個fixed-load速率控制器來保持值為2的恆定交易壓力。

    此外,我們將提供一個workload通過明確我們的readAsset.js工作負載檔案的位置,我們將傳遞引數{assets:10,compactId:asset-transfer-basic}

    以上是通過對round的規範來實現的:

        - 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
    
    
3. The Complete Benchmark Configuration File

完整的基準測試檔案如下:

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

2.5 執行caliper進行基準測試

2.5.1 命令介紹

我們現在可以使用上面的配置檔案和測試模組來執行效能基準測試了。效能基準測試將使用Caliper CLI執行,需要提供一個指向工作區的路徑,以及指向網路配置檔案和基準配置檔案的工作區相對路徑。

這些資訊分別與標記

--caliper workspace 工作區的路徑

--caliper-networkconfig 向網路配置檔案的工作區相對路徑

--caliper benchconfig 基準配置檔案的工作區相對路徑

一起提供

  • 由於智慧合約已經安裝和例項化,Caliper只需要執行測試階段。這是通過使用--caliper-flow-only-test標誌來指定的。

  • 由於目標網路已啟用發現功能,我們可以通過使用標誌--capiler Fabric gateway enabled--capiler Fabric gateway discovery來使用Hyperledger Fabric閘道器。

2.5.2 命令的執行與結果的解釋

1. 執行

在terminal中執行以下命令:

npx caliper launch manager 
--caliper-workspace ./   # 工作目錄
--caliper-networkconfig networks/networkConfig.json   # 網路配置檔案位置
--caliper-benchconfig benchmarks/myAssetBenchmark.yaml   # 基準配置檔案位置
--caliper-flow-only-test # 智慧合約已經安裝和例項化,Caliper只需要執行測試階段
--caliper-fabric-gateway-enabled # 使用Hyperledger Fabric閘道器
--caliper-fabric-gateway-discovery # 使用Hyperledger Fabric閘道器
2. 結果的解釋

結果報告將詳細說明每輪基準測試的以下專案:

  • Name—基準配置檔案中的圓形名稱
  • Succ/Fail-成功/失敗的交易數
  • Send Rate-Caliper發出交易的速率
  • Latency(max/min/avg)- 與發出交易和接收響應之間的時間(以秒為單位)有關的統計資訊
  • Throughput—每秒處理的平均交易數

report.html

可以通過改變基準測試引數來重複測試,以及新增資源監視器。

有關全套選項,請參閱Caliper文件