K8S CPU 制限を追加するとサービスのパフォーマンスが低下しますか?

K8S CPU 制限を追加するとサービスのパフォーマンスが低下しますか?

ご存知のとおり、Kubernetes QOS は次の 3 つのレベルに分かれています。

  • 保証: Pod 内の各コンテナにはメモリ/CPU 制限とリクエストがあり、その値は等しくなければなりません。コンテナーが制限のみを指定して要求を設定していない場合、要求の値は制限値と等しくなります。
  • Burstable: Pod 内の少なくとも 1 つのコンテナに、保証レベルの要件を満たさないメモリまたは CPU 要求があります。つまり、メモリ/CPU 値の設定が異なります。
  • BestEffort: コンテナーにはメモリや CPU の制約や要求があってはなりません。

Google のベスト プラクティスでは、リソースが不足したときに重要なサービスが削除されないように、重要なサービスは Guaranteed で構成する必要があるとされています。

ベストプラクティスでは、運用と保守の観点からこのように構成する必要があります。チームが立ち上がったばかりのときは、基本的にリソース要求や制限を設定しなくても正常に動作できますが、チームやプロジェクトが拡大するにつれて、安定性の問題が発生し始めます。サービスは互いに影響を及ぼし合うため、サービスに制限を追加するのに適したタイミングかもしれません。そうすることで、多くの悩みから解放されるかもしれません。

ここで明らかなのは、ベスト プラクティスに従うことで、クラスター全体の柔軟性と信頼性が向上するということです。

しかし、CPU の制限に関しては興味深いことが起こります。 CPU は圧縮可能なリソースです。アプリケーションが CPU 制限に達し始めると、Kubernetes はコンテナの調整を開始します。つまり、CPU が人為的に制限され、アプリケーションのパフォーマンスが低下する可能性があります。

1. なぜこのようなことが起こるのでしょうか?

コンテナ オーケストレーターでハード CPU 制限を設定すると、カーネルは Completely Fair Scheduler (CFS) Cgroup を使用してそれらの制限を適用するためです。 CFS cgroup メカニズムは、クォータとサイクルという 2 つの設定を使用して CPU 割り当てを管理します。アプリケーションが特定の期間内に割り当てられた CPU クォータを超えて使用した場合、次の期間まで制限されます。

cgroup のすべての CPU メトリックは、 /sys/fs/cgroup/cpu,cpuacct/<container>クォータと期間の設定はcpu.cfs_quota_us cpu.cfs_period_us

制限メトリック cpu.stat を表示することもできます。 cpu.stat には次の情報が表示されます:

  • nr_periods – cgroupのスレッドが実行できる期間の数
  • nr_throttled – アプリケーションがクォータをすべて使用し、スロットルされた実行可能サイクルの数
  • throttled_time – cgroup内の各スレッドの合計時間を制御します

2. 簡単な例を挙げてみましょう

シングルスレッド アプリケーションは、cgroup 制約のある CPU 上で実行されます。このアプリケーションでは、リクエストを完了するのに 200 ミリ秒の処理時間が必要です。制約がない場合、その応答は次の図のようになります。

設定制限のないリクエスト

ここで、アプリケーションに 0.4 CPU の CPU 制限を割り当てるとします。これは、CPU がその期間中に他の作業を行っていなかったとしても、アプリケーションは 100 ミリ秒サイクルごとに 40 ミリ秒の実行時間を取得することを意味します。 200 ミリ秒かかっていたリクエストが完了するまでに 440 ミリ秒かかるようになりました。

制限されたリクエストの設定

このとき、コンテナパス下の cpu.stat throttled_time を確認すると、240ms に制限されていることがわかります (100ms サイクルごとに、アプリケーションは 40ms しか実行できず、60ms に制限されています。4 サイクルに制限されているため、4 * 60 = 240ms です)。

