リードリペア
リードリペアとは、読み取りリクエスト中にデータレプリカを修復するプロセスです。特定の読み取り整合性レベルでの読み取りリクエストに関与するすべてのレプリカが整合している場合、データはクライアントに返され、リードリペアは必要ありません。しかし、特定の整合性レベルでの読み取りリクエストに関与するレプリカが整合していない場合、読み取りリクエストに関与するレプリカを整合させるためにリードリペアが実行されます。最新のデータがクライアントに返されます。リードリペアはフォアグラウンドで実行され、リードリペアが完了して最新のデータが構築されるまで応答がクライアントに返されないため、ブロッキングします。
単調クォーラム読み取りの期待
Cassandra は、"単調クォーラム読み取り" の期待を確実にするためにブロッキングリードリペアを使用します。つまり、2 回連続したクォーラム読み取りでは、2 回目が 1 回目よりも古いものを取得することはありません。これは、失敗したクォーラム書き込みが、最新の値の書き込みをレプリカの少数派に対してのみ行った場合でも同様です。"クォーラム" とは、レプリカ間のノードの過半数を意味します。
単調読み取りのテーブルレベル構成
Cassandra 4.0 では、単調読み取りのテーブルレベル構成がサポートされました (CASSANDRA-14635)。read_repair
テーブルオプションがテーブルスキーマに追加され、オプションとして blocking
(デフォルト) と none
があります。
read_repair
オプションは、さまざまなパフォーマンスと整合性動作を調整できるように、リードリペアの動作を構成します。2 つの整合性プロパティがリードリペアの動作によって影響を受けます。
-
単調クォーラム読み取り:
BLOCKING
によって提供されます。単調クォーラム読み取りは、状況によっては読み取りが時間をさかのぼって表示されるのを防ぎます。単調クォーラム読み取りが提供されておらず、書き込みがレプリカのクォーラムに到達できなかった場合、1 回の読み取りで表示され、その後の読み取りで消える可能性があります。 -
書き込みの原子性:
NONE
によって提供されます。書き込みの原子性は、部分的に適用された書き込みを読み取りが返すのを防ぎます。Cassandra はパーティションレベルの書き込みの原子性を提供しようとしますが、SELECT
ステートメントでカバーされるデータのみがリードリペアによって修復されるため、データが書き込まれたよりも細かいレベルで読み取られると、リードリペアは書き込みの原子性を損なう可能性があります。たとえば、複数の行をバッチでクラスター化されたパーティションに書き込み、SELECT
ステートメントでクラスタリング列を指定して単一の行を選択すると、リードリペアは書き込みの原子性を損なう可能性があります。
利用可能なリードリペア設定は次のとおりです。
リードリペアの例
例を挙げてリードリペアを説明するために、クライアントが図 1 に示すように、読み取り整合性レベル TWO
で 5 ノードクラスターに読み取りリクエストを送信すると仮定します。読み取り整合性レベルは、読み取りリクエストが成功したと見なされる前に、応答を返す必要のあるレプリカノードの数を決定します。

図 1. クライアントが 5 ノードクラスターに読み取りリクエストを送信します。
図 2 に示すように、3 つのノードが要求されたデータのレプリカをホストしています。読み取り整合性レベルが TWO
の場合、読み取りリクエストが成功したと見なされるには、2 つのレプリカノードが応答を返す必要があります。クライアントがリクエストを送信するノードが、リクエストされたデータのレプリカをホストしている場合、別のレプリカノードに読み取りリクエストを送信する必要があるのは 1 つだけです。ただし、受信ノードが要求されたデータのレプリカをホストしていない場合、そのノードはコーディネーターノードになり、レプリカをホストするノードに読み取りリクエストを転送します。図 2 に示すように、ダイレクト読み取りリクエストは、(動的スニッチによって決定される) 最速のノードに転送されます。ダイレクト読み取りリクエストはフル読み取りであり、要求されたデータを返します。

