手動リペア: アンチエントロピー・リペア

手動リペアの仕組みについて説明します。

すべてのCassandraクラスターにとってアンチエントロピー・ノードのリペアは、重要です。頻繁にデータを削除することやダウンしたノードは、データの不整合を引き起こす一般的な原因です。日常的な保守を実行する場合や、nodetool repairコマンドを実行してクラスターを修正する必要がある場合に、アンチエントロピー・リペアを使用します。

アンチエントロピー・リペアの仕組み

Cassandraでは、DynamoやRiakと同様に、Merkleツリーを使用してアンチエントロピー・リペアを実現します。アンチエントロピーは、すべてのレプリカのデータを比較し、各レプリカを新しいバージョンに更新するプロセスです。Cassandraは、次の2つのフェーズを処理します。
  1. 各レプリカのMerkleツリーを構築する
  2. Merkleツリーを比較して、不整合を検出する

nodetool repairコマンドは、指定されたノード上で、またはノードが指定されていない場合はすべてのノード上で実行できます。リペアを開始するノードは、この操作のコーディネーター・ノードになります。Merkleツリーを構築するため、コーディネーター・ノードはデータの一致範囲にあるピア・ノードを決定します。メジャー・コンパクションまたは検証コンパクションは、ピア・ノード上でトリガーされます。検証コンパクションは、格納されたカラム・ファミリー内の各行のハッシュの読み取りと生成を行い、Merkleツリーに結果を追加して、ツリーを開始ノードに返します。一般的に、ハッシュはデータ自体より少ないため、Merkleツリーはデータのハッシュを使用します。このプロセスの詳細については、「Cassandraでのリペア」を参照してください。

Merkleツリーは、そのリーフが個々のキー値のハッシュであるバイナリー・ハッシュ・ツリーです。Cassandraの場合、リーフが行の値のハッシュを保持します。ツリー内でより上位のノードは、それぞれの子のハッシュになります。Merkleツリー内ではより上位ノードが、ツリーのさらに下位のデータを表すため、データ・セット全体のダウンロードにノードを必要とせずに、ツリーの各ブランチを個別にチェックできます。Merkleツリーの構造の場合、Cassandraが採用するアンチエントロピー・リペアによって、ツリーの深さが15(リーフ・ノード数は、2^15=32K)のコンパクション・ツリー・バージョンを使用できます。たとえば、100万個のパーティションを含むノードに破損したパーティションが1つある場合は、約30個のパーティションがストリームされます。これは、ツリーの各リーフに相当する数です。サイズの小さいMerkleツリーを構築した場合の結果として、ツリーを格納するためのメモリ使用量が削減され、比較プロセス中に別のノードにMerkleツリーを転送する必要があるデータの量が最小化されます。

開始ノードが参加しているピア・ノードからMerkleツリーを受け取った後、開始ノードは各ツリーをその他すべてのツリーと比較します。不整合が見つかった場合、不整合ノードは整合性のない範囲のデータとSSTableに書き込まれた新しいデータを交換します。比較は、Merkleツリーの最上位のノードから開始されます。不整合が見つからなかった場合、プロセスは左側の子ノードを処理して比較してから右側の子ノードを処理します。ノードに不整合が見つかった場合、そのノードに関連する範囲には整合性のないデータが存在します。Merkleツリー・ノードの下にあるリーフに対応するすべてのデータは、新しいデータに置き換えられます。

Merkleツリーの構築は、膨大なリソースを必要とし、ディスクI/Oに対する負荷やメモリの消費を伴います。以下に示すいくつかのオプションを使用すると、クラスターのパフォーマンスへの影響を軽減させることができます。

フル・リペアとインクリメンタル・リペア

