R3 Cordaノードの高可用性(HA)とその構成方法
Corda Enterpriseは、バージョン3.2のリリース以降、Cordaノード用の「Hot-cold high availability deployment」を正式にサポートしています。この「Hot-cold high availability deployment」についてどのような設定をするのか、どういった挙動をするのか、高可用性が担保できるのか?について確認しましたので、紹介します。
A. はじめに
この記事ではAWS環境を使用してCordaノードのHA設定を構成します。また、すべてのAWSインスタンスは同じVPC内に設定されています。
・HA設定のCordaノードのDBはPostgreSQLを使用しています。その他のCordaノードはデフォルトのH2 DBを使用しています。
・各ノードはEC2インスタンスを利用して構築します。OSはUbuntu、18.04 LTです。
・CorDapp開発環境を設定するには、Cordaの公式文書に従ってください。
- https://docs.corda.r3.com/getting-set-up.html
・参考にしたCorda公式サイト
- https://docs.corda.r3.com/releases/3.3/hot-cold-deployment.html
B. 本記事のHA設定の全体的なイメージ
・Cordaノードは4つのEC2インスタンスで構成。
・HAノード(以降PartyBとします)のDBはAWSのRDSサービスを使用
・PartyBのArtemisサービスはAWSのEFSサービス(共有ネットワークドライブとして)を使用。
・PartyBに必要なロードバランサはAWSのELB(Classic Load Balancer)を使用。
Cordaの「Hot-cold high availability deployment」は基本的に「HAクラスタリング」の考え方です。R3のWebサイトでは「共有ディスク構成」で紹介されています。今回の検証で使用したロードバランサ、EFS、およびAWSのRDSの役目について説明します。
1. ロードバランサは、PartyBインスタンスの状態を監視し、他のParty ノードからアクティブなPartyBノードへトラフィックを自動的にルーティングします。なお、Cordaの機能によりHAクラスタ内のノードは1つしか起動しないようになっており、2台目を起動しようとしても待ち状態となります。この待ち状態の際、1台目がインアクティブになると自動的に起動されます。ロードバランサのIPアドレス(代表アドレス)は、PartyBのP2Pアドレスとして他のCordaネットワークにアドバタイズされます。これは、ロードバランサのIPを設定ファイル(build.gradle)内のノードのP2Pアドレスとして設定することによって行われます。これについては、セクションFで説明します。
2. EFSは、P2Pメッセージブローカーファイル用の共有ネットワークドライブとして使用されます。 したがって、P2Pメッセージはアクティブ/インアクティブ関わらずアクセス可能となります。また、このネットワークドライブを利用してどちらのノードがアクティブかを確認しています。つまり、HAクラスタ内のノードが1つしか起動しないという仕組みはネットワークドライブを利用して実現されています。
3.アクティブ/インアクティブ関わらず同一DBを参照する必要があるため、RDSはHAノード用の共有DBとして使用されます。
C. ロードバランサの設定
ロードバランサは、着信トラフィック(P2P、RPC、およびHTTP)をアクティブなCorda ノード、たとえば図1のHot Party Bノードにリダイレクトするために使用されます。以下に、ロードバランサを構築する手順を示します。
1.AWS上のLoad Balancerコンソール・ページにアクセスする
「ロードバランサーの作成」ボタンをクリックしてロードバランサーの作成を開始します。
2.「Classic Load Balancer」を選択して構成を完了してください。
3.本記事のテスト環境では、すべてのCordaノードが同じVPC内にあるため、本環境のロードバランサタイプでは、公式サイトに記載されている「外部向け」のロードバランサではなく、「内部向けロードバランサーの作成」をチェックする必要があります。
4.ロードバランサポートとインスタンスポートの値は、PartyBのnode.confファイルで設定されている「p2pAddress」と「rpcSettings」の値と同じである必要があります。
5.公式サイト(https://docs.corda.r3.com/hot-cold-deployment.html)に従って[セキュリティグループ]、[ヘルスチェック]を完了してください。
6. PartyBの2つのEC2インスタンス(Hot / Cold)をロードバランサーに追加します。 例:
7.プロセス全体を完了すると、新しいロードバランサーが作成されます。
新しく作成したロードバランサのDNS名をメモしてください。これは後の設定に使用します(セクションF)。
D. EFS(P2Pメッセージブローカーファイル用の共有ネットワークドライブ)を作成する。
公式サイトとAWS(https://docs.aws.amazon.com/ja_jp/efs/latest/ug/getting-started.html)に手順が公開されている為、詳細な手順は省略しますが、下記の注意点について説明します。
1. EFSは、PartyBノードと同じサブネットおよびセキュリティグループを使用する必要があります。
2. EFSが作成されたら、「Amazon EC2のマウント手順(ローカルVPCから)」をメモしてください。後程このEFSを二つのHAノード(PartyB Hot/Cold)にマウントする時、これらの手順を使用します。
E. RDS (PostgreSQL on AWS)の作成及びテンプレートの設定
PostgreSQLインスタンスの作成について
AWS上でPostgreSQLインスタンスを作成します。(設定手順は省略)いくつか注意点を記載します。
- Cordaの公式サイトによると、PostgreSQL 9.6 with JDBC Driver 42.1.4がテスト済みです。 本検証では、同じドライバを使ったPostgreSQL 10を利用しましたが、問題なく正常に動作しました。https://docs.corda.r3.com/releases/3.3/node-database.html?highlight=node%20database%20developer#postgresql
2. DBインスタンスのサブネットおよびセキュリティグループの設定は、LBとPartyBノードの設定と同じにします。
3. 新しく作成したDBインスタンスのエンドポイント名をメモしてください。 これは後の設定に使用されます(セクションF)。
PostgreSQLインスタンスの設定について
4. pgAdmin4などの他社製DB接続クライアントツールを使用して、上記で作成したDBインスタンスに接続します。管理者としてDBインスタンスに接続し、データベースを作成します。
5. 公式スクリプトを使用してノードユーザーとスキーマを作成します。
(https://docs.corda.r3.com/releases/3.3/node-database.html#postgresql)
上記のスクリプトを実行した後、作成したDBにスキーマが作成されます。
F. ノードの設定
今回検証用で設定した設定内容を記載します。
<build.gradle>ファイルへHA設定に関する情報を追記します。
ノード(例えば、PartyB)をHA設定に構成するためには、そのノードの関連設定情報のみを修正する必要があります。以下、注意点も含めて記載します。
……. <build.gradle>…….
G. CorDappsのビルドおよびデプロイをする
上記の変更した<build.gradle>ファイルを保存して、CorDappsのディレクトリで「./gradlew deployNodes」を実行してCorDappsのコンパイルを開始します。
CorDappsのコンパイルが正常に完了した場合、以下と同様のメッセージが表示されます。
これで、PartyBを含むすべてのcordaノードのディレクトリが“ build / nodes”の下に作成されました。 PartyBのnode.confファイルは次のようになります。
さらに、データベースには、Cordaに必要なすべてのテーブルが作成されています。
CorDappsが必要とする上記以外のテーブルはまだ作成されていないことに注意してください。 これについては後のセクションIで説明します。
次に各cordaノードのディレクトリを対応するサーバにコピーします。。本記事では、各cordaノードのEC2インスタンスにコピーします。HAノード(PartyB)のディレクトリについてはセクションCのステップ4でロードバランサに追加した2つのEC2インスタンス(HA-Hot(AZ1)とHA-Cold(AZ1))にコピーします。
H. HAノード用の共有ドライブを設定する.
上記の2つPartyB用のEC2インスタンスにログインします。 2つのインスタンス共、以下の設定を完了してください。
1. PartyBディレクトリの下に「artemis」という名前のディレクトリが存在しない場合は作成します。
> mkdir artemis
2. 「artemis」ディレクトリにEFSドライブをマウントします
> sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport fs-*******.efs.ap-northeast-1.amazonaws.com:/ artemis
//セッションDのメモを参照して、上記を確認してください。.
3. 「artemis」ディレクトリの所有者がこのcordaノードの所有者と同じであることを設定してください。
> e.g. chown ubuntu:ubuntu artemis
同じでない場合、PartyBノードを起動するときに以下のようなエラーが表示されます。
4. EC2インスタンスでのJDBCドライバは異なるディレクトリにある可能性があるため、PartyBのnode.confの「jarDirs」の値が正しいことを再確認してください。必要に応じて、修正してください。
I. すべてのcordaノードを起動します
すべてのEC2インスタンスにログインし、そこにコピーしたcordaノードディレクトリにアクセスします。
そのディレクトリで「java -jar corda.jar」を実行してcordaノードを起動します
ただし、HAノード(PartyB)を起動すると、次のようなエラーメッセージが表示されることがあります:
これは、セクションGで説明したように、CorDappsに必要なスキーマ/テーブルがPostgreSQL DBに作成されていないためです。
必要な「移行スクリプト」を作成するには、セクションG(CorDappをビルドする環境)の作業ディレクトリで、以下のコマンドを実行してください。
Cordaの公式サイトには、これらのコマンドについての説明があります。 https://docs.corda.r3.com/database-management.html?highlight=node%20migration#adding-database-migration-scripts-retrospectively-to-an-existing-cordapp
移行スクリプトは、PartyBのCorDappsディレクトリにある.jarファイルとして作成されます。
これで、CorDappsに必要なスキーマがPostgreSQL DBに作成されました。たとえば、本記事で利用しているCorDappで必要とされるテーブル“ qd_states”が、新しく作成されました。
これで、EC2インスタンスHA-Hot(AZ1)で、PartyBノードが、次のようなコンソールメッセージで正常に起動されます。HA-Cold(AZ1)については起動待ち状態となります。
J. HA機能をテストする
これで、図1のように、すべてのコーダノードがEC2インスタンスで正常に起動されました。
たとえば、PartyAとPartyBの間でトランザクション(txn-a)を発行すると、txn-aは正常に完了します。、PartyAノードのログファイルを確認するとPartyAが実際にロードバランサーに接続してPartyBへの接続したことが記録されています:
また、PartyBのアクティブなノードがPartyAとの上記のtxn-aを処理していることがわかります。
その後、PartyBのHot Nodeを停止し、二個目のトランザクションを発行します(txn-b)。
TXN-Bも正常に完了できることを確認できます。
因みに、PartyAのログを確認すると、PartyBのアクティブなノードを停止した直後、PartyAはPartyBが切断されたことを検出し、PartyBのロードバランサーに再接続する動作が確認できます。
以下はPartyAのTxn-bのログです。これは、PartyAが正常にPartyB(Cold)署名を受信したことを示しています。
以下はPartyB Cold NodeのTxn-bのログです。これは、PartyB(Cold)はPartyAからtxn-bを受け取り、正常に処理したことを示しています。
停止したPartyB(hot)を再起動した場合、PartyB(cold)がアクティブ状態であれば、Cordaのプロセスは起動せず、待ち状態となります。よって3番目のトランザクション(txn-c)を発行した場合、txn-cがPartyB(cold)で正常に処理されます。
総評
アクティブなノードで障害が発生した場合でも、インアクティブなノードが自動で起動し、起動する間、若干待ち状態となりますが、トランザクションも切れることなく処理できるので、高可用性は担保できると考えます。ただし、これはノードのみの高可用性となります。システム全体で考えた場合、ノード、ロードバランサ、ネットワーク共有ドライブ、データベース、すべてがCordaノードにおいて必要なリソースとなり、その中の1つでも障害を起こすとCordaノードとしては機能しません。必要なリソースすべてにHAクラスタ構成を構築しなければ、システム全体の高可用性は担保できません。
まとめ
本記事は、AWS環境でHA Cordaノードを構築する際に必要な手順と注意点について説明しました。
最新のCorda Enterpriseバージョン(CE4.0)では、ロードバランサなしでHAノードを設定する代替アプローチを提供しています。 次の記事で、その機能の設定方法を公開する予定です。
記:TIS Blockchain Promotion Office (羅)
Thanks to Kiyotaka Yamasaki.