Logo
    Logo

    Search

    R3-Solana連携

    Blockchainトレンド

    Corda活用事例

    Corda技術

    おすすめ記事

    記事を探す

    その他

    お客様サポート

    SBI R3 Japan HP

    お問い合わせ

    状態マネージャー専用DB設定手順

    公開日
    Nov 12, 2024
    カテゴリ
    Corda技術を知る
    タグ
    🛠️Node運用⭐Corda5
    筆者
    立山
    image
    icon
    この記事で学べること

    状態データの分散管理の方法について

    icon
    目次
    • はじめに
    • 状態マネージャーとは?
    • 本記事の目的
    • 想定読者
    • 前提
    • 手順
    • 状態マネージャー専用RDBの設定
    • Corda clusterの設定ファイル編集
    • Corda cluster起動
    • 起動後の確認方法とエラーシューティング
    • おわりに
    • 付録:状態データ一覧・bitnami postgresを用いた設定例

    はじめに

    状態マネージャーとは?

    状態マネージャーとはflowのチェックポイントやP2Pセッション、flowステータスなどCorda clusterの状態データの一貫性や完全性を保持するために、RDB上の管理テーブルに挿入, 更新, 削除をするための制御機構です。

    本記事の目的

    デフォルトでは状態データは共通のRDBに保存されますが、データの保存先が集中することでRDBのI/Oに対するボトルネックになりえます。そのためCorda clusterでは状態データをタイプごとに分散して、別々のRDBに保存できます。本記事ではその設定手順を紹介します。

    💡

    状態データはCordaの英語版ではStateと表記されていますが、Cordaにはブロックチェーン上の価値(債権、トークン、法定通貨)という意味を表す言葉としてもStateが用いられています。本記事では混乱をさけるためStateという言葉を使わず状態データと表現します。併せて状態データの管理機構を状態マネージャー(英語ではState Manager)と表現します。

    想定読者

    • Corda cluster構築に携わるインフラエンジニア

    前提

    • 任意のKubernetes clusterが起動していること。本記事ではバージョン1.30を使用しています。
    • 操作端末にcorda-cli.shがインストールされていること。本記事では、corda 5.2.1バージョンを使用しています。インストール方法およびバージョン確認方法についてはこちらをご覧ください。
    • 操作端末にpsqlがインストールされていること。本記事では14.12バージョンを使用しています。
    • 状態データ専用のRDBが用意されていること。本記事では各状態データ専用のRDBを6つ用意します。本番環境では、独立したRDBインスタンスを用意する必要がありますが、学習目的の場合、Cordaと同じKubernetes clusterにPostgreSQL Podを代用できます。詳しい手順は「付録」の「bitnami postgresを用いた状態データ専用DB設定手順」をご覧ください。

    手順

    状態マネージャー専用RDBの設定

    状態マネージャー専用RDBへの接続はCorda cluster起動時に行われますが、以下のRDBの設定はCorda cluster起動前に完了させる必要があります。

    1. 任意のスキーマに状態データテーブルの作成 状態データテーブルは、corda-cli.shのdatabaseコマンドを使って出力したSQLを適用して作成します。以下はスキーマ「sm_flow_checkpoint」に状態データ関連のテーブルを作成する手順例です。
    2. 状態データテーブル操作用のロール作成
    3. PostgreSQLロールを作成して、「1」で作成したテーブルへの操作権限を付与します。 以下はロール「sm_user_5433」を作成して、「1」で作成したスキーマ「sm_flow_checkpoint」に対する操作権限を付与する手順例です。

    Corda clusterの設定ファイル編集

    状態マネージャーが分離させたテーブルに状態データを記録できるようにするためには、helm chartにわたすvalues.yaml中に状態データテーブルへの接続情報を定義してCorda clusterを起動します。冗長になるため、以下では、flowCheckpointの設定のみを記載していますが、workerと状態データの対応関係は、「付録」の「状態データ一覧」をご覧ください。

    Corda cluster起動

    helm installでCorda clusterを起動します。

    kubectl get podsで全てのpodがrunningになっていることを確認します。

    起動後の確認方法とエラーシューティング

    「Corda cluster起動」においてすべてのPodが起動した場合でも、RDBへの接続設定が誤っている場合、任意の操作で失敗することがあります。たとえば、Corda clusterを起動後にflow statusの状態を確認した場合、以下のエラーが返ってくることがあります。

    image

    ”ERROR: relation \”state\” does not exist\n Partition: 69”というエラーは一般的にはPostgreSQLでstateというテーブルが存在しない場合に出力するエラーです。こちらは2つの観点で、原因切り分けができます。

    • 接続先のRDBにテーブルが生成されていない場合
      • SQL発行コマンドの実行結果を確認してエラーが出ていないことをご確認ください。
      • RDBにログインしてテーブルの存在をご確認ください。
    • values.yamlに設定したusernameやpasswordが間違っている場合
      • 「状態データテーブル操作用のロール作成」で作成したロールおよびパスワードがそれぞれのRDBへのusernameやpassword として設定されているかご確認ください。
      • 特にRDBのadminロールとパスワードを誤って設定しているケースが散見されます。この場合、RDBには接続はできるためCorda clusterのPodは起動します。しかし、adminロールはテーブルが属するスキーマをsearch_pathとして設定していないため、テーブルを見つけることができません。そのため、状態データの書き込みができずに、Cordaの処理が失敗します。 以下誤った設定例です。
      • また関連workerが以下のWARNを繰り返し出力している場合、Corda clusterからRDBの接続に失敗している可能性が高いです。kubectl logs 各workerのpod名 を実行して確認してください。

    おわりに

    DBを分散した状態データの管理は、パフォーマンスの向上に有効であると言われています。理想的にはすべての状態データを分散させることですが、コスト的に難しい場合は以下の状態データだけでも分散することをご検討ください。

    • flowMapping
    • flowCheckpoint
    • tokenPoolCache (Tokenを使う場合)

    また、以下に付録の設定例も載せてありますので、ご興味があればご確認ください。

    📬
    最後までお読みいただきありがとうございます。当社へのご質問・ご要望がございましたら、📪SBI R3 Japan お問い合わせフォーム📪よりお気軽にお問い合わせください!

    <ご質問・ご要望の例>

    • Corda Portalの記事について質問したい
    • ブロックチェーンを活用した新規事業を相談したい
    • 企業でのブロックチェーン活用方法を教えて欲しい 等々
    📢
    また、厳選されたCordaに関する最新情報をお伝えるするメールマガジンやX、当社主催のイベントコミュニティを運営しております。ぜひご登録ください。
    • Cordaメールマガジンに登録
    • X(旧Twitter)をフォロー
    • 弊社イベントコミュニティ(Connpass)に参加
    ✍️
    Written by 立山 和人 (Kazuto Tateyama)
    image

    SBI R3 Japan エンジニアリング部所属

    ソリューションアーキテクト/PoC支援

    This is the way. みんなでキャズムを超えていきましょう!

    →筆者の記事一覧

    ‣

    付録:状態データ一覧・bitnami postgresを用いた設定例

    Logo

    © copyright SBI R3 Japan 2025

    GitHubYouTubeXFacebookLinkedIn
    # PostgreSQLの接続情報を定義。
    export PGHOST=localhost
    export PGPORT=5433
    
    # テーブルが属するスキーマを定義
    export SCHEMA_NAME=sm_flow_checkpoint
    
    # PostgreSQLのadminユーザーを定義
    export PGUSER=postgres
    export PGPASSWORD=postgrespassword
    
    # 操作ディレクトリ配下にSQL出力用ディレクトリを作成。
    mkdir ./${SCHEMA_NAME}
    
    # corda-cli.sh databaseコマンドでスキーマおよびテーブル作成用のSQLを出力。
    # 正常に終了した場合、特に返り値はなく指定したディレクトリ(この例の場合./sm_flow_checkpointディレクトリ)配下に、statemanager.sqlというファイルが出力する。
    # DBの状態を事前チェックするための--jdbc-urlオプションをつけているので、PostgreSQLに到達しない環境の場合は失敗する。
    # PostgreSQLに到達しない環境で実行したい場合は、--jdbc-url, -u, -pオプションを除外して実行すること。
    corda-cli.sh database spec -s "statemanager" -g "statemanager:${SCHEMA_NAME}"  --jdbc-url "jdbc:postgresql://${PGHOST}:${PGPORT}/${PGDATABASE}" -u ${PGUSER}  -p ${PGPASSWORD} -c -l ./${SCHEMA_NAME}
    
    # ./sm_flow_checkpoint/statemanager.sqlが作成されていることを確認。
    cat ./sm_flow_checkpoint/statemanager.sql
    
    CREATE SCHEMA IF NOT EXISTS sm_flow_checkpoint;
    
    -- *********************************************************************
    -- Update Database Script
    -- *********************************************************************
    -- Change Log: net/corda/db/schema/statemanager/db.changelog-master.xml
    -- Ran at: 2024/10/22 15:56
    -- Against: postgres@jdbc:postgresql://localhost:5433/cordacluster
    -- Liquibase version: 4.19.0
    -- *********************************************************************
    
    SET SEARCH_PATH TO sm_flow_checkpoint, "$user","public";
    .
    .
    .
    UPDATE sm_flow_checkpoint.databasechangeloglock SET LOCKED = FALSE, LOCKEDBY = NULL, LOCKGRANTED = NULL WHERE ID = 1;
    
    SET SEARCH_PATH TO sm_flow_checkpoint, "$user","public";
    
    # 数十行のSQLファイルが出力されればOK
    
    # SQLを適用
    psql -f ./${SCHEMA_NAME}/statemanager.sql
    CREATE SCHEMA
    SET
    .
    .
    .
    SET
    
    # エラーが出なければOK
    # 環境変数の一部は「1」の手順例から流用
    # テーブル操作用のロールおよびパスワードを定義
    export STATEMANAGER_USER=sm_user_${PGPORT}
    export STATEMANAGER_PASSWORD=sm_password_${PGPORT}
    
    # テーブルを操作するPostgreSQLロールの作成とスキーマへの権限付与を実行するためのSQL出力
    echo "CREATE USER ${STATEMANAGER_USER} WITH ENCRYPTED PASSWORD '${STATEMANAGER_PASSWORD}'; \
    GRANT USAGE ON SCHEMA ${SCHEMA_NAME} TO ${STATEMANAGER_USER};
    GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA ${SCHEMA_NAME} TO ${STATEMANAGER_USER};
    GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA ${SCHEMA_NAME} TO ${STATEMANAGER_USER};
    GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA ${SCHEMA_NAME} TO ${STATEMANAGER_USER};
    ALTER ROLE ${STATEMANAGER_USER} SET search_path TO ${SCHEMA_NAME};" > ./${SCHEMA_NAME}/setting_user_schema.sql
    
    # SQLを適用
    psql -f ./${SCHEMA_NAME}/setting_user_schema.sql
    CREATE ROLE
    GRANT
    GRANT
    GRANT
    GRANT
    ALTER ROLE
    # エラーが出なければOK
    # values.yaml
    image:
      registry: "任意のdocker repository"
      tag: "5.2.1.0"
    
    # databasesセクションに接続するDBの基本情報を定義
    # id: values.yaml内でのエイリアス。同ファイルの別箇所でDBに関するidを要求された場合に設定。
    # name: database名
    # host: 接続DBのホスト名
    # port: 接続DBのポート番号
    databases:
      - id: default
        name: "cordacluster"
        host: "postgres-postgresql"
        port: 5432
        type: "postgresql"
      - id: "flow-checkpoint-state-manager"
        name: "cordacluster"
        host: "postgres-5433-postgresql"
        port: 5433
        type: "postgresql"
      - id: "flow-mapping-state-manager"
        name: "cordacluster"
        host: "postgres-5434-postgresql"
        port: 5434
        type: "postgresql"
      - id: "flow-status-state-manager"
        name: "cordacluster"
        host: "postgres-5435-postgresql"
        port: 5435
        type: "postgresql"
      - id: "key-rotation-state-manager"
        name: "cordacluster"
        host: "postgres-5436-postgresql"
        port: 5436
        type: "postgresql"
      - id: "p2p-session-state-manager"
        name: "cordacluster"
        host: "postgres-5437-postgresql"
        port: 5437
        type: "postgresql"
      - id: "token-pool-cache-state-manager"
        name: "cordacluster"
        host: "postgres-5438-postgresql"
        port: 5438
        type: "postgresql"
    .
    .
    .
    # 状態マネージャーが各タイプの状態データを保存するDBおよびスキーマ名を設定
    stateManager:
      # flowCheckpointという状態データの保存先設定
      flowCheckpoint:
        type: Database
        # databasesで定義したidを設定
        storageId: "flow-checkpoint-state-manager"
        # 接続先DBに作成済のスキーマ名を設定
        partition: "sm_flow_checkpoint"
      flowMapping:
        type: Database
        storageId: "flow-mapping-state-manager"
        partition: "sm_flow_mapping"
      flowStatus:
        type: Database
        storageId: "flow-status-state-manager"
        partition: "sm_flow_status"
      keyRotation:
        type: Database
        storageId: "key-rotation-state-manager"
        partition: "sm_key_rotation"
      p2pSession:
        type: Database
        storageId: "p2p-session-state-manager"
        partition: "sm_p2p_session"
      tokenPoolCache:
        type: Database
        storageId: "token-pool-cache-state-manager"
        partition: "sm_token_pool_cache"
    .
    .
    .
    # 各workerが状態データテーブルを操作するために、各DBに接続するためのusernameとpasswordを定義する。
    workers:
      flow:
        image:
          repository: "corda-ent-flow-worker"
        replicaCount: 1
        stateManager:
          # flowCheckpointに紐づいたDB(postgres-5433-postgresql)に接続するためのロールおよびパスワード設定
          # 下記例では、シークレット「my-secret」のキー「sm_user_5433」および「sm_password_5433」を参照しているが、直接定義することもできる。
          flowCheckpoint:
            username:
              valueFrom:
                secretKeyRef:
                  name: "my-secret"
                  key: "sm_user_5433"
            password:
              valueFrom:
                secretKeyRef:
                  name: "my-secret"
                  key: "sm_password_5433"
    .
    .
    .
    # 他のworkerでも同様の定義をする。
    helm install corda ~/Corda/Corda5/5.2.1/corda-enterprise-5.2.1.tar -f ./values_with_statemanager.yaml
    NAME: corda
    LAST DEPLOYED: Tue Oct 15 15:59:34 2024
    NAMESPACE: corda-cluster1
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    1. Extract the username and password for the REST API admin created during bootstrap:
    kubectl get secret my-secret --namespace corda-cluster1 -o go-template='{{ .data.restapiusername | base64decode }}'
    kubectl get secret my-secret --namespace corda-cluster1 -o go-template='{{ .data.restapipassword | base64decode }}'
    
    2. Expose the API endpoint on localhost by running this command:
    kubectl port-forward --namespace corda-cluster1 deployment/corda-corda-enterprise-rest-worker 8888 &
    
    3. The API endpoint definition can then be accessed via: https://localhost:8888/api/v1/swagger
    
    For more information, see the Corda 5 documentation at docs.r3.com.
    SR19-032:files_for_writing_article ktateyam$ kubectl get pods
    NAME                                                              READY   STATUS      RESTARTS       AGE
    corda-corda-enterprise-create-topics-zc45h                        0/1     Completed   0              4m1s
    corda-corda-enterprise-crypto-worker-67d98d478c-7zzhq             1/1     Running     0              3m15s
    corda-corda-enterprise-db-worker-5f88d44744-5t8dv                 1/1     Running     0              3m15s
    corda-corda-enterprise-flow-mapper-worker-d445ffcbd-6tqvx         1/1     Running     0              3m15s
    corda-corda-enterprise-flow-worker-5b7dc488f-9qwnj                1/1     Running     0              3m15s
    corda-corda-enterprise-membership-worker-7f4d4b495d-bqsxl         1/1     Running     0              3m15s
    corda-corda-enterprise-p2p-gateway-worker-5597f5f69d-q5mzz        1/1     Running     0              3m15s
    corda-corda-enterprise-p2p-link-manager-worker-86d4644546-9c466   1/1     Running     0              3m15s
    corda-corda-enterprise-persistence-worker-7486767876-4dvs4        1/1     Running     0              3m15s
    corda-corda-enterprise-preinstall-checks-g25cf                    0/1     Completed   0              4m25s
    corda-corda-enterprise-rest-worker-6d94844597-t4prs               1/1     Running     0              3m15s
    corda-corda-enterprise-setup-db-mr4vs                             0/1     Completed   0              3m48s
    corda-corda-enterprise-setup-rbac-7cmlq                           0/1     Completed   0              3m15s
    corda-corda-enterprise-token-selection-worker-6c5bc6cfb6-n49ct    1/1     Running     0              3m15s
    corda-corda-enterprise-uniqueness-worker-6fcf566cf6-wmqc7         1/1     Running     0              3m15s
    corda-corda-enterprise-verification-worker-6885cf7b-2jwb4         1/1     Running     0              3m15s
    kafka-0                                                           1/1     Running     1 (167m ago)   167m
    kafka-1                                                           1/1     Running     1 (167m ago)   167m
    kafka-2                                                           1/1     Running     0              167m
    kafka-zookeeper-0                                                 1/1     Running     0              167m
    postgres-5432-postgresql-0                                        1/1     Running     0              158m
    postgres-5433-postgresql-0                                        1/1     Running     0              154m
    postgres-5434-postgresql-0                                        1/1     Running     0              153m
    postgres-5435-postgresql-0                                        1/1     Running     0              153m
    postgres-5436-postgresql-0                                        1/1     Running     0              153m
    postgres-5437-postgresql-0                                        1/1     Running     0              153m
    postgres-5438-postgresql-0                                        1/1     Running     0              153m
    # PostgreSQLにadminロール「postgres」でログインして、roleとsearch_pathの対応関係を出力
    cordacluster=# SELECT rolname, rolconfig
    FROM pg_roles
    WHERE rolconfig IS NOT NULL;
       rolname    |            rolconfig             
    --------------+----------------------------------
     sm_user_5433 | {search_path=sm_flow_checkpoint}
    (1 row)
    
    # adminロールでテーブル一覧を表示。search_pathが設定されていないのでテーブルが見つからない。
    cordacluster=# \dt
    Did not find any relations.
    
    # sm_user_5433ロールで再ログインして、テーブル一覧を表示。stateが表示される。
    cordacluster=> \dt
                           List of relations
           Schema       |         Name          | Type  |  Owner   
    --------------------+-----------------------+-------+----------
     sm_flow_checkpoint | databasechangelog     | table | postgres
     sm_flow_checkpoint | databasechangeloglock | table | postgres
     sm_flow_checkpoint | state                 | table | postgres
    (3 rows)
    
    # values.yamlを確認。usernameとして、adminロール「postgres」が設定されている。
    # この場合、Corda clusterがDBにアクセスしてもテーブルを見つけられずにエラーになる。
    workers:
      flow:
        image:
          repository: "corda-ent-flow-worker"
        replicaCount: 1
        stateManager:
          flowCheckpoint:
            username:
              value: "postgres" # -> sm_user_5433が正しい。
            password:
              value: "postgrespassword5433" # -> sm_user_5433のパスワードが正しい。
    # 可読性のために加工していますが、本来は1行のメッセージとして出力されます。messageフィールドを確認してください。
    {
      "instant": {
        "epochSecond": 1729582296,
        "nanoOfSecond": 257000000
      },
      "thread": "flow-event-mediator-long-running-thread-75889d88-a714-4151-90e5-4610fc18934b",
      "level": "WARN",
      "loggerName": "net.corda.messaging.mediator.processor.ConsumerProcessor-FlowEventMediator",
      # stateテーブルが見つからないWARN
      "message": "Retrying processing: ERROR: relation \"state\" does not exist\n  Position: 68.",
      "endOfBatch": false,
      "loggerFqcn": "org.apache.logging.slf4j.Log4jLogger",
      "threadId": 100,
      "threadPriority": 5
    }