上記のプロセスは、ノードのデータのフル・リペアを行う場合を示したものです。このノードのすべてのSSTableが比較され、必要に応じてリペアされます。Cassandra 2.1以降では、インクリメンタル・リペアも利用できます。インクリメンタル・リペア、すでにリペア済みのデータを維持し、リペアされていない(未リペアの)SSTableのMerkleツリーのみを計算します。SSTableのリペア・ステータスを追跡し、リペア済みのデータと未リペアのデータを識別する新しいメタデータが採用されました。

リペアが頻繁に実行される場合、Merkleツリーのサイズを縮小すると、インクリメンタル・リペア・プロセスのパフォーマンスが向上します。インクリメンタル・リペアは、フル・リペアの機能と同様に、開始ノードを使用して同じリペアされていないデータを持つピア・ノードからMerkleツリーを要求し、Merkleツリーを比較して不整合を検出します。データの不整合が解消され、新しいSSTableが構築されると、開始ノードはアンチコンパクション・コマンドを発行します。アンチコンパクションは、SSTable全体がリペア済み範囲内にある場合を除き、リペア済みの範囲と未リペアの範囲を別々のSSTableに分離するプロセスです。 後者の場合、SSTableメタデータはそのリペア済みのステータスを反映して更新されます。

アンチコンパクションは、データに割り当てられているコンパクション・ストラテジによって処理が異なります。
  • サイズ階層化コンパクションでは、リペア済みのデータと未リペアのデータを別々のコンパクション用プールに分離します。メジャー・コンパクションでは、データの各プールに1つずつ、合わせて2つのSSTableを生成します。
  • レベル化コンパクションでは、未リペアのデータでサイズ階層化コンパクションを実行します。リペアが完了すると、Casandraは未リペアのSSTableセットをL0に移動します。
  • インクリメンタル・リペアには、日付階層化コンパクションを使用しないでください。

Cassandra 2.1以前のバージョンでは、フル・リペアがデフォルトです。Cassandra 2.2以降のバージョンでは、インクリメンタル・リペアがデフォルトです。Cassandra 2.2以降のバージョンで、フル・リペアを実行する場合は、SSTableはリペア済みおよびアンチコンパクション済みとしてマークされます。

パラレルとシーケンシャル

シーケンシャル・リペアは、1つのノードずつ順番に実行されます。パラレル・リペアでは、同じレプリカ・データを持つすべてのノードを同時にリペアします。

シーケンシャル・リペアは、各レプリカのスナップショットを取得します。スナップショットは、既存のSSTableに対するハードリンクです。スナップショットは不変であり、ディスク領域をほとんど必要としません。スナップショットは、リペアが完了するまで利用でき、リペアの完了後に削除されます。コーディネーター・ノードは、各レプリカのMerkleツリーを1つずつ順番に構築し、最後に、スナップショットから各レプリカを1つずつリペアします。たとえば、RF=3で、A、B、およびCが3つのレプリカを表している場合、このコマンドは、各レプリカのスナップショットをただちに取得した後、各レプリカをスナップショット(A<->B、A<->C、B<->C)から順番にリペアしていきます。

パラレル・リペアでは、ノードA、B、およびCをすべてまとめてリペアします。このタイプのリペアを実行中、動的スニッチは、リペア中ではないスナップショットのレプリカを使用してアプリケーションのパフォーマンスを維持できます。

スナップショットは、既存のSSTableに対するハードリンクです。スナップショットは不変であり、ディスク領域をほとんど必要としません。リペアでは、Merkleツリーの構築時に検証コンパクションが行われるため、ディスクI/Oが集中的に発生します。任意のレプリカ・セットに対して、検証コンパクションが行われるレプリカは一度に1つだけです。

Cassandra 2.1以前のバージョンでは、シーケンシャル・リペアがデフォルトです。Cassandra 2.2以降のバージョンでは、パラレル・リペアがデフォルトです。
注: Cassandra 2.1では、シーケンシャルとインクリメンタルを併用することはできません。

