本記事では、Hyperledger Fabricのトランザクション処理の特徴であるEndorsement-Ordering-Validation(EOV)モデルについて、良いところや課題について考察します。
良いところ
Endorsementの並列処理
Fabricのトランザクション処理は、他の記事等で詳しく解説されているのでここでは詳細は述べませんが、話の都合上、簡単に触れます。ざっくり言うとクライアント、Peer、Ordererという3人の登場人物が、Endorsement、Ordering、Validationという3つのフェーズで行います。
まず、クライアントが複数のPeerに対してトランザクション要求(例えば、AさんからBさんに100ドル送金してといった要求)を投げます。Peerは、その要求に従ってトランザクションを仮実行します。仮実行は、台帳の現在の状態に基づいて、このトランザクションがコミットされたらAさんとBさんの残高がどうなるかを計算するようなイメージです。Endorsementフェーズでは、いつの時点の状態を読んだか(Readセット)と、仮実行の結果(Writeセット)に署名を付与してクライアントに応答します。ReadセットとWriteセットは、以降、合わせてRWセットと呼びます。
クライアントは、複数のPeerから受領したRWセットが一致していれば、当該トランザクションをOrdererに送信します。Orderingフェーズでは、Ordererが、クライアントから受領した複数のRWセットを順番に並べ、1つのブロックにまとめた上で署名し、各Peerへばらまきます。
Validationフェーズでは、ブロックを受け取ったPeerが、各トランザクションのRWセットを検証した上で、コミット処理を行います。具体的には、Peerの署名の検証とともに、書き込み対象のデータが仮実行を行った時点から変更されていないかを確認します。変更されてしまっている場合には、当該トランザクションはアボートされます。
Fabric v1.0でEOVモデルが導入されたことにより、Endorsementフェーズで、投機的に複数のトランザクションを並列実行できるようになりました。v0.6までは全Peerで合意形成を行い、直列にトランザクションを実行しなければならなかったので、Peerをいくら増やしたところで性能をスケールさせることができなかったことを考えると、大きな変化だったと言えます。
Endorsementの柔軟性
もう1つ、EOVモデルの良いところは、どの取引に誰と誰の署名が必要かということを自由に定義できるところです。これは、Endorsement Policyという機能で、上記では、単に各PeerがRWセットに署名する(エンドースする)と書きましたが、どのPeerのエンドースが必要かを定義することができます。
例えば、3つの組織が参加するブロックチェーンネットワークで、各組織が2つずつPeerを運用している場合に、必ずしも全Peerから署名を得る必要はなく、全組織のいずれか1つのPeerの署名でOKといったポリシーや、いずれか2組織の署名でOKといったポリシーを書くことができます。これにより、結果の正しさと効率の良さを、アプリケーションの要件に合わせて自由に設計することができます。このような機能は、著者の知る限り、他のコンソーシアム型ブロックチェーンや分散台帳には見られない特徴的なものではないかと思います。
また、EOVモデルそのものからは外れてしまうのですが、Fabricが良くできているのは、このEndorsementの考え方がブロックチェーンネットワークの運用全体に行き届いているところです。例えば、ブロックチェーンネットワークでサービスを開始するにあたっては、(ある意味当然ではありますが)全組織の署名があってはじめて構成できるようになっていますし、ブロックチェーンネットワークに新しく組織を追加する際にも事前に定めたルール(e.g., 全員、過半数)にしたがって署名が求められるようになっています。このあたりの作り込みがしっかりしているのは大手ベンダ主導でしっかり開発されているが故かなと思います。
課題
Fabricのコンセンサスモデルの良いところについて述べてきましたが、色々と課題もあると思います。少々細かい話になってしまいますが、3つほど課題かなと思う点を挙げたいと思います。
Validationフェーズの並列化
EOVモデルの導入により、Endorsementフェーズにおける仮実行は並列処理が可能になったのですが、Validationフェーズは依然として直列実行になっています。署名の検証や、RWセットの検証を各トランザクションについて逐次やっていくのは非効率のように思います。
と思いながら、Fabricのコミュニティではどう考えているのか調べてみると、やはり課題意識はあるようで、署名の検証だけは並列でやろうとか、色々と議論されているようです。以下のJIRA、論文が参考になります。
https://jira.hyperledger.org/browse/FAB-12221
https://jira.hyperledger.org/browse/FAB-12280
https://arxiv.org/pdf/1808.08406.pdf
アボートの削減
EOVモデルの宿命のようにも思いますが、並列で仮実行している以上、同一のリソース(Key-Valueデータ)に更新が集中すると必然的にアボートが多くなります。特に、Fabricの場合、仮実行からコミットに至るまでに複数回のネットワーク通信を要するため、RDBMSの並行性制御よりも古い値を読みうる時間が長いのではないかと思います。例えば、送金アプリケーションにおいてあるユーザに送金が集中するといったことは容易に起こりうる状況なので、アプリケーション側のリトライに期待するだけでなく、何らかの工夫を期待したいところです。
ちなみに、これに関連しては、アカデミアの方では関連する取り組みがなされていました。下記の論文は、データベース関連の学会の最高峰の1つであるSIGMODで最近発表されたものですが、Orderingフェーズにおいて、各トランザクション間のRWセットの更新の依存関係を見た上で、なるべくアボートが少なくなるようトランザクションを並び替える手法が提案されています。
Sharma, A., Schuhknecht, F. M., Agrawal, D., & Dittrich, J., "Blurring the Lines between Blockchains and Database Systems: the Case of Hyperledger Fabric", SIGMOD 2019 (pp. 105–122)
https://dl.acm.org/citation.cfm?id=3319883
負荷分散
Endorsement Policyで誰の署名を得る必要があるか柔軟に定義できると延べましたが、裏を返すとクライアントがブロックチェーンネットワークに対してEndorsement Policyを踏まえつつ適切にトランザクション要求を投げる必要があります。ある組織に複数のPeerがあり、そのうち1つの署名を得れば良いケースでは、負荷がPeer間で均等になることも期待されます。これをクライアント(アプリケーション)が都度実装するのは負担が大きいので、Fabric v1.4ではSDKにConnection Profileという機能が導入されました。
Connection Profileにより、Endorsement Policyを考慮したトランザクション要求送信が容易にはなりましたが、負荷分散については単にラウンドロビンで投げるだけなようなので、これがもう少しインテリジェントになるとより実用的になるのではと思っています。