図 2. 最速のレプリカノードに送信されたダイレクト読み取りリクエスト。
次に、コーディネーターノードは、整合性レベルである TWO
を満たすために必要な数の追加リクエストを送信します。コーディネーターノードは、合計 2 つのリクエストのために、もう 1 つの読み取りリクエストを送信する必要があります。最初のダイレクト読み取りリクエストに追加されたすべての読み取りリクエストは、ダイジェスト読み取りリクエストです。ダイジェスト読み取りリクエストはフル読み取りではなく、データのハッシュ値のみを返します。ネットワークデータトラフィックを減らすために、ハッシュ値のみが返されます。議論されている例では、コーディネーターノードは、図 3 に示すように、レプリカをホストしているノードに 1 つのダイジェスト読み取りリクエストを送信します。

図 3. コーディネーターがダイジェスト読み取りリクエストを送信します。
コーディネーターノードは、あるノードからデータの完全なコピーと、別のノードからデータのハッシュ値を受信しました。返されたデータを比較するには、データの完全なコピーのハッシュ値が計算されます。2 つのハッシュ値が比較されます。ハッシュ値が同じ場合、リードリペアは必要なく、要求されたデータの完全なコピーがクライアントに返されます。コーディネーターノードは、読み取り整合性レベルが例では TWO
であるため、合計 2 つのレプリカ読み取りリクエストのみを実行しました。整合性レベルが THREE
などのように高い場合、3 つのレプリカノードが読み取りリクエストに応答する必要があり、すべてのダイジェストまたはハッシュ値がデータの完全なコピーのハッシュ値と一致した場合にのみ、読み取りリクエストが成功したと見なされ、データがクライアントに返されます。
しかし、ダイジェスト読み取りリクエストからのハッシュ値が、最初のレプリカノードからのフル読み取りリクエストからのデータのハッシュ値と同じでない場合、レプリカに不整合が存在することを示します。不整合を修正するために、リードリペアが実行されます。
たとえば、ダイジェストリクエストが、ダイレクトフルリードリクエストからのデータのハッシュ値と同じではないハッシュ値を返すと仮定します。コーディネーターノードが、以前にダイジェスト読み取りリクエストを送信したレプリカノードにダイレクト (フル) 読み取りリクエストを送信する必要があり、図 4 に示すように、レプリカを整合させる必要があります。

図 4. コーディネーターが、ダイジェスト読み取りリクエストを送信したレプリカノードにダイレクト読み取りリクエストを送信します。
コーディネーターは、2 番目のレプリカノードからデータを受信した後、2 つのレプリカノードからデータを取得しました。読み取り整合性レベルが例では TWO
であるため、必要なレプリカは 2 つだけです。2 つのレプリカからのデータが比較され、タイムスタンプに基づいて最新のレプリカが選択されます。レプリカの 1 つが一部の列のデータのみを持っている場合、最新のデータのコピーを構築するためにデータをマージする必要がある場合があります。例では、最初のダイレクト読み取りリクエストからのデータが古いことが判明し、2 番目のフル読み取りリクエストからのデータが最新の読み取りであると判明した場合、レプリカ 2 でリードリペアを実行する必要があります。2 つのレプリカをマージすることによって新しい最新のデータが構築された場合、関連する両方のレプリカでリードリペアが必要になります。たとえば、図 5 に示すように、レプリカ 2 でリードリペアが実行されます。

図 5. コーディネーターがリードリペアを実行します。
図 6 に示すように、最新のデータがクライアントに返されます。3 つのレプリカのうち、レプリカ 1 は読み取りすら実行されないため、修復されません。レプリカ 2 は修復されます。レプリカ 3 は最新であり、クライアントに返されます。