パーティショナー範囲(-pr

Cassandraクラスターで、特定の範囲のデータが複数のノードに格納されます。各ノードでnodetool repairの実行を検討する場合、キースペースで使用されたレプリケーション係数に基づいて同じ範囲のデータが複数回リペアされます。パーティショナー範囲オプションは、リペア操作を不必要に繰り返すことなく、特定の範囲のデータが1回のみリペアされます。この場合でも、各レプリカのMerkleツリーを構築する必要がありますが、ネットワーク・リソースへの負担は減ります。
注: このオプションを使用する場合は、すべてのデータがリペア対象であるクラスター内のすべてのノードに対してnodetool repair -prを実行してください。これを行わないと、一部の範囲のデータがリペアされません。
パーティショナー範囲オプションは、日常的な保守で使用することを推奨します。ただし、ダウンしているノードでこのツールを使用する場合は、このオプションを使用しないでください。

ローカル(-local, --in-local-dc)、データ・センター(dc, --in-dc)、およびクラスター全体

データ・センター全体とローカル・データ・センター内でnodetool repairを使用する場合は、注意が必要ないくつかの検討事項があります。ノードでリペアを実行し、その後、-localまたは--in-local-dcを使用すると、nodetool repair を実行しているノードと同じセンター内のノードのみがリペアされます。それ以外の場合は、同じデータ・センターかどうかを問わず、レプリカ内のすべてのノードがリペアされます。データ・センター間のネットワーク・トラフィックは、膨大な数に増え、クラスターの問題を引き起こす可能性があります。-dcまたは--in-dcオプションを使用する場合、リペアを実行する対象となる特定のデータ・センターを指定できます。この場合、他のデータ・センターのノードがレプリカを保持でき、リペアされますが、リペアはデータ・センター内のノードでのみ開始されます。このオプションを使用すると、ローカル・オプションより多くのノードをリペアできるうえに、ネットワーク・トラフィックを減らすことができます。

-prオプションは、レプリカが膨大な数に増えて処理が煩雑になる可能性があるため、複数のデータ・センター間で使用する場合に特に重要です。DC1とDC2という2つのデータ・センターをリペアし、それぞれのレプリケーション係数が3である場合は、6つのノードのリペア対象の各範囲にMerkleテーブルを構築する必要があります。データ・センターを追加すると、この数は直線的に増加します。
注: -localオプションは、データ・センターのノードにすべての範囲のすべてのデータが含まれる場合を除き、-prとともに使用することはできません。
-local オプションは、インクリメンタルではなく、フル・リペアの場合にのみ実行してください。

Cassandra 2.2以降のバージョンには、並行してデータ・センターをリペアする-dcparまたは--dc-parallelオプションが含まれています。複数データ・センターの場合、並列実行が推奨されます。

エンドポイント範囲リペアとサブ範囲リペア(-st, --start-token, -et --end-token

サブ範囲オプションを使用している場合を除き、リペア操作は、すべてのパーティション範囲またはエンドポイント範囲で実行され、ノードに格納されます。サブ範囲リペアでは、一部のパーティション範囲のみがリペアされるように、開始トークンと終了トークンを指定します。生成されたトークン範囲を使用する必要があるため、一般的に、サブ範囲リペアは推奨されません。ただし、既知のパーティションにエラーが発生した場合は、そのパーティション範囲をリペア対象に指定できます。繰り返し範囲のリペアを送信することでリソースを拘束する可能性がある、過剰ストリーミングと呼ばれる問題は、サブ範囲リペア・オプションによって軽減される場合があります。

サブ範囲リペアは、単なるnodetool repairコマンドより多くの範囲を対象にします。32Kのパーティションを含むスプリットを取得する、Javaのdescribe_splits呼び出しを範囲全体にシーケンシャルまたは並列に繰り返すことで、過剰ストリーミングの動作を排除できます。スプリットのトークンが生成されると、これらのトークンはnodetool repair -st <start_token> -et <end_token>に渡されます。-localオプションを使用して、ローカルのデータ・センター内でのみリペアして、データ・センター間の転送を減らすことができます。