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 が自動的にスケールアップおよびスケールダウンできるようにします。

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

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

推薦する

企業ウェブサイトのブランド、人気、評判を向上させる方法

「一流企業は標準を売り、二流企業はブランドを売り、三流企業は製品を売ります。」これは伝統産業でよく言...

ウェブページの掲載は多ければ多いほど良いというわけではない

SEO 業界には、含まれるサイトが多ければ多いほど良いという伝統的な概念があります。また、サイトの品...

おすすめ: host1plus-50% 割引コード/VPS クラウド/10g ポート/カスタム ISO/ワンクリック バックアップ/Alipay

host1plus のクラウド サーバーは 2 つの新機能を追加し、50% 割引プロモーションを発表...

SEO実践(4) - SEOに適したURL構造

このシリーズの前の 2 つの記事では、SEO のほぼすべてのアイデアについて説明しました。冒頭で述べ...

SpringBootは分散メッセージングプラットフォームPulsarを統合

みなさんこんにちは。ジュン兄です。優れたメッセージストリーミングプラットフォームとして、Pulsar...

キーワードの選択は重要

キーワードは、SEO 最適化を行う際に最も基本的なものです。 したがって、SEO作業を行う際には、キ...

5G、エッジコンピューティング、産業用IoT

新しい 5G ネットワークは、今後数年間で多くの産業分野に変革をもたらすでしょう。 5G ネットワー...

gfrack: 春節プロモーション、ロサンゼルス VPS 年間支払い 99 元 (1G 帯域幅)、香港 VPS 年間支払い 199 元 (20M 帯域幅)

gfrack は春節の大きなプロモーションを開始しました。米国ロサンゼルスの QN データセンターの...

2024 年に統合データ ストレージを推進する 4 つの要因

現在の技術力の優れた環境において、企業は急速にクラウド コンピューティングへと移行しています。最新の...

討論: SEO ブログは、実践者がオンライン ブランドを構築するための強力なツールになり得るでしょうか?

最近はSEOブログが非常に蔓延しています。都市名とSEO(例えば、福州SEO)を検索すると、関連する...

アリババの科学者は、エネルギー消費量を鶏卵4個からウズラの卵1個に減らすのに14年かかった。

タオバオで注文をするときに、アリババのデータセンターがどれだけの電気とエネルギーを消費するか考えたこ...

ウェブマスターネットワークからの毎日のレポート:タオバオが仮想スーパーマーケットを立ち上げ、百度がキングソフトネットワークと提携

1. 王府井百貨店の電子商取引プラットフォームが開設:商品価格は実店舗と同等伝統的なブランド企業が電...

SEOの活力を維持するための最後の要点:独創性を尊重し保護する

「海賊版を拒否し、オリジナル性を守る」というのは、私たちが生活の中でよく耳にする言葉ですが、それを実...

Google が、広告が多すぎるウェブサイトの所有者を罰すると明言した場合、私たちはどう対応すべきでしょうか?

現在、ほとんどの個人ウェブサイトは依然として利益のために広告に依存していますが、ほんの数日前、Goo...

SEOにおける合理性と感性

最近、ジェーン・オースティンの「分別と多感」という本を読みました。この本では、世の中の人は感性と合理...