Edited at

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

本記事はTIS株式会社様のMedium記事の転載となっております(了承済み)。

本文URL:https://medium.com/@TIS_BC_Prom/r3-corda%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7-ha-%E3%81%A8%E3%81%9D%E3%81%AE%E6%A7%8B%E6%88%90%E6%96%B9%E6%B3%95-34cb5dd409d1


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の公式文書に従ってください。

・参考にしたCorda公式サイト


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_Ru1l1qoLW-D9dOLbHMVq7w.jpg

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


C. ロードバランサの設定

ロードバランサは、着信トラフィック(P2P、RPC、およびHTTP)をアクティブなCorda ノード、たとえば図1のHot Party Bノードにリダイレクトするために使用されます。以下に、ロードバランサを構築する手順を示します。

1.AWS上のLoad Balancerコンソール・ページにアクセスする

2.jpg

「ロードバランサーの作成」ボタンをクリックしてロードバランサーの作成を開始します。

2.「Classic Load Balancer」を選択して構成を完了してください。

3.jpg

3.本記事のテスト環境では、すべてのCordaノードが同じVPC内にあるため、本環境のロードバランサタイプでは、公式サイトに記載されている「外部向け」のロードバランサではなく、「内部向けロードバランサーの作成」をチェックする必要があります。

4.ロードバランサポートとインスタンスポートの値は、PartyBのnode.confファイルで設定されている「p2pAddress」と「rpcSettings」の値と同じである必要があります。

4.jpg

5.公式サイト(https://docs.corda.r3.com/hot-cold-deployment.html) に従って[セキュリティグループ]、[ヘルスチェック]を完了してください。

6. PartyBの2つのEC2インスタンス(Hot / Cold)をロードバランサーに追加します。 例:

6.jpg

7.プロセス全体を完了すると、新しいロードバランサーが作成されます。

5.jpg

新しく作成したロードバランサの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)にマウントする時、これらの手順を使用します。


1_9DdinUTL4ugbwN72gh8OaQ.jpeg


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


  1. DBインスタンスのサブネットおよびセキュリティグループの設定は、LBとPartyBノードの設定と同じにします。


  2. 新しく作成したDBインスタンスのエンドポイント名をメモしてください。 これは後の設定に使用されます(セクションF)。

    7.jpg


PostgreSQLインスタンスの設定について


  1. pgAdmin4などの他社製DB接続クライアントツールを使用して、上記で作成したDBインスタンスに接続します。管理者としてDBインスタンスに接続し、データベースを作成します。


  2. 公式スクリプトを使用してノードユーザーとスキーマを作成します。


