現在、リモートディスク IO と CPU については、ここで説明する方法でスケジューリングできます。柔軟なメモリ制限については、メモリオーバーコミット を参照してください。
ディスク設定
storage_configuration があります。
特定のディスクで I/O スケジューリングを有効にするには、ストレージ構成で read_resource および/または write_resource を指定する必要があります。これにより ClickHouse に、そのディスクに対する各読み取りリクエストおよび書き込みリクエストでどのリソースを使うかを指定できます。読み取りリソースと書き込みリソースは同じリソース名を参照でき、これはローカルSSD や HDD で有用です。複数の異なるディスクが同じリソースを参照することもでき、これはリモートディスクで有用です。たとえば、"production" ワークロードと "development" ワークロードの間でネットワーク帯域幅を公平に分配できるようにしたい場合に役立ちます。
例:
ワークロードの指定
workload を指定できます。workload が設定されていない場合は、値 “default” が使用されます。なお、設定プロファイルを使用して別の値を指定することもできます。ユーザーからのすべてのクエリに workload 設定の固定値を付与したい場合は、設定の制約を使用して workload を定数にできます。
バックグラウンドアクティビティに workload 設定を割り当てることも可能です。マージとミューテーションでは、それぞれ merge_workload および mutation_workload サーバー設定が使用されます。これらの値は、merge_workload および mutation_workload MergeTree 設定を使用して、特定のテーブルごとに上書きすることもできます。
“production” と “development” という 2 つの異なるワークロードを持つシステムの例を考えてみましょう。
リソーススケジューリングの階層
inflight_limit(constraint) - 同時実行中のリクエスト数がmax_requestsを超えるか、それらの合計コストがmax_costを超えるとブロックします。子は 1 つだけである必要があります。bandwidth_limit(constraint) - 現在の帯域幅がmax_speedを超える場合 (0 は無制限を意味します) 、またはバーストがmax_burstを超える場合 (デフォルトではmax_speedと同じ) にブロックします。子は 1 つだけである必要があります。fair(policy) - max-min fairness に従って、子ノードの 1 つから次に処理するリクエストを選択します。子ノードではweightを指定できます (デフォルトは 1) 。priority(policy) - 静的な優先度に従って、子ノードの 1 つから次に処理するリクエストを選択します (値が小さいほど優先度が高くなります) 。子ノードではpriorityを指定できます (デフォルトは 0) 。fifo(queue) - リソース容量を超えたリクエストを保持できる、階層のリーフです。
inflight_limit を使用してください。max_requests または max_cost が小さすぎると、リソースを十分に使い切れない可能性があります。一方で、大きすぎると scheduler 内のキューが空になり、その結果、サブツリー内で policy が無視される (公平性が失われたり、優先度が無視されたりする) 可能性がある点に注意してください。逆に、リソースを過度な利用から保護したい場合は、bandwidth_limit を使用してください。これは、duration 秒間に消費されたリソース量が max_burst + max_speed * duration バイトを超えるとスロットリングを行います。同じリソースに 2 つの bandwidth_limit ノードを設定すると、短いインターバルでのピーク帯域幅と、より長いインターバルでの平均帯域幅をそれぞれ制限できます。
次の例は、図に示されている I/O スケジューリング階層を定義する方法を示しています:
ワークロード分類子
workload を、特定のリソースで使用するリーフキューにマッピングするために使用されます。現時点で利用できるワークロード分類は単純で、静的なマッピングのみです。
例:
ワークロード階層
CREATE RESOURCE で作成されたすべてのリソースは同じ階層構造を共有しますが、一部の特性は異なる場合があります。CREATE WORKLOAD で作成された各ワークロードでは、すべてのリソースに対していくつかのスケジューリングノードが自動的に作成されます。子ワークロードは、別の親ワークロードの下に作成できます。以下は、上記の XML 設定とまったく同じ階層を定義する例です。
SETTINGS workload = 'name' で使用できます。
ワークロードをカスタマイズするには、次の設定を使用できます。
priority- 兄弟ワークロードは静的な優先度の値に従って処理されます (値が小さいほど優先度が高くなります) 。weight- 同じ静的優先度を持つ兄弟ワークロードは、重みに応じてリソースを共有します。max_io_requests- このワークロードにおける同時実行 I/O リクエスト数の上限です。max_bytes_inflight- このワークロードにおける同時実行リクエストの処理中バイト総量の上限です。max_bytes_per_second- このワークロードの読み取りまたは書き込みのバイトレートの上限です。max_burst_bytes- スロットリングされることなくこのワークロードで処理できる最大バイト数です (リソースごとに個別に適用されます) 。max_concurrent_threads- このワークロード内のクエリに対するスレッド数の上限です。max_concurrent_threads_ratio_to_cores-max_concurrent_threadsと同じですが、使用可能な CPU コア 数に対して正規化されます。max_cpus- このワークロード内のクエリを処理する CPU コア 数の上限です。max_cpu_share-max_cpusと同じですが、使用可能な CPU コア 数に対して正規化されます。max_burst_cpu_seconds-max_cpusによってスロットリングされることなく、このワークロードが消費できる最大 CPU 秒数です。
max_bytes_per_second = 10485760 を持つワークロードには、各読み取りリソースおよび各書き込みリソースに対して、それぞれ独立した 10 MB/s の帯域幅上限が適用されます。読み取りと書き込みに共通の上限が必要な場合は、READ アクセスと WRITE アクセスに同じリソースを使用することを検討してください。
リソースごとに異なるワークロード階層を指定する方法はありません。ただし、特定のリソースに対して異なるワークロード設定値を指定する方法はあります。
CREATE OR REPLACE WORKLOADクエリを使用します。
ワークロード設定は、適切なスケジューリングノードのセットに変換されます。より下位レベルの詳細については、スケジューリングノードの種類とオプションの説明を参照してください。
CPU スケジューリング
- マスタースレッド — クエリ、または merge や mutation のようなバックグラウンド処理で最初に動作を開始するスレッド。
- ワーカースレッド — CPU 負荷の高いタスクを処理するために、マスターが追加で生成できるスレッド。
max_threads クエリ設定の値が大きいと、多数のワーカースレッドが CPU リソースを容易に占有してしまいます。すると、新たに到着したクエリは、マスタースレッドが実行を開始するための CPU スロット が空くまでブロックされて待機することになります。これを避けるには、次の設定を使用できます。
cpu_slot_preemption サーバー設定で有効にします。これが有効な場合、各スレッドは CPU スロットを定期的に更新します (cpu_slot_quantum_ns サーバー設定に従います) 。この更新によって、CPU が過負荷のときは実行がブロックされることがあります。実行が長時間ブロックされると (cpu_slot_preemption_timeout_ms サーバー設定を参照) 、クエリはスケールダウンし、同時実行中のスレッド数が動的に減少します。CPU 時間の公平性はワークロード間では保証されますが、同じワークロード内のクエリ間では、一部の特殊なケースで損なわれる可能性があることに注意してください。
CPU リソースを宣言すると、
concurrent_threads_soft_limit_num および concurrent_threads_soft_limit_ratio_to_cores 設定は効かなくなります。代わりに、特定のワークロードに割り当てる CPU 数の制限には、ワークロード設定 max_concurrent_threads が使用されます。従来の動作を再現するには、WORKER THREAD リソースのみを作成し、ワークロード all の max_concurrent_threads を concurrent_threads_soft_limit_num と同じ値に設定したうえで、クエリ設定 workload = "all" を使用してください。この構成は、concurrent_threads_scheduler 設定を “fair_round_robin” にした場合に相当します。スレッドと CPU
- スレッド数の制限:
max_concurrent_threadsとmax_concurrent_threads_ratio_to_cores - CPU スロットリング:
max_cpus、max_cpu_share、max_burst_cpu_seconds
max_threads で指定される値を引き下げます。2 つ目は、トークンバケットアルゴリズムを使ってワークロードの CPU 消費をスロットリングします。これはスレッド数自体には直接影響しませんが、ワークロード内のすべてのスレッドによる CPU の総消費量をスロットリングします。
max_cpus と max_burst_cpu_seconds によるトークンバケットスロットリングは、次のことを意味します。任意の delta 秒の期間において、ワークロード内のすべてのクエリによる CPU 総消費量は max_cpus * delta + max_burst_cpu_seconds CPU 秒を超えてはなりません。長期的には平均消費量が max_cpus によって制限されますが、短期的にはこの上限を超える場合があります。たとえば、max_burst_cpu_seconds = 60 かつ max_cpus=0.001 の場合、スロットリングされることなく、1 スレッドを 60 秒間、2 スレッドを 30 秒間、または 60 スレッドを 1 秒間実行できます。max_burst_cpu_seconds のデフォルト値は 1 秒です。値を小さくしすぎると、同時実行スレッドが多い場合に、許可された max_cpus コアを十分に使い切れないことがあります。
CPU スロットを保持している間、スレッドは次の 3 つの主要な状態のいずれかになります。
- Running: 実際に CPU リソースを消費している状態。この状態で費やされた時間は CPU スロットリングの対象として計上されます。
- Ready: CPU が利用可能になるのを待っている状態。CPU スロットリングの対象にはなりません。
- Blocked: I/O 操作やその他のブロッキング syscall (例: mutex の待機) を行っている状態。CPU スロットリングの対象にはなりません。
max_cpu_share に基づく上限は CPU リソース全体の 70% です。一方、インジェストには少なくとも 0.8 * 0.25 = 20% が保証され、上限はありません。
ClickHouse server で CPU 使用率を最大化したい場合は、ルート workload
all に対して max_cpus や max_cpu_share を使用しないでください。代わりに、max_concurrent_threads により大きな値を設定してください。たとえば、8 CPU のシステムでは、max_concurrent_threads = 16 に設定します。これにより、8 スレッドが CPU タスクを実行している間に、別の 8 スレッドで I/O 操作を処理できます。追加のスレッドによって CPU 負荷が生じるため、スケジューリングルールが確実に適用されます。これに対して、max_cpus = 8 を設定しても CPU 負荷は発生しません。これは、server が利用可能な 8 CPU を超えて使用できないためです。クエリスロットのスケジューリング
max_concurrent_queries は、特定のワークロードで同時に実行できるクエリ数を制限します。これは、クエリ設定 max_concurrent_queries_for_all_users およびサーバー設定 max_concurrent_queries に相当します。非同期 INSERT クエリと、KILL のような一部の特殊なクエリは、この上限にはカウントされません。
ワークロード設定 max_queries_per_second と max_burst_queries は、トークンバケットスロットラーを使用して、そのワークロードのクエリ数を制限します。これにより、任意の時間間隔 T において、実行を開始する新規クエリ数が max_queries_per_second * T + max_burst_queries を超えないことが保証されます。
ワークロード設定 max_waiting_queries は、そのワークロードの待機中クエリ数を制限します。上限に達すると、サーバーはエラー SERVER_OVERLOADED を返します。
ブロックされたクエリは、すべての制約が満たされるまで無期限に待機し、
SHOW PROCESSLIST には表示されません。ワークロードとリソースの保存
CREATE WORKLOAD および CREATE RESOURCE クエリ形式の、すべてのワークロードとリソースの定義は、workload_path のディスク上、または workload_zookeeper_path の ZooKeeper に永続的に保存されます。ノード間の整合性を確保するには、ZooKeeper ストレージの使用を推奨します。あるいは、ディスクストレージとあわせて ON CLUSTER 句を使用することもできます。
設定ベースのワークロードとリソース
Configuration のフォーマット
CREATE WORKLOAD 文および CREATE RESOURCE 文と同じ SQL 構文を使用します。すべてのクエリは有効である必要があります。
使用時の推奨事項
- インフラストラクチャの制限を設定するため、設定内でルートワークロードとネットワーク I/O リソースを定義します
- これらの制限を確実に適用するため、
throw_on_unknown_workloadを設定します - すべてのクエリに制限を自動適用するため、
CREATE WORKLOAD default IN allを作成します (workloadクエリ設定のデフォルト値は ‘default’ であるため) - 設定された階層内で、ユーザーが追加のワークロードを作成できるようにします
厳格なリソースアクセス
throw_on_unknown_workload があります。これを true に設定すると、すべてのクエリで有効な workload クエリ設定の指定が必須になり、指定しない場合は RESOURCE_ACCESS_DENIED 例外が発生します。これを false に設定すると、そのようなクエリはリソーススケジューラを使用せず、つまり任意の RESOURCE に無制限にアクセスできます。クエリ設定 use_concurrency_control = 0 を指定すると、クエリは CPU スケジューラを回避し、CPU を無制限に使用できます。CPU スケジューリングを強制するには、use_concurrency_control を読み取り専用の定数値として維持する設定制約を作成してください。
CREATE WORKLOAD default を実行していない限り、throw_on_unknown_workload を true に設定しないでください。起動中に workload が明示的に設定されていないクエリが実行されると、サーバーの起動時に問題が発生する可能性があります。関連項目
- system.scheduler
- system.workloads
- system.resources
- merge_workload MergeTree 設定
- merge_workload グローバルなサーバー設定
- mutation_workload MergeTree 設定
- mutation_workload グローバルなサーバー設定
- workload_path グローバルなサーバー設定
- workload_zookeeper_path グローバルなサーバー設定
- cpu_slot_preemption グローバルなサーバー設定
- cpu_slot_quantum_ns グローバルなサーバー設定
- cpu_slot_preemption_timeout_ms グローバルなサーバー設定