Demystifying Kubernetes CPU Limits (and Throttling)
#翻訳
https://wbhegedus.me/understanding-kubernetes-cpu-limits/
最近、Wordpress Web サイトの定期的なセキュリティ スキャン中に CPU 使用率が高くなり、応答の遅さやエラーの増加、その他の望ましくない結果などの問題を引き起こしていることについて調査を行っています。 これは通常、単一のポッド (スキャナーがランダムにルーティングされるポッド) に限定されますが、それでもユーザーに表示される (および Pagerduty をアクティブ化する 😅) 可能性があるため、それをより適切に監視したいと考えています。
Initial Investigation
不明な点を調査している IT 業界の他の人と同じように、私もまず Google に相談しました。私は、他の人が Kubernetes のポッドの CPU 使用率を監視するために何をしているかを調べました。このことが、CPU の使用量よりも、CPU のスロットリング量を監視する方が実際にははるかに有益であることを初めて発見しました。
Kubernetes クラスターの健全性を監視するための適切なデフォルトの Prometheus アラート ルールを提供する kubernetes-mixin プロジェクトのことはすでに知っていました。そこで、CPU の監視にどのようなルールが使用されているかを確認するために、まずそこを調べました。現在、バンドルされている唯一の CPU 使用率アラートは「CPUThrottlingHigh」です。これは、number_of_cpu_cycles_pod_gets_throttled /number_of_cpu_cycles_total (実際のメトリクス名ではありません) を計算して、ポッドが CPU スロットルを取得する頻度の割合を示します。
しかし、待ってください、スロットルとは一体何を意味するのでしょうか? (少なくとも私の考えでは) スロットルとは、単に速度が低下するというような意味ですが、この場合、スロットルとは完全に停止することを意味します。次の CFS 期間 (Kubernetes では 100 ミリ秒ごと、Linuxのデフォルトでもあるーこれについては後で詳しく説明します) まで、それ以上 CPU を使用できません。
抽象的には、これは非常に簡潔に見えますが、大量の CPU コアを備えた本番サーバーで本当に実際に見ると、さらに混乱します。
Conceptualizing
この記事では、CPU 制限が 4.0 のポッドを実行する 128 CPU コアを備えたサーバーについて言及します。
ミリコアの概念にまだ慣れていない場合は、1 ミリコア = CPU 時間の 1/1000 (1000 ミリコア = 1 コア全体) と言うだけで十分です。これは、Kubernetes で CPU リクエスト/制限を定義するために使用されるメトリックです。この例のポッドには 4.0 という制限があり、これは 4,000 ミリコア、つまり 4 コア全体に相当する作業能力に相当します。
しかし、オペレーティング システムのカーネルはどのようにしてこの措置を強制するのでしょうか? Linux コンテナーがどのように機能するかに詳しい場合は、おそらく cgroup について聞いたことがあるでしょう。簡単に言えば、cgroup は、同じサーバー上で実行されている他のプロセスを認識しないように、プロセスのグループを分離して制御する方法です。これが、Docker コンテナを実行するときに、その ENTRYPOINT + CMD が PID 1であると認識する理由です。
とりわけ、cgroup は Linux CFS (Completely Fair Scheduler) を使用して、プロセスのグループにリソース制限を設定および強制します。 たとえばKubernetes のポッド。これを行うには、割り当てquotaと期間periodを設定します。クォータとは、一定期間内に使用できる CPU 時間のことです。クォータを使い切ると、CPU の使用を再開できる次の期間まで「スロットル」されます。
ミリコアの説明に戻りますが、これは、オペレーティング システムの cfs_period 100 ミリ秒ごとに 400 ミリ秒の使用が許可されることを意味します。 100 ミリ秒の時間枠で 400 ミリ秒が得られる理由は、各コアが 100 ミリ秒の期間で 100 ミリ秒の作業を実行できるためです (100 ミリ秒 x 4 コア = 400 ミリ秒)。この 400 ミリ秒の作業は、どのような方法でも分割できます。100 ミリ秒の cfs_period で 4 つの vCPU がそれぞれ 100 ミリ秒の作業を実行したり、8 つの vCPU がそれぞれ 50 ミリ秒の作業を実行したりする可能性があります。覚えておいてください - CPU 制限は実際のvCPUではなく時間に基づいています。
それを理解すると、スロットリングの混乱の理由が明らかになり始めます。私が理解できる限り、スロットリングの理論上の上限は n * (100ms) - 制限です。ここで、n は vCPU の数、制限は 100 ミリ秒のウィンドウ内に割り当てられる CPU のミリ秒数です (cpuLimit * 100ms によって以前に計算されました) )。これは、(128 コア * 100 ミリ秒 - 400 ミリ秒) * 10 = 124 であるため、私の 128 コア マシンでのスロットルの理論上の上限は 1 秒あたり 124 秒のスロットルであることを意味します。
注: 実際の CPU スロットリングは、実行しているプロセスの数と、OS スケジューラによってそれらのプロセスが割り当てられているコアによって決まります。
Putting it together
今、ようやく私の脳内で物事がカチッと音を立て始めました。少なくとも...Linux スケジューラ自体で発生する詳細については私がまだ多少無知であることを考慮すると、できる限りのことです。
この調査全体は、Prometheus のcontainer_cpu_cfs_throttled_seconds_total メトリクスに対して rate() 関数を使用しようとしたとき、1 秒あたりのスロットル レートが 1 秒よりも大幅に高かった (1 秒あたり 70 秒に近いと考えてください) という事実から始まりました。 1 秒のウィンドウ内で 1 秒を超えてポッドをスロットルするにはどうすればよいでしょうか?私は不思議に思いました。
これらすべての情報をまとめると、このような高いスロットルの原因は、httpd が追加の CPU コアで追加のプロセスを生成し、スロットルの量がリソース制限を大幅に超えていたためであることがわかりました。
Conclusion
十分に脳が活性化したので、CPU がスロットルされている時間に基づいて CPU 使用率の高さを警告する十分な監視が行われていると言えます。現在実施されているアラートは次のとおりです。
code:yaml
- alert: Wordpress_High_CPU_Throttling
expr: rate(container_cpu_cfs_throttled_seconds_total{namespace=~"wordpress-.*"}1m) > 1
for: 30m
labels:
severity: warning
annotations:
message: The {{ $labels.pod_name }} pod in {{ $labels.namespace }} is experiencing a high amount of CPU throttling as a result of its CPU limit.
要約すると:
Kubernetes は 100 ミリ秒の cfs_period_us を使用します (Linux のデフォルト)
k8s の 1.0 の各 CPU リクエストは、cfs_period 内の 100ms の CPU 時間を表します。
理論的には、これは 1 CPU の時間の 100% ですが、ポッドは通常、複数のコアで複数のプロセスを実行するため、実際にはそうではありません。
カーネルがポッドのスロットリングを報告する秒数の上限は、ポッドが使用している CPU コアの数によって決まります。
使用する CPU コアの数は、CPU limitに直接関係しません。これは、ポッドが実行するプロセスの数とより強く相関します。
関連
Understanding CPU throttling in Kubernetes to improve application performance #k8sjp - Speaker Deck
#Kubernetes