2019.04.10

parity-ethereumのベンチマーク

Pocket

こんにちは、次世代システム研究室のN.O.です。

Z.com Cloud ブロックチェーンではブロックチェーン技術にEthereumを利用しています。Ethereumではgeth(Go Ethereum)parity-ethereum(Parity Ethereum)、以前の記事でご紹介したEthereum Harmonyなど、様々なクライアントがあります。クライアントを選択するにあたり、ベンチマークを比較することがあると思います。
今回は、手軽に複数のクライアントのベンチマークが実施できるツール、Chainhammerを使ってgethとparity-ethereumを比較し、結論としては同様のベンチマーク結果が得られたのですが、その過程でparity-ethereumのチューニングについて詳しく知ることができたので、共有したいと思います。

Chainhammerを使ってみる

まずはChainhammerを使ってみたいと思います。
環境は以下を使用します。
  • ConoHa
  • プラン 4GB
  • イメージタイプ Debian 9.7(64bit)

インストール

アップデートおよびgit、curlをインストールし、一度リブートを行います。
    sudo apt-get update
    sudo apt-get -y upgrade
    sudo apt-get -y install git curl
    sudo reboot
clone後、インストールスクリプトを実行します。
    git clone https://github.com/drandreaskrueger/chainhammer.git
    cd chainhammer
    ./scripts/install.sh
正しくインストールされているか確認したい場合は、テストスクリプトを実行します。
    ./pytest.sh
1件eth_utilsでDeprecationWarningが出ましたが、ベンチマークの測定に支障はありませんでした。
    eth_utils/applicators.py:32: DeprecationWarning

ベンチマーク

Chainhammerでは以下のクライアント、およびエンジンをサポートしています。
ここでは試しにgeth cliqueとparity-ethereum Auraのベンチマークを測定することにします。

geth clique
    CH_TXS=10000 CH_THREADING="threaded2 20" \
      ./run.sh ConoHa4GB-Geth geth-clique
parity-ethereum Aura
    networks/parity-configure-aura.sh v1.11.11
    CH_TXS=10000 CH_THREADING="threaded2 20" \
      ./run.sh ConoHa4GB-ParityAura parity
結果はresults/runs以下にhtml, markdownの形で出力されます。markdownの1行目にTPSが出ています。geth cliqueとparity-ethereum Auraでは以下の通りとなりました。
環境クライアントエンジンTx数TPS (Tx Per Seccond)
ConoHa4GBGeth v1.8.14clique10000374.1
ConoHa4GBParity v1.11.11Aura1000041.2


結果にだいぶ差がついてしまいました。この原因についてissueが上がっていますので、詳しく説明します。

Parityのチューニング

parity-ethereum AuraでTPSが出ない件については、Chainhammerの作者drandreaskruegerさんがissueを投稿し議論が続きました。最終的にparityの開発者tomusdrwさんのコメントによってparityでもgeth同様の結果が得られ、その再現手順が示されました。
そのコメントによりますと、一番影響するのが--fast-unlockというフラグです。parityではセキュリティ上の理由から、Accountをunlockする際もパスワードのみメモリに保持し、生の秘密鍵は署名が終わったらすぐにメモリから消去します。このように署名のたびにAccountのkeyfileから秘密鍵をメモリにロードする方式のため、メモリの脆弱性をついた攻撃には耐性がありますが、その分ファイル読み込みが発生するため、パフォーマンス的に不利になります。--fast-unlockではunlockが無期限の場合に限りこの振る舞いを無効にし、秘密鍵をメモリに保持します。今回はベンチマークが目的なので、--fast-unlockを有効にします。

他にもいくつかチューニングの参考になるパラメータの説明がありました。
--gas-floor-target=40M
gas floor targetは、blockのgasLimitの下限です。blockのgasLimitは前のブロックのTx量によって決まります。前のブロックのTxが少なければgasLimitも減少していき、逆に前のブロックのTxが多ければ上昇します。普段Txが少ないネットワークでは下限になりがちなので、下限を適切な値にする必要があります。なおdefaultは8Mです。

