パーティションの拒否リスト登録
アクセスパターンとデータモデリングにより、Cassandraクラスタで不安定性を引き起こす可能性のある「ホット」な特定のパーティションが存在する場合があります。これは、データモデルに単一パーティションに対する多数の更新または挿入操作が含まれており、パーティションが時間の経過とともに非常に大きくなり、読み取りと保守に非常にコストがかかる場合によく発生します。
Cassandraは、これらの問題のあるパーティションを「拒否リスト登録」することをサポートしています。これにより、クライアントがポイントリード(パーティションキーが指定された`SELECT`ステートメント)またはレンジリード(`SELECT *`など、データの範囲を取得するもの)を発行したときに、ブロックされたパーティションキーと交差する場合、クエリは`InvalidQueryException`で直ちに拒否されます。
パーティションキーを拒否リスト登録する方法
`system_distributed.denylisted_partitions`テーブルを使用して、パーティションを拒否リスト登録できます。 このデータを操作および変更するには、いくつかの方法があります。 まず、CQLを介して直接、以下の詳細を含むレコードを挿入します。
-
キースペース名(ks_name)
-
テーブル名(table_name)
-
パーティションキー(partition_key)
パーティションキーの形式は、`nodetool getendpoints`で必要な形式と同じである必要があります。
プライマリキー`Id`のさまざまなデータ型について、キースペース`ks`とテーブル`table1`のパーティションキーを拒否リスト登録する例を以下に示します。
-
Idが単純な型の場合 - `INSERT INTO system_distributed.denylisted_partitions (ks_name, table_name, partition_key) VALUES ('ks','table1','1');`
-
IdがBLOBの場合 - `INSERT INTO system_distributed.denylisted_partitions (ks_name, table_name, partition_key) VALUES ('ks','table1','12345f');`
-
Idにコロンが含まれている場合 - `INSERT INTO system_distributed.denylisted_partitions (ks_name, table_name, partition_key) VALUES ('ks','table1','1\:2');`
複合カラムパーティションキー(Key1、Key2)の場合
-
INSERT INTO system_distributed.denylisted_partitions (ks_name, table_name, partition_key) VALUES ('ks', 'table1', 'k11:k21')
特別な考慮事項
拒否リストには、キャッシュ(下記参照)とCQLデータをレプリカセットのできるだけ近くに保持するという特性があります。そのため、クラスタ内の異なるノードが異なるキーを拒否または許可することはありません。これを最適に実現するために、拒否リストの変更(追加または削除)のワークフローは、常に次のとおりである必要があります。
JMXパス(単一の変更に推奨)
-
目的のキーを使用して`denylistKey()`のJMXフックを呼び出します。
-
`isKeyDenylisted()`でキャッシュがリロードされたことを再確認します。
-
認識されないキースペース/テーブルの組み合わせ、制限、または整合性レベルに関する警告を確認します。ノードがダウンしていて、拒否リストのCLに達していないというメッセージが表示された場合は、ダウンしたノードを回復してから、各ノードで`loadPartitionDenylist()`を使用してキャッシュの再ロードをトリガーします。
CQLパス(一括変更に推奨)
-
CQLを介して拒否リスト登録されたパーティションリストを変更します。
-
JMX `loadPartitionDenylist()`(下記参照)を介して各ノードで拒否リストキャッシュの再ロードをトリガーします。
-
拒否リストの更新に使用できないという警告を確認します。ノードがダウンしている場合は、回復してから2に進みます。
既知の利用できないレンジスライスに関する状態により、起動時にアラートストームが発生する可能性があるため、`cassandra.yaml` - `denylist_consistency_level`で構成された整合性レベルを達成できない限り、拒否リストキャッシュはノードの起動時にロードされません。ただし、`loadPartitionDenylist`へのJMX呼び出しは、使用可能なノードの数に関係なくキャッシュをロードします。これにより、劣化クラスタ状態中の拒否リスト登録または拒否リスト登録解除の制御は、オペレーターの手に委ねられます。
拒否リスト登録されたパーティションキャッシュ
Cassandraは内部的に、`system_distributed.denylisted_partitions`からロードされた拒否リスト登録されたパーティションのオンヒープキャッシュを保持します。テーブルの値は、`conf/cassandra.yaml`ファイルで指定された`denylist_refresh`ごとに自動的に再入力されます。デフォルトは`600秒`、つまり10分です。無効なレコード(不明なキースペース、テーブル、またはキー)は無視され、ロード時にキャッシュされません。
キャッシュは次の方法で更新できます。
-
Cassandraノードの起動時
-
自動オンヒープキャッシュ更新メカニズムを介して。注:これは、`denylist_refresh`時間が経過した後、クエリで非同期に発生します。
-
JMXコマンド`loadPartitionDenylist`を介して、`org.apache.cassandra.service.StorageProxyMBean`呼び出しポイントで。
キャッシュサイズは、次の2つの構成プロパティによって制限されます。
-
denylist_max_keys_per_table
-
denylist_max_keys_total
キャッシュのロード時に、テーブルが`denylist_max_keys_per_table`(デフォルトは1000)で許可されている値を超えると、警告がログに出力され、残りのキーはキャッシュされません。同様に、許可されている合計サイズを超えた場合、後続のks_name + table_nameの組み合わせ(クラスタリング/辞書式順序)もスキップされ、警告がサーバーログに記録されます。
1)変更、2)キャッシュのリロードという必要なワークフローを考えると、自動リロードプロパティは不要に思えるかもしれません。これは、オペレーターが誤ってキーを拒否リスト登録(または拒否リスト登録解除)し、キャッシュのリロードを忘れた場合に、その意図が次のキャッシュリロードでキャプチャされるようにするために存在します。 |
JMXインターフェース
コマンド | 効果 |
---|---|
loadPartitionDenylist() |
CQLテーブルからキャッシュされた拒否リストをリロードします |
getPartitionDenylistLoadAttempts() |
キャッシュリロード試行回数を取得します |
getPartitionDenylistLoadSuccesses() |
キャッシュリロード成功回数を取得します |
setEnablePartitionDenylist(boolean enabled) |
パーティション拒否リスト登録機能を有効または無効にします |
setEnableDenylistWrites(boolean enabled) |
書き込み拒否リスト登録機能を有効または無効にします |
setEnableDenylistReads(boolean enabled) |
読み取り拒否リスト登録機能を有効または無効にします |
setEnableDenylistRangeReads(boolean enabled) |
範囲読み取り拒否リスト登録機能を有効または無効にします |
denylistKey(String keyspace, String table, String partitionKeyAsString) |
特定のキースペース、テーブル、およびパーティションキーの組み合わせを拒否リストに追加します |
removeDenylistKey(String keyspace, String cf, String partitionKeyAsString) |
拒否リストから特定のキースペース、テーブル、およびパーティションキーの組み合わせを削除します |
setDenylistMaxKeysPerTable(int value) |
拒否リスト内のテーブルあたりの許可されるキーの数を制限します |
setDenylistMaxKeysTotal(int value) |
システム内で許可される拒否リスト登録キーの総数を制限します |
isKeyDenylisted(String keyspace, String table, String partitionKeyAsString) |
keyspace.tableに入力パーティションキーが拒否されているかどうかを示します |