(https://docs.corda.r3.com/releases/3.3/node-database.html#postgresql)

8.jpg

CREATE USER "my_user" WITH LOGIN PASSWORD 'my_password';

CREATE SCHEMA "my_schema";
GRANT USAGE, CREATE ON SCHEMA "my_schema" TO "my_user";
GRANT SELECT, INSERT, UPDATE, DELETE, REFERENCES ON ALL tables IN SCHEMA "my_schema" TO "my_user";
ALTER DEFAULT privileges IN SCHEMA "my_schema" GRANT SELECT, INSERT, UPDATE, DELETE, REFERENCES ON tables TO "my_user";
GRANT USAGE, SELECT ON ALL sequences IN SCHEMA "my_schema" TO "my_user";
ALTER DEFAULT privileges IN SCHEMA "my_schema" GRANT USAGE, SELECT ON sequences TO "my_user";
ALTER ROLE "my_user" SET search_path = "my_schema";

8.jpg

上記のスクリプトを実行した後、作成したDBにスキーマが作成されます。

9.jpg


F. ノードの設定

今回検証用で設定した設定内容を記載します。

build.gradleファイルへHA設定に関する情報を追記します。

ノード(例えば、PartyB)をHA設定に構成するためには、そのノードの関連設定情報のみを修正する必要があります。以下、注意点も含めて記載します。

build.gradle

…<略>…

node {
name "O=PartyB,L=Tokyo,C=JP"
p2pAddress "internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008"
//上記のアドレスは、セクションCで作成したロードバランサーのDNS名です.
//他のCordaノードは、上記のロードバランサを介してPartyB(Hot/Cold)ノードに接続します。
rpcSettings {
address("0.0.0.0:10009")
adminAddress("0.0.0.0:10049")
}
// rpcアドレスを0.0.0.0に割り当てます。これらのアドレスは起動時にノード自体によって使用されるため、他のノードからアクセスされる必要がないためです。
//また、公式サイトに記載されているように、手前のマシンのIPアドレスに設定すると、「Cannot assign requested address」というエラーが表示されるかもしれません。
extraConfig = [
jarDirs : ["/***/***/"],
//ドライバ“ postgresql-42.1.4.jar”があるディレクトリへ設定してください。
"dataSourceProperties.dataSource.url": "jdbc:postgresql://ce4-pgsql.************.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2",
//上記のdataSource.urlはDBのエンドポイント(セクションEで作成)/PGSQL Serverのポート番号(デフォルトは5432)/データベース名(セクションEで作成)です。
"dataSourceProperties.dataSourceClassName": "org.postgresql.ds.PGSimpleDataSource",
"dataSourceProperties.dataSource.user": "*****",
"dataSourceProperties.dataSource.password": "*****",
"database.transactionIsolationLevel": "READ_COMMITTED",
"database.schema": "my_schema",
"database.runMigration": "true"
//ノードの起動時に必要なテーブルを作成できるようにするには、database.runMigration「true」に設定します。
]
cordapps = [
"$project.group:cordapp-contracts-states:$project.version",
"$project.group:cordapp:$project.version"
]
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}
…<略>…


G. CorDappsのビルドおよびデプロイをする

上記の変更したファイルを保存して、CorDappsのディレクトリで「./gradlew deployNodes」を実行してCorDappsのコンパイルを開始します。

CorDappsのコンパイルが正常に完了した場合、以下と同様のメッセージが表示されます。

…<略>…

node {
name "O=PartyB,L=Tokyo,C=JP"
p2pAddress "internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008"
//上記のアドレスは、セクションCで作成したロードバランサーのDNS名です.
//他のCordaノードは、上記のロードバランサを介してPartyB(Hot/Cold)ノードに接続します。
rpcSettings {
address("0.0.0.0:10009")
adminAddress("0.0.0.0:10049")
}
// rpcアドレスを0.0.0.0に割り当てます。これらのアドレスは起動時にノード自体によって使用されるため、他のノードからアクセスされる必要がないためです。
//また、公式サイトに記載されているように、手前のマシンのIPアドレスに設定すると、「Cannot assign requested address」というエラーが表示されるかもしれません。
extraConfig = [
jarDirs : ["/***/***/"],
//ドライバ“ postgresql-42.1.4.jar”があるディレクトリへ設定してください。
"dataSourceProperties.dataSource.url": "jdbc:postgresql://ce4-pgsql.************.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2",
//上記のdataSource.urlはDBのエンドポイント(セクションEで作成)/PGSQL Serverのポート番号(デフォルトは5432)/データベース名(セクションEで作成)です。
"dataSourceProperties.dataSourceClassName": "org.postgresql.ds.PGSimpleDataSource",
"dataSourceProperties.dataSource.user": "*****",
"dataSourceProperties.dataSource.password": "*****",
"database.transactionIsolationLevel": "READ_COMMITTED",
"database.schema": "my_schema",
"database.runMigration": "true"
//ノードの起動時に必要なテーブルを作成できるようにするには、database.runMigration「true」に設定します。
]
cordapps = [
"$project.group:cordapp-contracts-states:$project.version",
"$project.group:cordapp:$project.version"
]
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}
…<略>…

これで、PartyBを含むすべてのcordaノードのディレクトリが“ build / nodes”の下に作成されました。 PartyBのnode.confファイルは次のようになります。

ataSourceProperties {

dataSource {
password=*****
url="jdbc:postgresql://ce4-pgsql.************.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2"
user=*****
}
dataSourceClassName="org.postgresql.ds.PGSimpleDataSource"
}
database {
runMigration="true"
schema="my_schema"
transactionIsolationLevel="READ_COMMITTED"
}
devMode=true
jarDirs=[
"/***/***/"
]
myLegalName="O=PartyB,L=Osaka,C=JP"
p2pAddress="internal- PartyB-HA-LB -*********.ap-northeast-1.elb.amazonaws.com:10008"
rpcSettings {
address="0.0.0.0:10009"
adminAddress="0.0.0.0:10049"
}security {
authService {
dataSource {
type=INMEMORY
users=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
}
}
}

さらに、データベースには、Cordaに必要なすべてのテーブルが作成されています。

10.jpg

CorDappsが必要とする上記以外のテーブルはまだ作成されていないことに注意してください。 これについては後のセクションIで説明します。

次に各cordaノードのディレクトリを対応するサーバにコピーします。。本記事では、各cordaノードのEC2インスタンスにコピーします。HAノード(PartyB)のディレクトリについてはセクションCのステップ4でロードバランサに追加した2つのEC2インスタンス(HA-Hot(AZ1)とHA-Cold(AZ1))にコピーします。

https://gist.github.com/luomin/263460bc930bc30ab719dd390394016c#file-logs-in-partyb-cold-node-txn-b

11.jpg


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ノードを起動するときに以下のようなエラーが表示されます。

---------- Corda Enterprise Edition 4.0 (8dcaeef) -------------------

Tip: If you don't wish to use the shell it can be disabled with the --no-local-shell flag
Logs can be found in : /path to your cordapp directory/build/nodes/PartyB/logs
! ATTENTION: This node is running in development mode! This is not safe for production deployment.
Database connection url is : jdbc:postgresql://ce4-pgsql.************.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2
Advertised P2P messaging addresses : internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008
RPC connection address : 0.0.0.0:10009
RPC admin connection address : 0.0.0.0:10049
[ERROR] 03:25:07+0000 [main] internal.Node.start - Messaging service could not be started.
Shutting down ...
[ERROR] 03:25:07+0000 [main] internal.NodeStartupLogging.invoke - Exception during node startup [errorCode=b46fui, moreInformationAt=https://errors.corda.net/ENT/4.0/b46fui]

4.EC2インスタンスでのJDBCドライバは異なるディレクトリにある可能性があるため、PartyBのnode.confの「jarDirs」の値が正しいことを再確認してください。必要に応じて、修正してください。


I. すべてのcordaノードを起動します

すべてのEC2インスタンスにログインし、そこにコピーしたcordaノードディレクトリにアクセスします。

そのディレクトリで「java -jar corda.jar」を実行してcordaノードを起動します

ただし、HAノード(PartyB)を起動すると、次のようなエラーメッセージが表示されることがあります:

------------------ Corda Enterprise Edition 4.0 (8dcaeef) ---------------------------

Tip: You can issue SQL queries to the database from the Corda shell with the jdbc command
Logs can be found in : /path to PartyB folder/logs
! ATTENTION: This node is running in development mode! This is not safe for production deployment.
Database connection url is : jdbc:postgresql://ce4-pgsql.***********.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2
[ERROR] 04:24:40+0000 [main] internal.NodeStartupLogging.invoke - Could not create the DataSource: No migration defined for schema: poc.schemas.**Schema v1: Could not create the DataSource: No migration defined for schema: poc.schemas.**Schema v1 [errorCode=5k06pt, moreInformationAt=https://errors.corda.net/ENT/4.0/5k06pt]

これは、セクションGで説明したように、CorDappsに必要なスキーマ/テーブルがPostgreSQL DBに作成されていないためです。

必要な「移行スクリプト」を作成するには、セクションG(CorDappをビルドする環境)の作業ディレクトリで、以下のコマンドを実行してください。


java -jar tools-database-manager-4.0.jar - base-directory /full-path-to-your-cordapp/build/nodes/PartyB - create-migration-sql-for-cordapp
cd build/nodes/PartyB
jar cvf cordapps/migration.jar migration
cd ../../..
java -jar tools-database-manager-4.0.jar - base-directory /full-path-to-your-cordapp/build/nodes/PartyB - dry-run
java -jar tools-database-manager-4.0.jar - base-directory /full-path-to-your-cordapp/build/nodes/PartyB - execute-migration

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”が、新しく作成されました。

12.jpg

これで、EC2インスタンスHA-Hot(AZ1)で、PartyBノードが、次のようなコンソールメッセージで正常に起動されます。HA-Cold(AZ1)については起動待ち状態となります。

ubuntu@ip-**.**.**.**$ java -jar corda.jar

*************************************************************************************************************************************
* All rights reserved. *
* This software is proprietary to and embodies the confidential technology of R3 LLC ("R3"). *
* Possession, use, duplication or dissemination of the software is authorized only pursuant to a valid written license from R3. *
* IF YOU DO NOT HAVE A VALID WRITTEN LICENSE WITH R3, DO NOT USE THIS SOFTWARE. *
*************************************************************************************************************************************

______ __ _____ _ _ _____ _____ ____ ____ ____ ___ ____ _____
/ ____/ _________/ /___ _ | ____| \ | |_ _| ____| _ \| _ \| _ \|_ _/ ___|| ____|
/ / __ / ___/ __ / __ `/ | _| | \| | | | | _| | |_) | |_) | |_) || |\___ \| _|
/ /___ /_/ / / / /_/ / /_/ / | |___| |\ | | | | |___| _ <| __/| _ < | | ___) | |___
\____/ /_/ \__,_/\__,_/ |_____|_| \_| |_| |_____|_| \_\_| |_| \_\___|____/|_____|

--- Corda Enterprise Edition 4.0 (8dcaeef) --------------------------------------------------

Tip: You can issue SQL queries to the database from the Corda shell with the jdbc command

Logs can be found in : /full-path-to-PartyB-folder/logs
! ATTENTION: This node is running in development mode! This is not safe for production deployment.
Database connection url is : jdbc:postgresql://ce4-pgsql.********.ap-northeast-1.rds.amazonaws.com:5432/PartyB_HA2
Advertised P2P messaging addresses : internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008
RPC connection address : 0.0.0.0:10009
RPC admin connection address : 0.0.0.0:10049
Loaded 3 CorDapp(s) : Contract CorDapp: ***
Node for "PartyB" started up and registered in 16.17 sec

Welcome to the Corda interactive shell.
Useful commands include 'help' to see what is available, and 'bye' to shut down the node.

Thu May 23 05:26:59 UTC 2019>>>


J. HA機能をテストする

これで、図1のように、すべてのコーダノードがEC2インスタンスで正常に起動されました。

たとえば、PartyAとPartyBの間でトランザクション(txn-a)を発行すると、txn-aは正常に完了します。、PartyAノードのログファイルを確認するとPartyAが実際にロードバランサーに接続してPartyBへの接続したことが記録されています:

[INFO ] 2019-05-23T05:48:44,588Z [Messaging executor] messaging.P2PMessagingClient.createQueueIfAbsent - Create fresh queue internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr bound on same address {}

[INFO ] 2019-05-23T05:48:44,629Z [Thread-28 (ActiveMQ-client-global-threads)] bridging.BridgeControlListener.processControlMessage - Received bridge control message Create(nodeIdentity=O=PartyA, L=Osaka, C=JP, bridgeInfo=BridgeEntry(queueName=internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, targets=[internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008], legalNames=[O=PartyB, L=Osaka, C=JP], serviceAddress=false)) {
// note: above msg shows PartyA was trying to connect the LoadBalancer. "targets=[internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008"
[INFO ] 2019-05-23T05:48:44,629Z [Thread-28 (ActiveMQ-client-global-threads)] bridging.LoopbackBridgeManager.deployBridge - Deploying AMQP bridge for internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, source O=PartyA, L=Osaka, C=JP {}
[INFO ] 2019-05-23T05:48:44,648Z [Thread-28 (ActiveMQ-client-global-threads)] bridging.AMQPBridgeManager$AMQPBridge.invoke - Create new AMQP bridge {legalNames=O=PartyB, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, source=O=PartyA, L=Osaka, C=JP, targets=internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008}
[INFO ] 2019-05-23T05:48:44,649Z [Thread-28 (ActiveMQ-client-global-threads)] netty.AMQPClient.start - connect to: internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008 {}
[INFO ] 2019-05-23T05:48:44,784Z [nioEventLoopGroup-2-1] netty.AMQPClient.operationComplete - Connected to internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008 {}
[INFO ] 2019-05-23T05:48:44,788Z [nioEventLoopGroup-2-1] netty.AMQPChannelHandler.invoke - New client connection 790466bd from internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008 to /26.132.139.158:37634 {allowedRemoteLegalNames=O=PartyB, L=Osaka, C=JP, localCert=null, remoteAddress=internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008, remoteCert=null, serverMode=false}
[INFO ] 2019-05-23T05:48:44,846Z [nioEventLoopGroup-2-1] netty.LoggingTrustManagerWrapper.checkServerTrusted - Check Server Certpath:^M
C=JP,L=Osaka,O=PartyB[E341A0565CDBFF8699CBA8CB377382C0513CB0EA] issued by C=JP,L=Osaka,O=PartyB[1D6C7F86F4F99AED0CE281FE996A0C70DC5EFBB1]^M
C=JP,L=Osaka,O=PartyB[1D6C7F86F4F99AED0CE281FE996A0C70DC5EFBB1] issued by C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213]^M
C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773]^M
CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[null] {}
[INFO ] 2019-05-23T05:48:44,891Z [nioEventLoopGroup-2-1] netty.AMQPChannelHandler.invoke - Handshake completed with subject: O=PartyB, L=Osaka, C=JP, requested server name: e8c5bf64fbba23612e26a3302a65c60a.corda.net. {allowedRemoteLegalNames=O=PartyB, L=Osaka, C=JP, localCert=O=PartyA, L=Osaka, C=JP, remoteAddress=internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008, remoteCert=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T05:48:45,015Z [nioEventLoopGroup-2-1] bridging.AMQPBridgeManager$AMQPBridge.invoke - Bridge Connected {legalNames=O=PartyB, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, source=O=PartyA, L=Osaka, C=JP, targets=internal- PartyB-HA-LB-********.ap-northeast-1.elb.amazonaws.com:10008}

Logs in PartyA (txn-a)

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

[INFO ] 2019-05-23T05:37:25,681Z [Node thread-1] internal.Node.registerJolokiaReporter - Registering Jolokia JMX reporter: {}

//PartyBのCold Nodeでは、txn-aに関するログ情報はありません

logs in PartyB cold (txn-a)

[INFO ] 2019-05-23T05:26:59,167Z [Node thread-1] internal.Node.registerJolokiaReporter - Registering Jolokia JMX reporter: {}

//以降はtxn-aのログです。
[INFO ] 2019-05-23T05:49:18,883Z [Messaging executor] messaging.P2PMessagingClient.createQueueIfAbsent - Create fresh queue internal.peers.DLANwREshETUbbSsJhFT4PHMHLqnSvHBzVrzxTd6faYGeF bound on same address {}
[INFO ] 2019-05-23T05:49:18,978Z [Thread-8 (ActiveMQ-client-global-threads)] bridging.BridgeControlListener.processControlMessage - Received bridge control message Create(nodeIdentity=O=PartyB, L=Osaka, C=JP, bridgeInfo=BridgeEntry(queueName=internal.peers.DLANwREshETUbbSsJhFT4PHMHLqnSvHBzVrzxTd6faYGeF, targets=[26.132.139.158:10005], legalNames=[O=PartyA, L=Osaka, C=JP], serviceAddress=false)) {}
[INFO ] 2019-05-23T05:49:18,979Z [Thread-8 (ActiveMQ-client-global-threads)] bridging.LoopbackBridgeManager.deployBridge - Deploying AMQP bridge for internal.peers.DLANwREshETUbbSsJhFT4PHMHLqnSvHBzVrzxTd6faYGeF, source O=PartyB, L=Osaka, C=JP {}
[INFO ] 2019-05-23T05:49:18,997Z [Thread-8 (ActiveMQ-client-global-threads)] bridging.AMQPBridgeManager$AMQPBridge.invoke - Create new AMQP bridge {legalNames=O=PartyA, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DLANwREshETUbbSsJhFT4PHMHLqnSvHBzVrzxTd6faYGeF, source=O=PartyB, L=Osaka, C=JP, targets=26.132.139.158:10005}
[INFO ] 2019-05-23T05:49:18,998Z [Thread-8 (ActiveMQ-client-global-threads)] netty.AMQPClient.start - connect to: 26.132.139.158:10005 {}
[INFO ] 2019-05-23T05:49:19,124Z [nioEventLoopGroup-2-1] netty.AMQPClient.operationComplete - Connected to 26.132.139.158:10005 {}
[INFO ] 2019-05-23T05:49:19,149Z [nioEventLoopGroup-2-1] netty.AMQPChannelHandler.invoke - New client connection 16364379 from /26.132.139.158:10005 to /26.132.142.60:36896 {allowedRemoteLegalNames=O=PartyA, L=Osaka, C=JP, localCert=null, remoteAddress=/26.132.139.158:10005, remoteCert=null, serverMode=false}
[INFO ] 2019-05-23T05:49:19,258Z [nioEventLoopGroup-2-1] netty.LoggingTrustManagerWrapper.checkServerTrusted - Check Server Certpath:^M
C=JP,L=Osaka,O=PartyA[A5B65A4EF961EB9963C217598BDD2B3BAFD81263] issued by C=JP,L=Osaka,O=PartyA[8F7435C49DD49B99DB3D5083E40D8FEE34A62DDB]^M
C=JP,L=Osaka,O=PartyA[8F7435C49DD49B99DB3D5083E40D8FEE34A62DDB] issued by C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213]^M
C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773]^M
CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[null] {}
[INFO ] 2019-05-23T05:49:19,366Z [nioEventLoopGroup-2-1] netty.AMQPChannelHandler.invoke - Handshake completed with subject: O=PartyA, L=Osaka, C=JP, requested server name: 26a6b0b27deba4660c3598ce3f39c668.corda.net. {allowedRemoteLegalNames=O=PartyA, L=Osaka, C=JP, localCert=O=PartyB, L=Osaka, C=JP, remoteAddress=/26.132.139.158:10005, remoteCert=O=PartyA, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T05:49:19,461Z [nioEventLoopGroup-2-1] bridging.AMQPBridgeManager$AMQPBridge.invoke - Bridge Connected {legalNames=O=PartyA, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DLANwREshETUbbSsJhFT4PHMHLqnSvHBzVrzxTd6faYGeF, source=O=PartyB, L=Osaka, C=JP, targets=26.132.139.158:10005}
[INFO ] 2019-05-23T05:49:19,515Z [nioEventLoopGroup-2-1] engine.ConnectionStateMachine.invoke - Connection local open org.apache.qpid.proton.engine.impl.ConnectionImpl@4a5e5c39 {localLegalName=O=PartyB, L=Osaka, C=JP, remoteLegalName=O=PartyA, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T05:49:19,740Z [flow-worker] corda.flow.call - Received transaction acknowledgement request from party O=PartyA, L=Osaka, C=JP. {fiber-id=10000001, flow-id=1087877d-3892-4501-9b72-c714664c71b5, invocation_id=96c77912-6cea-4614-aced-8bba36aa5a34, invocation_timestamp=2019-05-23T05:49:18.397Z, origin=O=PartyA, L=Osaka, C=JP, session_id=96c77912-6cea-4614-aced-8bba36aa5a34, session_timestamp=2019-05-23T05:49:18.397Z, thread-id=268, tx_id=E4DA424F4AE1C5ABC22E2104E2481C2C811A54F61002154F3A1EFF80166726E9}
[INFO ] 2019-05-23T05:49:19,925Z [flow-worker] corda.flow.call - Transaction dependencies resolution completed. {fiber-id=10000001, flow-id=1087877d-3892-4501-9b72-c714664c71b5, invocation_id=96c77912-6cea-4614-aced-8bba36aa5a34, invocation_timestamp=2019-05-23T05:49:18.397Z, origin=O=PartyA, L=Osaka, C=JP, session_id=96c77912-6cea-4614-aced-8bba36aa5a34, session_timestamp=2019-05-23T05:49:18.397Z, thread-id=264, tx_id=E4DA424F4AE1C5ABC22E2104E2481C2C811A54F61002154F3A1EFF80166726E9}
[INFO ] 2019-05-23T05:49:23,419Z [flow-worker] corda.flow.call - Received transaction acknowledgement request from party O=PartyA, L=Osaka, C=JP. {fiber-id=10000001, flow-id=1087877d-3892-4501-9b72-c714664c71b5, invocation_id=96c77912-6cea-4614-aced-8bba36aa5a34, invocation_timestamp=2019-05-23T05:49:18.397Z, origin=O=PartyA, L=Osaka, C=JP, session_id=96c77912-6cea-4614-aced-8bba36aa5a34, session_timestamp=2019-05-23T05:49:18.397Z, thread-id=268, tx_id=E4DA424F4AE1C5ABC22E2104E2481C2C811A54F61002154F3A1EFF80166726E9}
// note: the msg in line 20 shows it was this PartyB (hot) node process the txn-a with PartyA

logs in PartyB hot (txn-a)

その後、PartyBのHot Nodeを停止し、二個目のトランザクションを発行します(txn-b)。

TXN-Bも正常に完了できることを確認できます。

因みに、PartyAのログを確認すると、PartyBのアクティブなノードを停止した直後、PartyAはPartyBが切断されたことを検出し、PartyBのロードバランサーに再接続する動作が確認できます。

[INFO ] 2019-05-23T05:48:50,765Z [nioEventLoopGroup-2-3] engine.ConnectionStateMachine.invoke - Connection local open org.apache.qpid.proton.engine.impl.ConnectionImpl@7f99bfe6 {localLegalName=O=PartyA, L=Osaka, C=JP, remoteLegalName=O=Regulator, L=Osaka, C=JP, serverMode=false}

[INFO ] 2019-05-23T07:15:10,415Z [nioEventLoopGroup-2-1] netty.AMQPClient.operationComplete - Disconnected from internal- PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008 {}
[INFO ] 2019-05-23T07:15:10,416Z [nioEventLoopGroup-2-1] netty.AMQPChannelHandler.invoke - Closed client connection 790466bd from internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008 to /26.132.139.158:37634 {allowedRemoteLegalNames=O=PartyB, L=Osaka, C=JP, localCert=O=PartyA, L=Osaka, C=JP, remoteAddress=internal-PartyB-HA-LB -*********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008, remoteCert=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T07:15:10,417Z [nioEventLoopGroup-2-1] bridging.AMQPBridgeManager$AMQPBridge.invoke - Bridge Disconnected {legalNames=O=PartyB, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, source=O=PartyA, L=Osaka, C=JP, targets=internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008}
[INFO ] 2019-05-23T07:15:10,422Z [nioEventLoopGroup-2-1] engine.ConnectionStateMachine.invoke - Connection local close org.apache.qpid.proton.engine.impl.ConnectionImpl@1d3c4dab {localLegalName=O=PartyA, L=Osaka, C=JP, remoteLegalName=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T07:15:10,424Z [nioEventLoopGroup-2-1] engine.ConnectionStateMachine.invoke - Transport Error TransportImpl [_connectionEndpoint=org.apache.qpid.proton.engine.impl.ConnectionImpl@1d3c4dab, org.apache.qpid.proton.engine.impl.TransportImpl@51b2ec6f] {localLegalName=O=PartyA, L=Osaka, C=JP, remoteLegalName=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T07:15:10,424Z [nioEventLoopGroup-2-1] engine.ConnectionStateMachine.invoke - Error: connection aborted {localLegalName=O=PartyA, L=Osaka, C=JP, remoteLegalName=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T07:15:11,416Z [nioEventLoopGroup-2-1] netty.AMQPClient.nextTarget - Retry connect to internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008 {}
[INFO ] 2019-05-23T07:15:11,431Z [nioEventLoopGroup-2-2] netty.AMQPClient.operationComplete - Connected to internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008 {}
[INFO ] 2019-05-23T07:15:11,432Z [nioEventLoopGroup-2-2] netty.AMQPChannelHandler.invoke - New client connection 2fab52c6 from internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008 to /26.132.139.158:37842 {allowedRemoteLegalNames=O=PartyB, L=Osaka, C=JP, localCert=null, remoteAddress=internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008, remoteCert=null, serverMode=false}
[INFO ] 2019-05-23T07:15:11,450Z [nioEventLoopGroup-2-2] netty.LoggingTrustManagerWrapper.checkServerTrusted - Check Server Certpath:^M
C=JP,L=Osaka,O=PartyB[E341A0565CDBFF8699CBA8CB377382C0513CB0EA] issued by C=JP,L=Osaka,O=PartyB[1D6C7F86F4F99AED0CE281FE996A0C70DC5EFBB1]^M
C=JP,L=Osaka,O=PartyB[1D6C7F86F4F99AED0CE281FE996A0C70DC5EFBB1] issued by C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213]^M
C=US,L=New York,OU=Corda,O=R3 HoldCo LLC,CN=Corda Doorman CA[EBEE2E30152940AE19981ED86FE37D7F07A2C213] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773]^M
CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[7CAEA9DFB948012B13890B9AE645851C39170773] issued by CN=Corda Node Root CA,O=R3,OU=corda,L=London,C=UK[null] {}
[INFO ] 2019-05-23T07:15:11,479Z [nioEventLoopGroup-2-2] netty.AMQPChannelHandler.invoke - Handshake completed with subject: O=PartyB, L=Osaka, C=JP, requested server name: e8c5bf64fbba23612e26a3302a65c60a.corda.net. {allowedRemoteLegalNames=O=PartyB, L=Osaka, C=JP, localCert=O=PartyA, L=Osaka, C=JP, remoteAddress=internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com/26.132.138.97:10008, remoteCert=O=PartyB, L=Osaka, C=JP, serverMode=false}
[INFO ] 2019-05-23T07:15:11,481Z [nioEventLoopGroup-2-2] bridging.AMQPBridgeManager$AMQPBridge.invoke - Bridge Connected {legalNames=O=PartyB, L=Osaka, C=JP, maxMessageSize=10485760, queueName=internal.peers.DL33z2w7VP2FYTRrowmhC54mZVZQjtHhYxN2PzWL5hLovr, source=O=PartyA, L=Osaka, C=JP, targets=internal-PartyB-HA-LB-*********.ap-northeast-1.elb.amazonaws.com:10008}
[INFO ] 2019-05-23T07:15:11,484Z [nioEventLoopGroup-2-2] engine.ConnectionStateMachine.invoke - Connection local open org.apache.qpid.proton.engine.impl.ConnectionImpl@6455ea8d {localLegalName=O=PartyA, L=Osaka, C=JP, remoteLegalName=O=PartyB, L=Osaka, C=JP, serverMode=false}
//note: the msg in line 2 and line 8 show the PartyA detected the disconnection of PartyB(hot) and retry to connect to Loadbalancer.

以下はPartyAのTxn-bのログです。これは、PartyAが正常にPartyB(Cold)署名を受信したことを示しています。

[INFO ] 2019-05-23T07:15:22,234Z [pool-8-thread-3] shell.StartShellCommand.main - Executing command "our txn-b commands here", {}

[INFO ] 2019-05-23T07:15:28,650Z [flow-worker] corda.flow.call - Sending transaction to notary: O=Notary, L=Osaka, C=JP. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=903, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}

[INFO ] 2019-05-23T07:15:30,639Z [flow-worker] corda.flow.call - Notary responded. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=903, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:30,649Z [flow-worker] corda.flow.notariseAndRecord - Recording transaction locally. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=903, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:30,708Z [flow-worker] corda.flow.notariseAndRecord - Recorded transaction locally successfully. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=903, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:30,847Z [flow-worker] corda.flow.call - Party O=PartyB, L=Osaka, C=JP received the transaction. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=912, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:30,847Z [flow-worker] corda.flow.call - All parties received the transaction successfully. {actor_id=internalShell, actor_owning_identity=O=PartyA, L=Osaka, C=JP, actor_store_id=NODE_CONFIG, fiber-id=10000002, flow-id=b6aa33d8-307a-4338-b8bc-9ce8e3cf1962, invocation_id=2a2f2483-1a24-4702-8d0f-9f02072f27ab, invocation_timestamp=2019-05-23T07:15:22.263Z, origin=internalShell, session_id=e4fe6f15-d925-42e5-8510-30d00af8a86f, session_timestamp=2019-05-23T04:28:05.971Z, thread-id=912, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
// note: the tx_id and msg in line 2 and 7 show that PartyA processed txn-b with PartyB

以下はPartyB Cold NodeのTxn-bのログです。これは、PartyB(Cold)はPartyAからtxn-bを受け取り、正常に処理したことを示しています。

[INFO ] 2019-05-23T07:15:39,557Z [flow-worker] corda.flow.call - Transaction dependencies resolution completed. {fiber-id=10000001, flow-id=7ee8d76d-25f1-439a-9f43-45cffc8c10e1, invocation_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, invocation_timestamp=2019-05-23T07:15:38.233Z, origin=O=PartyA, L=Osaka, C=JP, session_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, session_timestamp=2019-05-23T07:15:38.233Z, thread-id=653, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}

[INFO ] 2019-05-23T07:15:46,418Z [flow-worker] corda.flow.call - Received transaction acknowledgement request from party O=PartyA, L=Osaka, C=JP. {fiber-id=10000001, flow-id=7ee8d76d-25f1-439a-9f43-45cffc8c10e1, invocation_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, invocation_timestamp=2019-05-23T07:15:38.233Z, origin=O=PartyA, L=Osaka, C=JP, session_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, session_timestamp=2019-05-23T07:15:38.233Z, thread-id=658, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:46,459Z [flow-worker] corda.flow.call - Transaction dependencies resolution completed. {fiber-id=10000001, flow-id=7ee8d76d-25f1-439a-9f43-45cffc8c10e1, invocation_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, invocation_timestamp=2019-05-23T07:15:38.233Z, origin=O=PartyA, L=Osaka, C=JP, session_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, session_timestamp=2019-05-23T07:15:38.233Z, thread-id=661, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:46,496Z [flow-worker] corda.flow.call - Successfully received fully signed tx. Sending it to the vault for processing. {fiber-id=10000001, flow-id=7ee8d76d-25f1-439a-9f43-45cffc8c10e1, invocation_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, invocation_timestamp=2019-05-23T07:15:38.233Z, origin=O=PartyA, L=Osaka, C=JP, session_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, session_timestamp=2019-05-23T07:15:38.233Z, thread-id=661, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
[INFO ] 2019-05-23T07:15:46,626Z [flow-worker] corda.flow.call - Successfully recorded received transaction locally. {fiber-id=10000001, flow-id=7ee8d76d-25f1-439a-9f43-45cffc8c10e1, invocation_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, invocation_timestamp=2019-05-23T07:15:38.233Z, origin=O=PartyA, L=Osaka, C=JP, session_id=86bf5cb8-4442-4de4-93ef-075e6eba0877, session_timestamp=2019-05-23T07:15:38.233Z, thread-id=661, tx_id=DC1B4FBE9E052302EFDB733086C651C7615EDFFE6D37BD23450E45D9BB530D16}
// note: the tx_id and msg in line 1 and 5 show that this PartyB (cold) node processed txn-b with the PartyA

停止した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.


本記事はTIS株式会社様のMedium記事の転載となっております(了承済み)。

本文URL:https://medium.com/@TIS_BC_Prom/r3-corda%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7-ha-%E3%81%A8%E3%81%9D%E3%81%AE%E6%A7%8B%E6%88%90%E6%96%B9%E6%B3%95-34cb5dd409d1

本記事に関するお問い合わせ:

SBI R3 Japan

info-srj@sbir3japan.co.jp