より一般的な言葉で言えば、1 つの CPU を要求すると、アプリケーションは 1 秒あたり 1 つの CPU コアを使用できることを意味します。シングルスレッドの場合は、常に 1 つのコアを使用できます。ただし、スレッドが 2 つある場合は、制限なく 1 秒あたり 2 つのコアを使用できます。したがって、この制限により、2 つのコアを 1/2 秒間完全に使用してから、調整される可能性があります。 (これは実際には秒単位で測定されるのではなく、私たちの中に存在しますが、このようにすると理解しやすいと思います)。

これを見ると、これは単なる制約であると言うかもしれません。範囲外のリソースは使用できません。そうでない場合は制限されます。

3. 不必要な制限はありますか?

それはそんなに単純なことではありません。多くの人が、不要な cgroup 制限や、CPU 上限がないことを報告しています。ここでは白熱した議論が交わされています:

  1. ​​​https://github.com/kubernetes/kubernetes/issues/67577​​​
  2. ​​​https://github.com/kubernetes/kubernetes/issues/51135​​​
  3. ​​​https://github.com/kubernetes/kubernetes/issues/70585​​​
  4. ​​​https://github.com/kubernetes/kubernetes/pull/75682​​​

コンテナを実行するときにチェックする重要なメトリックはスロットリングです。これは、コンテナが調整されている回数を示します。 CPU 使用率が制限に近いかどうかに関係なく、多くのコンテナが調整されていることがわかりました。熱心なネットユーザーによって報告された事例は次のとおりです。

アニメーションでは、CPU 制限が 800m (0.8 コア、コアの 80%) に設定されており、ピーク使用率は 200m (コアの 20%) で最高になることがわかります。これを見ると、サービスがスロットルされる前に実行するのに十分な CPU があると思うかもしれませんね。 。さて、これを見てください:

CPU 使用率が CPU 制限を下回っていても、CPU スロットリングが発生することがわかります。最大 CPU 使用率は CPU 制限に近づいていません。

制限があると、サービスのパフォーマンスが低下し、待ち時間が長くなります。

4. 原因は何ですか?

本質的に、この問題は Linux カーネルによって発生します。詳細については、このビデオをご覧ください: ​​​https://www.youtube.com/watch?v=UE7QX98-kO0​​​

ビデオが意味しているのはだいたいこれです。

以下は、それぞれ独自のコアに固定された 2 つのワーカー スレッドを持つマルチスレッド デーモンの例です。次の図に示すように、最初の図は一定期間にわたる cgroup のグローバル クォータを示しています。これは 20 ミリ秒のクォータから始まり、0.2 CPU に関連付けられます。中央のグラフは各 CPU キューに割り当てられたクォータを示し、下のグラフはワーカー スレッドが CPU で実行に費やした実際の時間を示します。

10 ミリ秒の場合:

  • ワーカー 1 がリクエストを受信します。
  • クォータの一部は、グローバル クォータから CPU 1 の各 CPU キューに転送されます。
  • ワーカー 1 は、リクエストを処理して応答するのに 5 ミリ秒かかります。

17 ミリ秒:

  • ワーカー2がリクエストを受信します。
  • クォータの一部は、グローバル クォータから CPU 2 の各 CPU キューに転送されます。

ワーカー 1 が要求に応答するのにちょうど 5 ミリ秒かかる可能性は非常に非現実的です。リクエストに追加の処理時間がかかった場合はどうなりますか?

30 ミリ秒後:

  • ワーカー 1 がリクエストを受信します。
  • ワーカー 1 はリクエストを処理するのに 1 ミリ秒しか必要としないため、CPU 1 の CPU ごとのバケットには 4 ミリ秒が残ります。
  • 各 CPU の実行キューには時間が残っていますが、CPU 1 には実行可能なスレッドがもうないため、余裕クォータをグローバル バケットに戻すタイマーが設定されます。このタイマーは、ワーカー 1 の実行が停止してから 7 ミリ秒に設定されます。

38 ミリ秒で:

  • CPU 1 に設定されたスラック タイマーが起動し、1 ミリ秒を除くすべてのクォータがグローバル クォータ プールに返されます。
  • これにより、CPU 1 に 1 ミリ秒の割り当てが残ります。

