R3 Cordaノードの高可用性(HA)とその構成方法

TIS Blockchain Promotion Office
15 min readJun 7, 2019

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として使用されます。

図1 本記事のHA設定の全体像

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インスタンスを作成します。(設定手順は省略)いくつか注意点を記載します。

  1. 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への接続したことが記録されています:

Logs in PartyA (txn-a)

また、PartyBのアクティブなノードがPartyAとの上記のtxn-aを処理していることがわかります。

logs in PartyB cold (txn-a)
logs in PartyB hot (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.

--

--