Taking ledger snapshots and using them to join channels¶
チャネル上のトランザクションを処理する際、ピアはチャネル内の他のピアと同時にトランザクションを承認し検証するため、必要最小限の台帳データを保持する必要があります。これには、ステートデータベース上に保持される「ワールドステート」が含まれます。ワールドステートは、最も直近にコミットされたブロック時点での台帳上のすべてのキーの現在の値(例えば、特定の資産の所有者)を表します。ピアが必要な台帳データのコピーを行う方法は2つあります。
- 初期設定ブロック(いわゆる「ジェネシスブロック」)からチャネルに参加し、オーダーリングサービスからブロックを継続的に取得し、それらをローカルで処理し、台帳に書き込まれた最新のブロックに到達するまで続ける。このシナリオでは、ワールドステートはブロックから構築されます。
- 個々のブロックを取得して処理することなく、特定のブロック番号時点での最小限の台帳データを含む「スナップショット」からチャネルに参加する。
最初の方法は、チャネルに参加する一般的な方法ですが、構築済のチャネルのサイズ(数千ブロックに達する可能性あり)によっては、ピアがチャネルにコミットされたすべてのブロックをプルして処理するのに時間がかかる場合があります。この方法でチャネルに参加するピアは、チャネル作成以降のすべてのブロックを保存する必要があり、組織のストレージコストが増加します。さらに、スナップショットによる参加は、ピアに最新のチャネル設定を提供します。これは、ジェネシスブロック以降にチャネル設定が変更された場合、重要な情報となる可能性があります。例えば、ピアはオーダーリングサービスからブロックを正常に取得する前に、最新のチャネル設定からorderer endpointやCA証明書を取得する必要がある場合があります。
このトピックでは、スナップショットを使用してピアをチャネルに参加させるプロセスを説明します。
Limitations¶
スナップショットを作成し、そのスナップショット(「チェックポイント」とも呼ばれる)を使用してピアをチャネルに接続する方法は、台帳上のすべてのブロックを処理して保存するよりも時間がかからず、ストレージコストを節約できます。ただし、以下の制限事項に注意が必要です:
- スナップショットから参加したピアは、スナップショットの取得以前にコミットされたブロック(またはブロック内のトランザクション)をクエリできません。同様に、スナップショット以前に存在したキーの履歴をクエリすることもできません。例えば、ピアがチャネルに参加するために使用したスナップショットがブロック1000で取得された場合、0-999のブロックはクエリできません。これらのブロック内のデータをクエリするアプリケーションは、該当するブロックを含むピアをターゲットにする必要があります。このため、組織は少なくとも1つのピアにすべての履歴データを保持し、履歴クエリのターゲットとしてこのピアを指定する可能性が高いでしょう。
- 特定の時点でのスナップショットを取得しているピアは、スナップショットが生成されている間、トランザクションの承認やクエリは実行可能ですが、チャネルにブロックをコミットすることはできません。スナップショットの取得はリソースを消費する操作であるため、当該ピアでのトランザクションの承認や、他のチャネルにおけるブロックのコミットが遅れる可能性があります。これらの理由から、スナップショットは必要な場合のみ取得されることが想定されています(例えば、新しいピアがチャネルに参加するためにスナップショットが必要な場合、または組織が台帳の分岐が発生していないことを確認したい場合)。
- チャネル内の組織間で共有されるプライベートデータは少なくとも一部が異なるため、スナップショットにはプライベートデータは含まれません(プライベートデータのハッシュは含まれますが、データ自体は含まれません)。スナップショットを使用してチャネルに参加するピアは、自身が所属するコレクションを検出し、それらのコレクションに所属するピアから関連するプライベートデータを直接取得します。このプライベートデータの同期は、ピアがチャネルに参加した後開始され、時間がかかる場合があります。
- スナップショットプロセスは、既にチャネルに参加しているピアの台帳をアーカイブまたは削除しません。同様に、スナップショットはピアの完全なバックアップを取る方法として設計されていません。プライベートデータやピアの構成情報(MSPなど)はスナップショットに含まれないためです。
- スナップショットを使用してチャネルに参加したピアに対しては、
reset、rollback、およびrebuild-dbsコマンドを使用できません。これは、ピアがこれらの操作に必要なブロックファイルをすべて持っていないためです。代わりに、スナップショットを使用してチャネルに参加したピアは、同じまたはより新しいスナップショットから再構築されることが想定されています。
Considerations¶
- ジェネシスブロック、スナップショットのどちらを使ってピアに参加するかを決定する際は、ジェネシスブロックからのブロック数に基づいてピアがチャネルに参加するまでに要する時間、ピアがジェネシスブロックの元のチャネル設定に基づいてオーダーリングサービスからブロックを取得できるかどうか、およびチャネルの全履歴(過去のブロック、トランザクション、ステート情報)をクエリする必要があるかどうかを考慮してください。
- 承認リクエストやクエリに最新のブロックコミットが不要な場合、スナップショットを生成するピアをターゲットにできます。
- 承認リクエストやクエリに最新のブロックコミットが必要な場合、サービスディスカバリーを利用してチャネル内のブロック高が最も高いピアを特定しターゲットにすることで、スナップショットを生成しているピアを回避できます。または、特定のピアをスナップショット作成用とし、そのピアを承認やクエリに利用しないように設定できます。例えば、
peer.gossip.externalEndpointを設定しないことで、ピアがサービスディスカバリーに参加しないようにします。 - ピアがすべての予想されるチャネルに参加し、受け取る権限のあるすべてのプライベートデータを同期するまで、承認やクエリに利用可能にしない方が良い可能性があります。
Overview¶
スナップショットは、既にチャネルにピアを保有する組織や、チャネルに新規に参加する組織が利用可能です。いずれのケースにおいても、プロセスはほぼ同じです。
- スナップショットをスケジュールする。それぞれのスナップショットは、各ピアで正確に同じ台帳の高さで取得する必要があります。これにより、組織はスナップショットを比較して同じデータが含まれていることを確認できます。台帳の高さは、現在のブロック高と同じかそれ以上でなければなりません(より高いブロック高でスケジュールされたスナップショットは、指定したブロック高に到達した時点で取得されます)。より低いブロック高からスナップショットを取得することはできません。現在の高さより低い高さでスナップショットをスケジュールしようとすると、エラーが発生します。チャネルに参加するためにスナップショットを使用したピアも、スナップショットを取得するために使用できます。スナップショットは必要に応じてスケジュールできるほか、組織間で合意して定期的な間隔でスケジュールすることもできます(例えば10,000ブロックごと)。これにより、一貫性があり最新のスナップショットが常に利用可能になります。ただし、再帰的なスナップショットをスケジュールすることはできません。各スナップショットは独立してスケジュールする必要があります。ただし、スケジュールできるスナップショットの数に制限はありません。スナップショットからピアに参加する際は、最新のチャネル構成ブロックの高さよりも新しいスナップショットを使用することが推奨されます。 これにより、ピアはorderering service endpointやCA証明書を含む最新のチャネル設定を取得できます。
- 指定した台帳の高さに到達すると、ピアがスナップショットを取得する。スナップショットは、公開されたステートを含むファイル、プライベート状態のハッシュ、トランザクションID、およびコレクション設定の履歴を含むディレクトリで構成されます。これらのファイルに関するメタデータを含むファイルも含まれます。詳細については、 contents of a snapshot を参照してください。
- スナップショットを新しい組織で使用する場合、スナップショットをその組織に送信する。これはアウトオブバンドで完了する必要があります。スナップショットファイルは圧縮されていないため、ピア管理者は送信前にこれらのファイルを圧縮したい場合が多いでしょう。一般的なシナリオでは、管理者は既存の組織の1つからスナップショットを受け取りますが、受け取ったスナップショットの検証のため、複数の組織からスナップショットメタデータを受け取ります。
スナップショットを使用してチャネルに参加する組織は、次に以下の手順を実行します:
- スナップショットを評価する。スナップショットを使用してチャネルに参加しようとするピア組織の管理者は、スナップショットファイルのハッシュを独自に計算し、メタデータファイルに格納されているハッシュと一致させる必要があります。さらに、ネットワークで確立された信頼モデルに応じて、複数の組織のメタデータファイルを照合する必要がある場合があります。一部のシナリオでは、管理者は他の組織の管理者にメタデータファイルに署名してもらうことを希望する場合があります。
- スナップショットを使用してピアをチャネルに加入させる。ピアがスナップショットを使用してチャネルへの加入を完了すると、所属するコレクションに応じてプライベートデータを取得し始めます。また、利用可能なスナップショットの高さよりも大きいブロックについて、通常通りオーダーリングサービスからブロックのコミットを開始します。
- ピアがチャネルに正常に参加したか確認する。詳細については、 Joining a channel using a snapshot を参照してください。
チャネルに既に参加している組織がスナップショットを使用して新しいピアに参加する場合、他の組織がスナップショットを取得し評価するプロセスを省略する可能性があります。ただし、組織は定期的にすべてのピアのスナップショットを取得し比較することで、台帳の分岐が発生していないことを確認するのがベストプラクティスです。その場合、組織はすぐにスナップショットを取得し、そのスナップショットを使用して新しいピアをチャネルに追加できます。
Using snapshots to verify peer integrity¶
スナップショットを使用して新しいピアをチャネルに参加させる以外にも、ピア間の状態が同一であること(つまり、台帳の分岐が発生していないこと)を確認するためにスナップショットを使用できます。
これは、ピア間で生成されたスナップショット内のファイル _snapshot_additional_metadata.json 内の snapshot_hash が同じであることを確認することで実現できます。
ハッシュが一致しない場合、 ledgerutil compare utility を使用して、任意の2つのスナップショット間で異なるキーを特定し、分岐が発生した可能性のあるタイミングを把握できます。
Taking a snapshot¶
スナップショット関連の全コマンドのリストについては、 peer snapshot commands を確認してください。
スナップショットを取得する前に、現在の台帳の高さを確認するために以下のようなコマンドを実行することが推奨されます:
peer channel getinfo -c <name of channel>
以下のような応答があるはずです:
Blockchain info: {"height":970,"currentBlockHash":"JgK9lcaPUNmFb5Mp1qe1SVMsx3o/22Ct4+n5tejcXCw=","previousBlockHash":"f8lZXoAn3gF86zrFq7L1DzW2aKuabH9Ow6SIE5Y04a4="}
この例では、台帳の高さは 970 です。
スナップショットのリクエストは、以下のようなコマンドを発行することで送信できます:
peer snapshot submitrequest -c <name of channel> -b <ledger height where snapshot will be taken> --peerAddress <address of peer> --tlsRootCertFile <path to root certificate of the TLS CA>
例えば:
peer snapshot submitrequest -c testchannel -b 1000 --peerAddress 127.0.0.1:22509 --tlsRootCertFile tls/cert.pem
台帳の高さを 0 に設定すると、スナップショットが即座に取得されます。これは、組織が自組織のピアによって使用されるスナップショットを生成したい場合で、他の組織とデータを共有する意図がない場合に便利です。複数のピアからスナップショットが評価される場合、これらの「即時」スナップショットを取得しないでください。なぜなら、スナップショットが異なる台帳の高さで取得される可能性が高まるからです。
リクエストが成功した場合、 Snapshot request submitted successfully というメッセージが表示されます。
未処理のスナップショットを一覧表示するには、次のようなコマンドを実行します:
peer snapshot listpending -c testchannel --peerAddress 127.0.0.1:22509 --tlsRootCertFile tls/cert.pem
以下のような応答があるはずです:
Successfully got pending snapshot requests [1000]
特定のブロック高でスナップショットが生成されると、そのブロック高の未処理リクエストはリストから表示されなくなります。スナップショットが正常に作成されたかどうかを確認するには、ピアのログを確認してください。
スナップショットは、 core.yaml の ledger.snapshots.rootDir プロパティに基づいて指定されたディレクトリに書き込まれます。完了したスナップショットは、スナップショットのチャネル名とブロック番号に基づいてサブディレクトリに書き込まれます: {ledger.snapshots.rootDir}/completed/{channelName}/{lastBlockNumberInSnapshot} 。 core.yaml ファイルで ledger.snapshots.rootDir プロパティが指定されていない場合、デフォルト値は {peer.fileSystemPath}/snapshots になります。スナップショットのサイズが大きくなる場合、またはスナップショットを生成した場所で共有する予定の場合、スナップショットディレクトリをピアの fileSystemPath とは異なるボリュームに設定することを検討してください。
スナップショットリクエストを削除する場合、単純に submitrequest を cancelrequest に置き換えて下さい。例えば:
peer snapshot cancelrequest -c testchannel -b 1000 --peerAddress 127.0.0.1:22509 --tlsRootCertFile tls/cert.pem
listpending コマンドを再度実行した場合、スナップショットはそれ以上現れません。
Contents of a snapshot¶
ピアがスナップショットを {ledger.snapshots.rootDir}/completed/{channelName}/{lastBlockNumberInSnapshot} ディレクトリに生成すると、そのピアはそのディレクトリをいかなる目的にも使用しないため、外部ツールを使用してスナップショットを圧縮して転送し、必要なくなった時点で削除しても安全です。
上記で述べたように、作成完了したスナップショットディレクトリには、以下の異なるデータ項目に対応するファイルが含まれています:
- Public state
- チャネル上のすべてのキーの最新の値が含まれます。例えば、パブリックステートには、資産(key)とその現在の所有者(value)が表示されますが、過去の所有者は表示されません。
- Private data hashes
- チャネル上のプライベートデータのハッシュが含まれます。プライベートデータに関するドキュメントで説明したように、プライベートデータの実際のデータはチャネルのパブリックな台帳には保存されませんが、データのハッシュは保存されます。これにより、例えばプライベートデータコレクションに追加された組織が、ハッシュに対してプライベートデータを検証することが可能です。これらのハッシュはスナップショットに含められ、新しい組織が所属するコレクションで受け取ったプライベートデータに対して検証できるようにしています。
- Transactions IDs
- スナップショットの最後のブロックまでの間にチャネルで使用されたトランザクションIDのリストからなります。このトランザクションIDは、別のトランザクションでトランザクションIDが再利用されていないことをピアが確認できるように含まれています。
- Collection config history
- すべてのチェーンコードのコレクション設定の履歴を含んでいます。プライベートデータに関するドキュメントで説明したように、コレクション設定はプライベートデータコレクションの承認および配信ポリシーを導出します。
さらに、スナップショットには、スナップショット内のデータを検証するために役立つ2つのメタデータファイルが含まれています。このスナップショットメタデータファイルは、特定の高さにおけるチャネルのスナップショット間で同じであることが期待されています。
これらのファイルの1つには、 snapshot_signable_metadata.json という名前のJSONレコードが含まれており、以下のフィールドを含みます:
channel_name: チャネルの名前。last_block_number: スナップショットが取得されたブロックの高さ。last_block_hash: スナップショットが取得されたブロックの高さにおけるブロックのハッシュ。previous_block_hash:last_blockの前のブロックのハッシュ。state_db_type: このフィールドの値は、CouchDBまたはSimpleKeyValueDB(LevelDBとも呼ばれる)のいずれかです。snapshot_files_raw_hashesは、上記のファイル群のハッシュを含むJSONレコードです。
このメタデータファイルは、以下の2つのフィールドを含むJSONレコードでもあります:
snapshot_hashは、ファイルsnapshot_signable_metadata.jsonのハッシュ値であり、スナップショットのハッシュ値として扱うことができます。last_block_commit_hashは、スナップショットを生成したノードがブロックコミットハッシュを計算できる場合に含まれます。
ここで説明されているファイルの種類は、スナップショットに含まれる可能性のあるすべてのファイルの集合です。管理者がスナップショットにこれらのファイルの一部(例えば、コレクション設定の履歴)が欠落していることを見つけた場合でも、これはスナップショットが不完全であることを意味するものではありません。チャネルにコレクションが存在しない可能性があります。
Joining a channel using a snapshot¶
ジェネシスブロックを使用してチャネルに参加する際は、 peer channel join --blockpath mychannel.block のようなコマンドが発行されます。スナップショットを使用してピアをチャネルに参加させる場合は、次のようなコマンドを発行します:
peer channel joinbysnapshot --snapshotpath <path to snapshot>
ピアがチャネルに正常に参加したかどうかを確認するには、次のようなコマンドを実行します:
peer channel getinfo -c <name of channel joined by snapshot>
さらに、ピアがチャネルで使用されているチェーンコードをまだインストールしていない場合、インストールし、その後クエリを発行します。データが正常に返却された場合、ピアがスナップショットを使用して正常に接続されたことを示します。その後、チャネルで使用されているすべてのチェーンコードをインストールできます。スナップショットが新しい組織で使用されており、チャネルに new chaincode lifecycle で定義されたチェーンコードの定義が含まれている場合、これらのチェーンコードはピアで実行できるようになる前に、新しい組織はこれらのチェーンコードの定義を承認する必要があります。
Try it out¶
台帳のスナップショット作成プロセスを試したい場合は、まず実行中のチャネルを持つネットワークが必要です。ネットワークがない場合は、 test network をデプロイしてください。これにより、2つの組織(それぞれが単一のピアを持つ)とアプリケーションチャネルを含むネットワークが作成されます。
次に、 Adding an Org to a Channel の手順に従って、ネットワークとアプリケーションチャネルに新しい組織を追加します。 Join Org3 to the Channel のセクションに到達したら、スナップショットを取得するピアを選択し、上記の指示に従ってスナップショットを取得します。その後、ピア上のスナップショットをファイルシステム内の別の場所にコピーします。このステップでスナップショットを取得することで、新しいピアがチャネルに参加する際、その組織が既にチャネルに加入した時点以降のスナップショットを使用して参加することが保証されます。
スナップショットを取得してコピーした後、 peer channel join -b mychannel.block コマンドを発行する代わりに、ファイルシステム上のスナップショットのパスを使用して peer channel joinbysnapshot --snapshotpath <path to snapshot> を指定します。
Troubleshooting¶
スナップショットを使用してチャネルに参加できない理由はいくつかあります:
- スナップショットが指定された場所に存在しない。
joinbysnapshotコマンドで指定した場所にスナップショットが存在するか確認してください。 - データのハッシュが一致しない。これは、スナップショットの作成時に検出されなかったエラーが発生したか、スナップショット内のデータが破損している可能性を示します。