41 ミリ秒:

  • ワーカー 2 は長いリクエストを受信します。
  • 残りの時間はすべてグローバル バケットから CPU 2 の CPU ごとのバケットに転送され、ワー​​カー 2 がすべての時間を使用します。

49 ミリ秒:

  • CPU 2 上のワーカー 2 は、未処理のリクエストがある間は調整されます。
  • これは、CPU 1 にまだ 1 ミリ秒の割り当てがある場合でも発生します。

1 ミリ秒はデュアルコア マシンでは大きな影響がないかもしれませんが、コア数が多いマシンではそれらのミリ秒が積み重なって大きな影響を及ぼします。 88 コア (n) のマシンでこの動作が発生した場合、サイクルごとに 87 (n-1) ミリ秒かかる可能性があります。これは、潜在的に使用できない 87 ミリ秒または 0.87 CPU (コンテナーあたり) になります。これは、過剰スロットリングによって低いクォータ使用量を実現する方法です。最良の場合、修正により、影響を受けるアプリケーションのインスタンスあたりの使用可能な CPU が 0.87 増加するか、必要な CPU クォータがそれに応じて削減されます。これらの利点により、アプリケーション密度が向上し、クラスター内のアプリケーション応答時間が改善されます。

8 コアおよび 10 コアのマシンでは、この問題はほとんど気付かれませんでした。コア数が流行している現在、この問題はさらに顕著になっています。そのため、コア数の多いマシンで同じアプリケーションを実行すると、制限が増加することがわかりました。

要約すると、クロック スキュー制限の問題により、各期間の割り当てが厳しく制限されます。この問題は、少なくともコミット 512ac999 およびカーネル v4.18 以降では、常に存在していました。

5. Linux カーネルはこの問題をどのように解決しますか?