--jsonrpc-server-threads 8
ベンチマークではマルチスレッド、非同期でTxを投げるので、受け側も適切なスレッド数にする必要があります。コメントでは2*coreで算出した、とありました。ConoHa 4GBのVCPUは4なので、こちらも8を選択しました。defaultは4です。

--jsonrpc-threads=0
上記のRPC serverに追加するthreadの数です。コメントには「最近のバージョンでは何もしない」とありました。threadを追加すると、thread間でdataのやり取りが発生し時間を消費します。このベンチマークではRPCのスループットはそこまで必要としないので、0にします。defaultは4です。

--tx-queue-per-sender 8192
送信者ごとのTx queueのサイズを指定します。ベンチマークでは単一の送信者がTxを送信するため、すべてのTx queueを割り当てます。(ちなみに、実社会のシナリオでは単一の送信者に多くのキューを割り当てる必要はありません。)defaultは--tx-queue-size(すべてのTx queue)の1%です。なお--tx-queue-sizeのdefaultは8192です。

--no-discovery
ノードが決まっている場合、ピアの探索は不要なので無効にします。

再びベンチマーク

以上を踏まえ、parityのオプションとunlockの期限を修正します。
差分はこちらです

再度計測すると多少改善しましたが、それでもgethには及びません
環境クライアントエンジンTx数TPS (Tx Per Seccond)
ConoHa4GBParity v1.11.11Aura10000141.8


ログを眺めていると、トランザクション数が同じ数で頭打ちになっていました。
    block 15 | new #TX 1492 / 10000 ms = 149.2 TPS_current | total: #TX 1493 / 10.8 s = 137.7 TPS_average (peak  is 137.7 TPS_average)
    block 16 | new #TX 1492 / 10000 ms = 149.2 TPS_current | total: #TX 2985 / 21.3 s = 140.0 TPS_average (peak  is 140.0 TPS_average)
    block 17 | new #TX 1492 / 10000 ms = 149.2 TPS_current | total: #TX 4477 / 31.5 s = 142.2 TPS_average (peak  is 142.2 TPS_average)
    block 18 | new #TX 1492 / 10000 ms = 149.2 TPS_current | total: #TX 5969 / 40.8 s = 146.2 TPS_average (peak  is 146.2 TPS_average)
このときblockのヘッダを確認すると、gasUsedがgasLimitにひっ迫していることがわかりました。
    curl -s --data '{"method":"eth_getBlockByNumber","params":["latest",true],"id":1,"jsonrpc":"2.0"}' \
      -H "Content-Type: application/json" \
      -X POST localhost:8545 | jq .result.gasLimit,.result.gasUsed
    "0x2625a00"
    "0x26119fc"
gasはblockのgasLimitで制限されるので、これ以上Txが入らなかったのです。
この問題を解決するには、blockのgasLimitを増やすか、blockの間隔を短くすることです。今回はblockの間隔を5秒から3秒に変更しました。以下がその結果です。
環境クライアントエンジンTx数TPS (Tx Per Seccond)
ConoHa4GBParity v1.11.11Aura10000405.1

まとめ

今回はgethには手を入れていませんので、ベンチマークとしては不十分かと思います。(おそらくChainhammerである程度チューニングされていると思いますが、、、)またベンチマークでは簡単なケースしか試していないため、プロジェクトで採用する際はユースケースに合わせてシナリオを作成し、性能検証すべきです。
ただ、今回の調査を通してparity-ethereumのパラメータについて深く知ることができたので、今後のチューニングに活かしたいと思います。
なお、今回パフォーマンス寄りにセッティングしましたが、--fast-unlockはセキュリティを考慮すると安易に有効にするべきではありません。バッチ処理等で大量にTxを送信する場合に、一時的に有効にする、ノードは使い捨てにする、といった使い方ならよいのではないかと考えます。

最後に

次世代システム研究室では、アプリケーション開発や設計を行うアーキテクト、またはブロックチェーンのエンジニアを募集しています。弊社にはGMOすごいエンジニア支援制度 – サバろうぜという制度があり、今回使用したConoHaも利用することができます。業務に直接関連が無くても「グループのサービスを個人的に使ってみたい」、「実際に個人的に使って、その声をフィードバックしたい」といったことが可能です。次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。