図 6. 最新のデータがクライアントに返されます。
読み取り整合性レベルとリードリペア
リードリペアを実行する必要があるかどうかを判断する上で最も重要なのは、読み取り整合性です。表 1 で説明したように、すべての整合性レベルでリードリペアが必要になるわけではありません。
表 1. 読み取り整合性レベルに基づくリードリペア
読み取り整合性レベル | 説明 |
---|---|
ONE |
最初のダイレクトリード要求からのデータが整合性レベル ONE を満たしているため、リードリペアは実行されません。データの不一致を見つけるためのダイジェストリード要求は関与しません。 |
TWO |
ダイレクトリード要求とダイジェストリード要求によってデータ内の不整合が検出された場合、リードリペアが実行されます。 |
THREE |
ダイレクトリード要求とダイジェストリード要求によってデータ内の不整合が検出された場合、リードリペアが実行されます。 |
LOCAL_ONE |
最も近いレプリカからのダイレクトリード要求からのデータが整合性レベル LOCAL_ONE を満たしているため、リードリペアは実行されません。データの不一致を見つけるためのダイジェストリード要求は関与しません。 |
LOCAL_QUORUM |
ダイレクトリード要求とダイジェストリード要求によってデータ内の不整合が検出された場合、リードリペアが実行されます。 |
QUORUM |
ダイレクトリード要求とダイジェストリード要求によってデータ内の不整合が検出された場合、リードリペアが実行されます。 |
リードリペアが実行される場合、それは最新の状態ではなく、リード要求に関与しているレプリカでのみ行われます。リード要求に関与するレプリカの数は、リード整合性レベルに基づきます。例では、2つです。
Cassandra 4.0 におけるリードリペアのブロッキング動作の改善
Cassandra 4.0 では、リードリペアのブロッキング動作に2つの改善が加えられています (CASSANDRA-10726)。
-
フルデータリード要求の投機的再試行。 Cassandra 4.0 では、最初のフルリード要求またはリードリペア中のフルデータリード要求のいずれにおいても、フルデータ応答を受信しなかった場合、レプリカへのリード要求(ダイジェストではなくフル)の送信に投機的再試行を利用します。投機的再試行を使用すると、整合性レベルを満たすために Cassandra がメッセージを送信した最初のレプリカセットからの応答が受信されない可能性がある場合、接触していないレプリカに追加のリード要求を投機的に送信します。 Cassandra 4.0 は、応答がない可能性がある場合、リードリペアデータリード/ライトサイクルに関与していないマイノリティノードへの修復ミューテーションも投機的に送信します。これは、未承認のすべてのミューテーションの結合された内容を含みます。 Cassandra は、送信された修復ミューテーションと同じ数の ack を受け取る限り、最初に送信されたミューテーションからの ack の代わりにそれらからの ack を受け入れます。
-
整合性レベルを満たすためのフルデータ応答のみでブロックします。 Cassandra 4.0 は、ダイジェストの不一致を解決するために必要なもののみをブロックし、投機的再試行であろうとリードリペアの機会であろうと、整合性レベルを満たすのに十分なフルデータ応答を待機します。例として、Cassandra が時間内にすべての人からフルデータ要求を受信できない可能性がある場合、最初のフルデータリードで接触しなかった追加のレプリカに追加のリクエストを送信します。時間内に応答したノードのコレクションがデータに同意した場合、リードリペアを開始した不一致のレプリカからの応答は考慮されず、モノトニックなクォーラムリードの期待を維持しながら、クライアントへの応答には含まれません。
リードリペアの診断イベント
Cassandra 4.0 では、リードリペアの診断イベント (CASSANDRA-14668) が追加されました。これを使用して、次のような情報を公開できます。
-
連絡されたエンドポイント
-
エンドポイントごとのダイジェスト応答
-
影響を受けるパーティションキー
-
投機的なリード/ライト
-
オーバーサイズの更新
バックグラウンドリードリペア
cassandra.yaml
の read_repair_chance
および dclocal_read_repair_chance
設定を使用して構成されていたバックグラウンドリードリペアは、Cassandra 4.0 で削除されました (CASSANDRA-13910)。
リードリペアは、フルリペアや障害が発生し続けるノードの交換などの他の種類のリペアの代替ではありません。リードリペアが実行された後でも、整合性レベルがすべてのレプリカからの応答を必要とするもの以外の場合、返されたデータは最新のデータではない可能性があります。