ClickHouse Cloud では、レプリケーションは自動的に管理されます。テーブルは引数を追加せずに作成してください。たとえば、以下の記述では次のような:を、次のように置き換えます:
- ReplicatedSummingMergeTree
- ReplicatedCoalescingMergeTree
- ReplicatedVersionedCollapsingMergeTree
- ReplicatedCollapsingMergeTree
- ReplicatedGraphiteMergeTree
- ReplicatedMergeTree
- ReplicatedReplacingMergeTree
- ReplicatedAggregatingMergeTree
INSERT および ALTER クエリの圧縮データはレプリケートされます (詳細については、ALTER のドキュメントを参照してください) 。
CREATE、DROP、ATTACH、DETACH、RENAME クエリは 1 台のサーバー上で実行され、レプリケートされません。
CREATE TABLEクエリは、クエリを実行したサーバー上に新しいレプリケート可能なテーブルを作成します。このテーブルが他のサーバーにすでに存在している場合は、新しいレプリカが追加されます。DROP TABLEクエリは、クエリを実行したサーバー上にあるレプリカを削除します。RENAMEクエリは、いずれか 1 つのレプリカ上でテーブル名を変更します。つまり、レプリケートテーブルはレプリカごとに異なる名前を持つことができます。
セキュリティ設定を軽視しないでください。ClickHouse は、ZooKeeper セキュリティサブシステムの
digest ACL scheme をサポートしています。SELECT クエリでは使用されません。レプリケーションは SELECT のパフォーマンスに影響しないためで、クエリは非レプリケートテーブルと同じ速度で実行されます。分散レプリケートテーブルに対してクエリを実行する際の ClickHouse の動作は、設定 max_replica_delay_for_distributed_queries と fallback_to_stale_replicas_for_distributed_queries によって制御されます。
各 INSERT クエリごとに、複数のトランザクションを通じて ZooKeeper におよそ 10 個のエントリが追加されます。 (より正確には、これは挿入されるデータブロックごとです。INSERT クエリには 1 つのブロック、または max_insert_block_size = 1048576 行ごとに 1 つのブロックが含まれます。) このため、INSERT のレイテンシは非レプリケートテーブルと比べてわずかに長くなります。ただし、データは 1 秒あたり 1 回を超えない INSERT をバッチで行うという推奨事項に従えば、問題にはなりません。1 つの ZooKeeper クラスターで調整される ClickHouse クラスター全体では、合計で毎秒数百件の INSERT を処理できます。データ挿入のスループット (1 秒あたりの行数) は、非レプリケートデータの場合と同程度に高くなります。
非常に大規模なクラスターでは、分片ごとに異なる ZooKeeper クラスターを使用できます。ただし、私たちの経験では、約 300 台のサーバーを持つ本番クラスターでも、これが必要になったことはありません。
レプリケーションは非同期かつマルチマスターです。INSERT クエリ (および ALTER) は、利用可能な任意のサーバーに送信できます。データはクエリを実行したサーバーに挿入され、その後ほかのサーバーへコピーされます。非同期であるため、直前に挿入されたデータがほかのレプリカに反映されるまでには多少の遅延があります。一部のレプリカが利用できない場合は、それらが利用可能になった時点でデータが書き込まれます。レプリカが利用可能であれば、レイテンシは圧縮済みデータブロックをネットワーク経由で転送するのにかかる時間です。レプリケートテーブルのバックグラウンドタスクを実行するスレッド数は、background_schedule_pool_size 設定で指定できます。
ReplicatedMergeTree エンジンは、レプリケーションの fetches 用に別のスレッドプールを使用します。このプールのサイズは background_fetches_pool_size 設定で制限されており、サーバーの再起動によって調整できます。
デフォルトでは、INSERT クエリは 1 つのレプリカからのデータ書き込み確認だけを待機します。データが 1 つのレプリカにしか正常に書き込まれず、そのレプリカを持つサーバーが失われた場合、保存されたデータも失われます。複数のレプリカからデータ書き込み確認を得るには、insert_quorum オプションを使用します。
各データブロックはアトミックに書き込まれます。INSERT クエリは、最大 max_insert_block_size = 1048576 行までのブロックに分割されます。つまり、INSERT クエリの行数が 1048576 未満であれば、そのクエリはアトミックに実行されます。
データブロックは重複排除されます。同じデータブロック (同じサイズで、同じ行を同じ順序で含むデータブロック) を複数回書き込んでも、そのブロックが書き込まれるのは 1 回だけです。これは、ネットワーク障害時にクライアントアプリケーションがデータが DB に書き込まれたかどうか分からなくても、INSERT クエリをそのまま再実行できるようにするためです。同一データの INSERT がどのレプリカに送信されたかは関係ありません。INSERT は冪等です。重複排除のパラメータは、merge_tree サーバー設定で制御されます。
レプリケーション中にネットワーク経由で転送されるのは、挿入元のデータだけです。その後のデータ変換 (マージ) は、すべてのレプリカで同じ方法で調整・実行されます。これによりネットワーク使用量が最小限に抑えられるため、レプリカが異なる datacenter にある場合でも、レプリケーションは有効に機能します。 (異なる datacenter 間でデータを複製することが、レプリケーションの主な目的である点に注意してください。)
同じデータに対して、レプリカはいくつでも持つことができます。私たちの経験では、比較的信頼性が高く運用しやすい構成として、本番環境では各サーバーで RAID-5 または RAID-6 (場合によっては RAID-10) を使用し、二重レプリケーションを行う方法が考えられます。
システムはレプリカ間のデータ同期状態を監視しており、障害発生後の復旧も可能です。フェイルオーバーは自動で行われる場合 (データの差分が小さい場合) と、半自動で行われる場合があります (データの差分が大きく、設定ミスの可能性がある場合) 。
レプリケートテーブルの作成
ClickHouse Cloud では、レプリケーションは自動的に処理されます。レプリケーション引数は指定せず、
MergeTree を使ってテーブルを作成してください。システムは内部的に MergeTree を SharedMergeTree に書き換え、レプリケーションとデータ分散を処理します。レプリケーションはプラットフォーム側で管理されるため、ReplicatedMergeTree の使用やレプリケーションパラメーターの指定は避けてください。Replicated*MergeTree パラメータ
例:
{} で囲まれた置換を含めることができます。置換される値は、設定ファイルの マクロ セクションから取得されます。
例:
/clickhouse/tables/ は共通のプレフィックスです。これをそのまま使用することを推奨します。
{shard} は分片識別子に展開されます。
table_name は ClickHouse Keeper 内でそのテーブルに対応するノード名です。これをテーブル名と同じにしておくのがよいでしょう。これは明示的に定義します。テーブル名と異なり、RENAME クエリの実行後も変更されないためです。
ヒント: table_name の前にデータベース名を付けることもできます。例: db_name.table_name
組み込み置換 {database} と {table} も使用できます。これらはそれぞれテーブル名とデータベース名に展開されます (これらのマクロが macros セクションで定義されていない場合) 。そのため、ZooKeeper のパスは '/clickhouse/tables/{shard}/{database}/{table}' と指定できます。
これらの組み込み置換を使用する場合は、テーブル名の変更に注意してください。ClickHouse Keeper 内のパスは変更できないため、テーブル名を変更すると、マクロが別のパスに展開され、テーブルは ClickHouse Keeper 内に存在しないパスを参照することになり、読み取り専用モードに入ります。
レプリカ名は、同じテーブルの異なるレプリカを識別するための名前です。例のように、これにはサーバー名を使用できます。この名前は各分片内で一意であれば十分です。
置換を使わずにパラメータを明示的に定義することもできます。これはテストや小規模なクラスターの設定では便利な場合があります。ただし、この場合は分散 DDL クエリ (ON CLUSTER) は使用できません。
大規模なクラスターを扱う場合は、ミスの可能性を減らせるため、置換を使用することを推奨します。
Replicated table engine のデフォルト引数は、サーバー設定ファイルで指定できます。たとえば:
CREATE TABLE クエリを実行します。このクエリは、新しいレプリケートテーブルを作成するか、既存のテーブルに新しいレプリカを追加します。
他のレプリカにすでにデータが存在する状態で新しいレプリカを追加した場合、クエリの実行後、そのデータは他のレプリカから新しいレプリカにコピーされます。つまり、新しいレプリカは他のレプリカと自動的に同期します。
レプリカを削除するには、DROP TABLE を実行します。ただし、削除されるのは 1 つのレプリカだけで、クエリを実行したサーバー上のレプリカのみです。
障害発生後の復旧
INSERT の実行中に ClickHouse Keeper を利用できない場合、または ClickHouse Keeper とのやり取り中にエラーが発生した場合は、例外がスローされます。
ClickHouse Keeper に接続すると、システムはローカルファイルシステム上のデータ集合が想定されるデータ集合と一致しているかどうかを確認します (この情報は ClickHouse Keeper に保存されています) 。軽微な不整合がある場合、システムはレプリカとデータを同期してそれを解消します。
システムが破損した データパーツ (ファイルサイズが正しくないもの) や未認識のパーツ (ファイルシステムに書き込まれているものの、ClickHouse Keeper には記録されていないパーツ) を検出した場合、それらは detached サブディレクトリに移動されます (削除はされません) 。不足しているパーツはレプリカからコピーされます。
ClickHouse は、大量のデータを自動削除するような破壊的操作は行わないことに注意してください。
サーバーの起動時 (または ClickHouse Keeper との新しいセッションを確立したとき) には、すべてのファイルの数とサイズだけを確認します。ファイルサイズが一致していても、途中のどこかでバイトが変更されていた場合は、すぐには検出されず、SELECT クエリでデータを読み取ろうとしたときに初めて検出されます。クエリは、checksum の不一致または compressed block のサイズ不一致に関する例外をスローします。この場合、データパーツ は検証キューに追加され、必要に応じてレプリカからコピーされます。
ローカルのデータ集合が想定されるものと大きく異なる場合は、安全機構がトリガーされます。サーバーはその旨をログに記録し、起動を拒否します。これは、たとえばある分片上のレプリカが、誤って別の分片上のレプリカとして設定されているような設定ミスを示している可能性があるためです。ただし、この機構のしきい値はかなり低く設定されているため、通常の障害復旧中にもこの状況が発生することがあります。この場合、データは半自動的に、つまり “ボタンを押す” ことで復元されます。
復旧を開始するには、ClickHouse Keeper に任意の内容でノード /path_to_table/replica_name/flags/force_restore_data を作成するか、すべてのレプリケートテーブルを復元するコマンドを実行します。
完全なデータ損失後の復旧
- サーバーに ClickHouse をインストールします。分片識別子とレプリカを使用している場合は、それらを含む設定ファイルで置換設定を正しく定義します。
- サーバー間で手動で複製する必要がある非レプリケートテーブルがある場合は、レプリカからそのデータをコピーします (ディレクトリ
/var/lib/clickhouse/data/db_name/table_name/) 。 /var/lib/clickhouse/metadata/にあるテーブル定義をレプリカからコピーします。テーブル定義内で分片またはレプリカ識別子が明示的に定義されている場合は、このレプリカに対応するよう修正します。 (別の方法として、サーバーを起動し、/var/lib/clickhouse/metadata/内の .sql ファイルに含まれているはずのATTACH TABLEクエリをすべて実行してもかまいません。)- 復旧を開始するには、ClickHouse Keeper ノード
/path_to_table/replica_name/flags/force_restore_dataを任意の内容で作成するか、すべてのレプリケートテーブルを復元するために次のコマンドを実行します:sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data
/path_to_table/replica_name) 、その後 “Creating replicated tables” に記載されているとおりにレプリカを再作成することもできます。
復旧中はネットワーク帯域幅に制限がありません。一度に多数のレプリカを復元する場合は、この点に注意してください。
MergeTree から ReplicatedMergeTree への変換
MergeTree は、ReplicatedMergeTree と同様に、MergeTree family に属するすべてのテーブルエンジンを指します。
手動でレプリケーションしていた MergeTree テーブルがある場合、それをレプリケートテーブルに変換できます。これは、すでに MergeTree テーブルに大量のデータを蓄積していて、あとからレプリケーションを有効にしたい場合に必要になることがあります。
ATTACH TABLE … AS REPLICATED ステートメントを使うと、デタッチされた MergeTree テーブルを ReplicatedMergeTree としてアタッチできます。
テーブルのデータディレクトリ (Atomic データベースの場合は /store/xxx/xxxyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/) で convert_to_replicated フラグが設定されていれば、MergeTree テーブルはサーバーの再起動時に自動的に変換されます。
空の convert_to_replicated ファイルを作成すると、次回のサーバー再起動時にそのテーブルはレプリケートテーブルとして読み込まれます。
次のクエリを使うと、テーブルのデータパスを取得できます。テーブルに複数のデータパスがある場合は、最初のものを使用する必要があります。
default_replica_path と default_replica_name の設定値を使用して作成されることに注意してください。
他のレプリカ上に変換後のテーブルを作成するには、ReplicatedMergeTree エンジンの第1引数でそのパスを明示的に指定する必要があります。以下のクエリを使用して、そのパスを取得できます。
ReplicatedMergeTree テーブルを作成します。
古いテーブルのデータを、新しいテーブルのデータディレクトリ (/var/lib/clickhouse/data/db_name/table_name/) 内の detached サブディレクトリに移動します。
その後、いずれかのレプリカで ALTER TABLE ATTACH PARTITION を実行し、これらのデータパーツをワーキングセットに追加します。
ReplicatedMergeTree から MergeTree への変換
ReplicatedMergeTree テーブルを MergeTree としてアタッチするには、ATTACH TABLE … AS NOT REPLICATED ステートメントを使用します。
これを行う別の方法として、サーバーの再起動を伴う手順があります。別の名前で MergeTree テーブルを作成します。ReplicatedMergeTree テーブルのデータが格納されているディレクトリから、新しいテーブルのデータディレクトリにすべてのデータを移動します。次に、ReplicatedMergeTree テーブルを削除して、サーバーを再起動します。
サーバーを起動せずに ReplicatedMergeTree テーブルを削除したい場合は、次のようにします。
- メタデータ ディレクトリ (
/var/lib/clickhouse/metadata/) 内の対応する.sqlファイルを削除します。 - ClickHouse Keeper 内の対応するパス (
/path_to_table/replica_name) を削除します。
MergeTree テーブルを作成して、そのディレクトリにデータを移動し、その後サーバーを再起動できます。