パッチ適用前のコードは、CPU ごとの有効期限がグローバル有効期限 cfs_rq->runtime_expires cfs_rq->runtime_expires != cfs_b->runtime_expiresカーネルをインストルメント化することで、この状況がノード上でほとんど発生しないことを確認できました。したがって、その 1 ミリ秒は決して期限切れになりません。このパッチは、このロジックをクロック時間に基づくものからサイクル シーケンス カウントに基づくものに変更し、カーネル内の長年のバグを解決します。コードは次のとおりです。

 - if ( cfs_rq - > runtime_expires != cfs_b - > runtime_expires ) {
+ if ( cfs_rq - > expires_seq == cfs_b - > expires_seq ) {
/* ローカル期限を延長し、2 ティック分ドリフトします */
cfs_rq - > runtime_expires + = TICK_NSEC ;
} それ以外{
/* グローバル期限が早まり、有効期限が過ぎました */
cfs_rq - > 残りランタイム= 0 ;
}

5.4 以降のメインライン カーネルの一部である問題を修正しました。これらは、利用可能な多くのカーネルにバックポートされています。

  1. RHEL 7: 3.10.0–1062.8.1.el7+
  2. RHEL 8: 4.18.0–147.2.1.el8_1+
  • Linux 安定版: 4.14.154+、4.19.84+、5.3.9+
  • Ubuntu: 4.15.0–67+、5.3.0–24+
  • Redhat エンタープライズ Linux:
  • コアOS: v4.19.84+

このバグ​​https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=763a9ec06c4​​修正され、4.19 以降を実行している Linux ディストリビューションのカーネルにマージされました。

ただし、kubernetes の問題​​https://github.com/kubernetes/kubernetes/issues/67577​​さまざまな Linux プロジェクトがこの問題に言及していることがわかります。そのため、一部の Linux ディストリビューションではまだこのバグが残っており、修正の統合に取り組んでいると考えられます。

Linux ディストリビューションのカーネル バージョンが 4.19 より低い場合は、ノードを最新の Linux ディストリビューションにアップグレードすることをお勧めしますが、いずれの場合でも、CPU 制限を削除して制限があるかどうかを確認する必要があります。

6. 結論

コンテナを監視して、スロットルによりパフォーマンスが低下していないかどうかを確認します。この場合は、カーネル バージョンを一括でアップグレードするのが最適です。これが不可能な場合は、次の方法で解決できます。

制限を解除する(個人的にはこれは良い考えではないと思う)

  • パフォーマンス要件のあるポッドは、特定のテイントを持つノードにスケジュールされます。
  • これらのポッドの CPU 制限を削除するには、名前空間レベルで制限を追加することを検討してください。

リソースの追加

さらに、CPU スロットルは主に CPU 制限の低下によって発生します。その制限は Cgroup の動作に影響します。したがって、この問題を素早く解決するには、監視に基づいて制限を 10 ~ 25% 増やし、ピークが確実に低減されるか完全に回避されるようにします。

自動拡張

CPU 要求と制限を同じ値に設定すると、通常は期待どおりの動作が得られるため、この問題の簡単な解決策は、CPU 要求と制限を同じ値に設定し、HPA を追加することです。負荷に応じて Pod が自動的にスケールアップおよびスケールダウンできるようにします。

<<:  クラウドセキュリティの主要技術と今後の開発動向

>>:  一般的なクラウド セキュリティ保護対策の一覧

推薦する

適切なクラウド データベース サービスを選択するための 4 つのヒント

リレーショナル データベースは半世紀も前から存在しており、そのさまざまなサブカテゴリ (ドキュメント...

servercrate-3.95USD/512M RAM/10GB SSD/2TB/G ポート

servercrate は 年に設立されましたが、この会社に関する情報はあまりありません。当社は、V...

2019 APP トラフィック価値評価レポート

2019 APP トラフィック価値評価レポート 2019 APP トラフィック価値評価レポート..著...

ユーザーの検索行動とキーワード分析(I)

Dianshi で公開したサイトとページのインクルードに関する前回の一連の記事に続いて、ユーザーの検...

煮えたぎるドメイン名:国内主要ウェブサイト36ピンインドメイン名の損益

最近、業界では、elong.com がダブルピンインドメイン名 yilong.com を取得したこと...

「何百もの意見」を使って、大規模アップデート後の苦痛から何を学ぶべきかを教えてくれる

6月28日のBaiduの大規模なアップデートは多くのウェブマスターを驚かせたが、それから間もなく、7...

セルフメディアの爆発的増加:その存続価値はまだ明らかにされていない

セルフメディアは人々の個人的な価値を高めることができます。名声を求める人もいれば、利益を求める人もい...

ヴィルマックはどうですか?アトランタ データ センター AMD Ryzen シリーズ VPS シンプル レビュー

virmach のアトランタ データ センターの新しい AMD RYZEN シリーズ VPS が正式...

2020 年にクラウド アーキテクトに必要な上位 10 のスキル

ビッグデータ クラウド コンピューティング テクノロジーの発展に伴い、クラウド アーキテクトなど、こ...

教育・研修会社が製品を販売するにはライブストリーミングが唯一の方法なのでしょうか?

教育・研修会社が取り組むビジネスは、成熟した社内プロセスに徐々に組み込まれつつあります。 2017年...

SEOを行うには、ツールを使用するだけでなく、それ以上のことも行う必要があります。

今日、グループで誰かが質問しました: Google に含まれているのに、バックリンクがないのはなぜで...

ブロックチェーンの3つの主要な考え方:分散思考、コード化思考、コンセンサス思考

従来のインターネットは情報インターネットであり、ブロックチェーンは価値インターネットであるため、ブロ...

Yaohe TechnologyがSmart Retailに登場し、新小売時代のマーケティングテクノロジーについて説明

月収10万元の起業の夢を実現するミニプログラム起業支援プラン2018年9月20日、上海ドラゴンドリー...

オートホームのリストから中国メディアの電子商取引の道を語る

2013年、中国のメディア業界に関して、 2 つのことによって引き起こされた 2 つの現象があり、そ...

悪い画像サイトをBaiduのホームページに最適化する方法

SEO 業界に入って以来、私が最も強く感じているのは、「最も欺瞞的なものはなく、より欺瞞的なものだけ...