前回の続きで、『NodeとPodのリソース量と、NodeあたりのPod数はどのくらいで運用するのが正着なの?』の答えを求めて幾星霜。
正解とは言わないまでも、有効と言える考え方まではもっていきたい。少しずつ寄せていって、詰めきれるかは閃き次第。そんなノリで Let’s & go.
概要
NodeあたりのPod数ってなんぞや?ってところからいくと、WEBサーバーのような同内容の複数Podであることを前提として、1Nodeの中で起動できる最大Pod数のことです。これは、Resource Requests を調整することで決定できます。Node 8vCPU 32GiB にて、Pod Requests 8000m 32GiB だと最大1Pod だし、2000m 8GiB だと最大4Pod になる、というおさらいです(面倒なので端数はなし)。
選択肢としては、1~16Pod くらいまであるとして、こうすべき、とまでは言えなくとも、どのくらいにしたらどのような特徴になるのか、というのは事前に考えておかなくちゃ運用に入る気なんて起きないでしょう。ということで、考察タイムです。
OSのオーバーヘッド
(少) ○ <---> ☓ (多)こんな感じで優劣を書いていきます。これはPod数が少ない方が良いということです。
コンテナを起動すると、アプリケーション用のデーモン以外に、OSに最低限必要なプロセスや、監視・ログなどの基盤用デーモンが常駐することになります。この、その他の部分は、CPUリソースについてはあまり気にする量ではないですが、メモリは一定量を食うので、Pod数が多くなるほどその総消費量が増えることになります。
例えば、1Pod あたり 50MiB のベースメモリが必要とすると、最大1Pod ならそのまま 50MiB で済みますが、10Pod だと 500MiB、20Pod で 1000MiB と膨れていきます。そして元のインスタンスタイプによるメモリ量が小さいほど、その影響は大きくなります。総容量64GiB のうち 10Pod 500MiB 使っても誤差の範囲ですが、4GiB で 500MiB となると「むっ」と感じるくらいになるでしょう。
少なくとも、多すぎても良くないだろうことは推測できます。
使用可能な状態のリソース量
(少) ○ <---> ☓ (多)Nodeへの負荷が徐々に上がっていった時、ほとんどのタイミングにおいてPod数が少ないほうが、リソースの確保量が多くなります。targetCPU=50% として、Node負荷10%毎の、総Podリソース%を簡単に表すと……(日本語が難しいっ)
1Pod だと当然、最初からNodeリソースを使い切ります。
複数の例えば 8Pod だと、最初の 1Pod しか起動していない状態では 12.5% しかNodeリソースを使えていないことになります。8Pod 中、4Pod 起動するのは Node負荷が 20% あたりで、それでようやく 50% のNodeリソースを発揮できる状態です。
※CPU は Limitをつけなければ100%発揮できるので、
主にメモリベースの話です。メモリ=同時接続数のイメージです
Pod数と、Node負荷%のタイミング次第では、Pod数が多いほうが数値が高いところもありますが、基本的にはPod数が多いほうが有効リソース量が少ないことがわかります。
これからわかることは、Node単位でみれば Pod数が少ない方が、より急増トラフィクに対応する耐久力があるということです。ゆるやかに増える場合は最終的なリソース量は同じですが、急激にきた場合は CPUメトリックの更新 + Pod起動 の時間の間に、総Podリソース量を超えるかどうかで、エラーの発生率などに影響が出てきます。
それ以上の、既存のNode群を突き抜ける超急増トラフィックの場合は、これに関係なくNode単位での対策になるので、また違う話になります。
ここでもまた、少なくとも細かすぎるPodはよくなさそうだ、という程度に抑えておきます。
追加Nodeの耐久力
(少) ○ <---> ☓ (多)1つ上のリソース量の話と似ているのですが、こちらは Node群での話になります。
Node増加後のNodeリソース配分
ALB + AutoscalingGroup 構成において、ALB から NodePort への分散方式は、おなじみラウンドロビンになります。なので Node への、一定期間における転送数は常にほぼ等しくなります。10 Node に対して 1000 req/s があれば、1 Node あたり 100 req/s をさばくことになります。その仕組み上で、徐々に負荷が上がっていき、Node の平均CPU使用率が targetCPU と同じ 50% に到達したとします。Node内のPod数は最大値に達しており、次のPodが起動できなくなって cluster-autoscaler が Node増加の処理をします。
という場面で、仮に追加Node数が 1台 だった場合に、新規Node群の1Nodeあたりの負荷がどうなるかというと……
1Node 50% に1台足したら、2Node で1台あたり 25%、
2Node 飽和状態は合計100%分なので、3Node になったら1台あたり 33.3%
3Node 同上は合計150%分なので、4Node になったら1台あたり 37.5%
という内容です。元の台数が多くなるほど、1台ぽっち追加しても平均リソース使用率はあまり緩和されないっていうのがわかります。実際にはCPU使用率の傾斜次第では、一気に複数台増えることも普通にありますが、傾斜が緩いと1台追加も普通にあるので、この最弱増加について警戒していきます。
既存Podのリソース変化
さぁさらに理解しづらい表を作りました。これは、1Node増加時に、既存つまり増加前のNode群の中の、1Podあたりの負荷はどう変化するかという内容です。こちらは、先程のNode配分に、さらにPod数で割ったような数値になっており、これ自体にはそんなに意味はありません。新規Podとの比較で出しておいただけであります。
新規Podの耐久力
ここで、新規1Podのリソース割当量を確認します。さきほども書いた通り、CPUはLimitなしで突き抜けるので、実際はメモリベースでのリソース上限であり、1Node 100% を振り分けた数値になります。これも確認の整理しただけで、本題は次です。
新規NodeにおけるPodリソースの貫通度合い
新規1Node増加後の、新規1Pod にかかる負荷は、新規Node群におけるリソース配分% と同値になります。1Pod しかいないと、1Node のトラフィックを全て引き受けるためです。で、それぞれの数値は出したので、1Node にかかる負荷を、1Pod の最大キャパシティで割ると、100 を限界とした 1Pod のキャパオーバー度合いを算出できます。
100 を超えた数値がほとんどになっています。
これが表すのは、1Pod こっきりで起動したNode では、新規参入した瞬間にキャパシティの 0.5~5 倍となるトラフィックを受けるであろう、ということです。ほぼ受け始めたその瞬間からキャパオーバーするとすれば、(1 / 新Node数) の確率で、エラーが返るということになります。
実際には、Deployment のヘルスチェックですぐに外れ、そのまま targetGroup からも外れ、落ち着いたらまた復帰し、を繰り返すかもしれません。し、CPU Limitがなければ、Podが想定より捌ける可能性はあります。
ここでわかることは、そこまで細かすぎないPodにしたとしても、スケールアウトの瞬間には一部の新規Podでキャパオーバーが発生する可能性がある、ということです。ただし、その最弱に近い条件が、どのくらいの頻度で発生するかは、負荷の増加傾斜や、Podでのリソース使用配分などが関わってくるので、こうだから危ないんです!という単純な話ではありません。
Pod数が少ない方が安全なのか
ここまで、Pod数が少ない方がメリットがある── というよりはPod数が多い時のデメリットをあげてきました。長くなったのでいったん区切って、次記事へ続きたいと思いますが、Node も Pod も複数台が同時に増加しますし、Pod数が細かいほど、全体の負荷増加に対してより多くのPodを同時に増やそうとしやすくなるので、あくまで最弱理論値であるという趣味に近い計算──
にみえるか、それとも現実的に対策を考えるべきかは、そのサービス、そこのエンジニア次第だと思います。
私の場合はそれなりに無視できないリスクにみえるので、のちのち対策となる検証をすることになるでしょう。