分離が有効なケース分離は、継続的インジェストを伴う大規模なデプロイメントを対象としています。保存データが月あたりおよそ100 TBを下回る規模であれば、通常は単一のread-writeサービスで両方のワークロードを処理でき、2つ目のサービスはおそらく不要です。月あたりのcompressedボリュームを見積もるには、sizing modelを利用してください。
読み取りと書き込みを分離する理由
- 書き込みが読み取りの性能を落とさなくなる。 継続的な OpenTelemetry インジェスト (insert そのものと、それに続くバックグラウンドマージ) は、ダッシュボードや検索のクエリと CPU およびメモリを奪い合います。インジェスト実行中は読み取りレイテンシが目に見えて悪化し、停止すると回復します。
- 読み取りが書き込みを妨げなくなる。 この競合は双方向に発生します。重いアドホッククエリや高コストなダッシュボードの描画がサービスのメモリを使い切り、insert が遅くなるどころか完全に失敗することもあります。
- 読み取り専用コンピュートをクエリに専念させられる。 読み取り専用サービスは、システムテーブル以外でバックグラウンドマージを実行しません。また、マージによって起動状態が維持されうる読み書きサービスと異なり、遅延なくアイドル状態に入ります。
- それぞれを個別にサイジングできる。 sizing model は ingest compute と query compute を別々に見積もり、warehouse では両者をそれぞれ独立したサービスとしてプロビジョニングできます。モデルのベースラインである 1 QPS を超えると query compute が支配的になり、5 QPS の計算例ではインジェストに 58 vCPU、クエリに 290 vCPU という結果になります。つまり、小規模な書き込みサービスで、はるかに大規模な読み取りサービスにデータを供給できます。
- アイドル化とオートスケーリングはサービス単位で設定できる。 各サービスがそれぞれのレプリカ数、オートスケーリング、自動アイドル化の設定を持つため、書き込みサービスは継続的インジェストのために常時稼働させたまま、読み取りサービスは業務時間外にアイドル化させるといった構成が可能です。
- ストレージは重複しない。 warehouse 内のサービスは同じオブジェクトストレージのフォルダーと同じテーブルを共有し、ストレージの課金は一度だけです。
- エンドポイントごとにアクセスを制限できる。 IP access list はサービスごとに適用されるため、書き込みエンドポイントは collector からのみ、読み取りエンドポイントは ClickStack デプロイメントからのみ到達可能にできます。ネットワークアクセス制御のガイドを参照してください。
アーキテクチャ
推奨されるトポロジは、インジェスト用の読み書きサービス 1 つと、ClickStack 用の読み取り専用サービス 1 つを含む warehouse です。
トポロジを計画する際は、次の点に留意してください。
- warehouse の最初のサービスは常に読み書きであり、サービスの種別は作成時に固定されます。読み取り専用と読み書きを切り替えるには、warehouse 内に新しいサービスを作成してください。
- warehouse 内のすべてのサービスは、同じクラウドプロバイダー、リージョン、ClickHouse バージョン、Keeper、およびプライマリサービスのアップグレードスケジュールを共有します。
- インジェストに使用する読み書きサービスは1 つにしてください。マージはストレージを共有するすべての読み書きサービスに割り当てられるため、あるサービスでの挿入に対するマージが別のサービスで実行されることがあります。その別のサービスが重いクエリも処理している場合、それらのクエリはマージを実行しているサービス上で CPU とメモリを奪い合います。その結果、最初のサービスの挿入に対するマージが遅くなり、挿入パフォーマンスも低下します。クエリワークロードは読み取り専用サービスに集約し、マージをインジェストから分離する必要がある場合にのみ 2 つ目の読み書きサービスを追加してください。
分離されたデプロイメントのセットアップ
1
読み書きサービスを準備する
インジェストには、既存のサービス、または新しい warehouse の primary service を使用します。サイズは、sizing model で算出した ingest compute に合わせて設定してください。このサービス上に、データベースとインジェスト専用ユーザーを作成します。warehouse 内のすべてのサービスはアクセス制御を共有するため、ここで作成したユーザーは warehouse 内のどのサービスからでも利用できます:パスワードは
openssl rand -base64 24 などのツールで生成し、manifest やシェルの履歴ではなくシークレットマネージャーに保管してください。詳細は インジェスト用ユーザーの作成 のガイドを参照してください。この service がすでに warehouse に属している場合、同じ warehouse 内の別の service が idled 状態になっていると、database レベルの DDL がハングすることがある点に注意してください。詳細は 管理と DDL を参照してください。2
warehouse に読み取り専用サービスを追加する
ClickHouse Cloud コンソールで、先ほど準備した service のプラス記号をクリックし、そのデータを共有する 2 つ目の service を作成します。サービス種別として read-only を選択し、サイジングモデルで算出したクエリ用コンピュートに合わせてサイズを設定します。詳しい手順については、ガイド warehouse のセットアップ方法 を参照してください。
3
読み書き可能なサービスをインジェスト先に指定する
インジェスト用ユーザーとして認証し、read-write の service endpoint にエクスポートするよう collector を設定します:詳細については collector の設定オプション を、Vector やその他のインジェストパスについては同等の設定を参照してください。read-only エンドポイントへの書き込みは拒否されるため、collector は常に read-write の service を指す必要があります。
4
ClickStack を読み取り専用サービスに接続する
ClickStack UI は、ClickHouse Cloud console で起動元となった ClickHouse service に常に接続します。読み取り専用コンピュート上で実行するには、次の手順を実行します。
- ClickHouse Cloud console で読み取り専用サービスを選択します。
- 左側のナビゲーションメニューから ClickStack を選択します。
5
分割を確認する
ClickStack で検索を実行するか、ダッシュボードを開き、クエリがどのノードで実行されたかを確認します。ここで結果が空であっても、それだけでクエリが別の場所に送られたことを意味するわけではありません。このクエリでは2点に注意してください。アイドル状態になったサービスは行を返せないため、完全な結果が必要な場合は事前に起動しておいてください。また、
system テーブルはクエリを実行したノード上に書き込まれるため、レプリカが複数あるサービスでは、そのすべてを対象とするために default というクラスター名を指定した clusterAllReplicas を使用する必要があります。読み取り専用のサービスでは、次のように ClickStack のクエリが確認できるはずです:system.query_log は定期的に (デフォルトでは 7.5 秒ごとに) フラッシュされるため、検索直後に実行したクエリはまだ記録に現れていない場合があります。少し待ってから再実行するか、権限 (grant) があれば SYSTEM FLUSH LOGS で強制的にフラッシュしてください。トラフィックの発生元を特定しているのは、user と http_user_agent によるグルーピングです。これにより、ログソースがどのテーブルを指していても、UI と SQL Console、さらにそのエンドポイントに接続するその他のクライアントを区別できます。is_initial_query = 1 でフィルタすると、送信された時点のクエリ 1 件につき 1 行だけが残ります。分散実行による二次的なクエリや、materialized view を評価する内部クエリは、is_initial_query = 0 として別途記録されます。read-write サービスでは、同じクエリでインジェスト用ユーザーからの insert が表示され、ClickStack によるクエリトラフィックは表示されないはずです。default クラスターには接続先サービスのレプリカのみが含まれるため、各サービスで順番にこのクエリを実行するのが確実な確認方法です。warehouse 全体を横断した集約ビューを得たい場合は、代わりにクラスター名 all_groups.default を使用してください。hostName() が識別するのはサービスではなくレプリカであるため、特定のサービスにアクティビティを紐付けたい場合は、そのサービスに対して直接クエリを実行してください。マージをインジェストから分離する
非常に高いインジェストレートが持続する場合、インジェストサービスにおける主なコストはインサートそのものではなくマージになります。マージはストレージを共有するすべての読み書きサービスに割り当てられるため、本来別の用途を想定していたサービスにマージ処理が回ってくることもあります。 このようなデプロイメントでは、マージをインジェストサービスから完全に切り離し、3 サービス構成のトポロジーにできます。サポートへのリクエストが必要です読み書きサービスでのマージの無効化は、Cloud コンソールからは設定できません。サービスに適用するにはサポートにお問い合わせください。
- どちらの読み書きサービスについても、自動アイドル化に依存しないでください。 マージを無効化したサービスであっても、ウェアハウス内の他のサービスでのインサートによって生成されるパーツのダウンロードおよび削除イベントは処理します。また、マージされていないパーツが多数存在すること自体がアイドル化を妨げる要因になります。どちらの読み書きサービスも常時稼働している前提で計画してください。
- どちらの読み書きサービスにもクエリを向けないでください。 読み書きサービス上で重い
SELECTクエリを実行すると、CPU とメモリをめぐってマージ処理と競合します。これはまさに、このトポロジーが回避しようとしている障害モードです。前述のとおり、ClickStack は読み取り専用サービスに向けてください。 - ミューテーションが存在する場合、それを実行したサービス上で追跡されます。 オブザーバビリティにおいてミューテーションはまれです。ClickStack のスキーマは
ttl_only_drop_parts = 1を設定しているため、通常の保持期間管理では行をミューテーションで削除するのではなく、TTL マージの際に期限切れのパーツ全体を削除します。ミューテーションを生成するALTERをインジェストサービスに送信した場合、それはマージサービスによって実行され、その進捗はインジェストサービスではなくマージサービス側のsystem.mutationsに現れます。
管理と DDL
スキーマ変更は、以下を含めてすべて read-write サービスに対して実行する必要があります。- テーブル作成 - 初回のインジェスト時に ClickStack collector が自動的に実行します
- 保持期間を変更するための 有効期限 (TTL) の変更
- クエリ高速化のための materialized view の作成
- スキップ索引、projections、その他のパフォーマンス最適化 の追加
エージェント型ワークロードの分離
ClickStack MCPサーバー経由で接続されたAIアシスタントは、ダッシュボードと同様に読み取りトラフィックですが、その負荷パターンは異なります。インシデントを調査するエージェントは、事前に誰も指定していない期間範囲に対して、探索的なクエリを短時間に大量に発行します。エージェントとUIで1つの読み取り専用サービスを共有すると、同じインシデント対応中にエンジニアが見ているダッシュボードの前に、そのバースト負荷が割り込むことになります。 ここでも同じwarehouseのパターンが有効です。つまり、エージェント専用の読み取り専用コンピュートを用意します。1
2つ目の読み取り専用サービスを追加する
上記のセットアップとまったく同じ手順で、warehouse内にもう1つ読み取り専用サービスを作成します。このサービスはUIを提供するサービスと同じテーブルを読み取るため、データをコピーする必要はありません。次に、ClickStackを読み取り専用サービスに向けると同様に、Cloud consoleからそのサービス上でClickStackを一度起動します。Cloud MCPを利用するには、MCP自体だけでなく、ClickStackが有効化されたサービスも必要です。MCPの前提条件を参照してください。サイジングは、sizing modelのダッシュボードQPSではなく、エージェントから想定されるクエリ負荷に基づいて行い、自動アイドル化は有効のままにしておきます。エージェント型の利用は通常断続的であるため、調査の合間はサービスをアイドル状態にできます。
2
そのサービスでMCPを有効化する
ClickHouse Cloud consoleで該当の読み取り専用サービスを開き、Connectをクリックし、Connect with MCPを選択してトグルをオンにします。リモートMCPサーバーの有効化を参照してください。
3
MCPクライアントをそのサービスに向ける
Cloud MCP endpointはすべてのサービスで共通です。リクエストはこのヘッダーはどのMCP clientでも付与できます。Cursor、VS Codeなどでの同等の設定については、特定のサービスを対象にするを参照してください。
x-service-idヘッダーに従って振り分けられ、このヘッダーがない場合は、アカウントで最初に使用されたClickStack serviceに送られます。既存のMCP設定をコピーし、新しい読み取り専用サービスのIDを指定したヘッダーを追加します。アラート
ClickStack はアラートが作成されたサービス上でそのアラートを評価するため、アラートは UI と同じコンピュート、すなわちこのトポロジーでは読み取り専用サービス上で実行されます。Managed ClickStackアラートを有効にするには、Service admin 権限を持つユーザーが少なくとも 1 人、少なくとも 1 回 ClickStack にサインインする必要があります。これにより、アラートのクエリを実行する専用のデータベースユーザーがプロビジョニングされ、このユーザーは warehouse 内のすべてのサービスで共有されます。詳細はManaged ClickStack へのアクセス権の付与のガイドを参照してください。
alert 評価の分離
alert の負荷を中央で振り分けることはできません。alert はユーザーが作成するものであり、ClickStack で alert を追加すると、その人が作業しているサービスに追加され、そのサービスのコンピュートで評価されるためです。あるサービスの alerts を別の場所へ移すような設定はありません。 分離できるのは、中央で管理している alerts です。つまり、プラットフォームチームが組織全体のために保守しているもので、通常は最も評価頻度が高いものでもあります。これらには warehouse 内に専用の読み取り専用サービスを用意し、そこで起動した ClickStack から作成してください:
残るトレードオフは、state がサービスごとに保持されることに起因するものです:
- 共通の alerts と、それに付随する dashboards は alert 評価用サービス上にのみ存在し、クエリ用サービスで作業しているユーザーからは見えません。通知はいずれの場合も同じ宛先に配信されるため、ユーザーが失うのは定義の可視性であって、alert 機能そのものではありません。
- alert 評価用サービス上の SOURCES は別個の object です。デフォルトの OpenTelemetry スキーマを使用しているものは自動検出されますが、カスタムのログソースは、alert から参照できるようにするために、そちらでも設定する必要があります。