待ち行列理論で考えるGoogle Kubernates Engineの最適なポッド数🤔
読み飛ばしていい、著者の戯言
色々ありまして、Clood Professional Architectの勉強しています。アウトプットしようと思っても、「本や公式ページ、Udemiyで勉強したことを、ただただまとめるのはつまらんなあ」と駄々を捏ねて書いた記事1作目です。GKEについて勉強していて気になったことを調べました。CPA関連で、この記事を含めて3報アップする予定です。
この記事を書くためにGeminiさんらと問答して、待ち行列なるものも新たに勉強することになりました(問答はしましたが、この記事を書いているのはすべて私です)。純粋な理論ばかり触ってきた私にって、応用数学は新鮮で、より現実の問題とリンクしてる感覚をひしひしと感じています。
もちろん学術書ではないので、ゴリゴリ数学の式変形をZennでやるようなことはしません。結果だけ使います。S. Hawkingの著書であるA Brief History of Time(ホーキング、宇宙を語る : ビッグバンからブラックホールまで)の冒頭には、数式を文書に入れると、その数だけ減少するという旨の話があります。流石に数式1つというわけにはいかないですが、紹介しながら進めていきます。
導入
クラウドネィティブなマイクロサービスのデプロイ先としてGoogle Kubernates Engine (GKE)を想像する人は多いと思います。マイクロサービスとして動くそれぞれのサービスのポッド性能は、開発段階において人の感覚で決められることが多いのではないでしょうか?「とりあえず、他のサービスのCPUがこれくらいだから」「ベストプラクティスがこれくらいだから」という理由で決めてしまっていることが、GKE上で、いやそうでない一般の開発現場でも往々にして存在するのではないか、と予想しています(だって、人間だもの)。
ベストプラクティスという言葉は、効率的にで業務を回す日常において安心感のある言葉ではあります。一方でよくよく考えてみると、なぜベストプラクティスなのかは瞬時にわかりかねます(私に関しては経験不足によるものでしょうが)。「〇〇という状況を想像してみると、こちらのほうがよい」と、なんとなく説得させられた気になります。しかしながら、「ベストプラクティス」は過去の多くの経験から帰納的に考えられたものです。
そこで、帰納的な考えをできる限り排すことにし、数理モデルから演繹的に、ポッドの性能を決定をすることを目指します。
この記事ではGKEのポッドを待ち行列理論、および実務的な観点から、いくつかの仮定を置くことで、数理的に適切なポッド数を予想します。
この記事の構成は次のとおりです。
- 待ち行列理論の概要を説明します。
- Google Kubernates Engineについて軽く触れます。
- 必要な数学(ポアソン分布、指数分布、待ち行列理論)を導入します。
待ち行列理論 (queueing theory)とは
簡単にいうと、ある系の混雑状況を数学的に記述した理論のこと。物理的、社会的な洞察から要請する仮定を使い、得られた系の数学的な表現を、単にモデルということが多いです。
混雑状況を数理的に表現するといことから、応用範囲は広く、レジに並ぶ顧客であったり、今回の記事にもなっているサーバなどの、性能評価に応用されることが多いようです。
ここで行列とは、線形代数でいう行列 (matrix)ではなく、並んでいる列(queue)を表します。
※英語版Wikipediaにも書いていますが、スペルが"queuing"と書かれる分野もあるそうですが、重要なジャーナルの一つは次のような雑誌名になっています:Queueing Systems
Google Kubernates Engine (GKE)とは
コンテナのオーケストレーションツールです。GoogleのBorgらの論文から始まった、GoogleがGoogle Cloud Platfrom上で提供するサービスです。
コンテナに対して、管理、実行、オートスケール、オートヒーリング、ローリングアップデートなどなどを宣言的に処理することができる便利ツールですね。
この記事では特に、オートスケールに興味を持ちます。このスケーリングにも種類があり、
- 水平スケール (HPA: Horizontal Pod Autoscaler)
- 垂直スケール (VPA: Vertical Pod Autoscaler)
- 水平垂直スケール (MPA: MultidimensionalPodAutoscaler)
があります。
準備
数学的な仮定
今回採用する待ち行列のモデルとして、簡単なMMcモデルを採用します(理由は特にありません。時間が足らんかったんです泣)。ここで、MMcはそれぞれ
- M: マルコフ到着過程 (Markovian Arrival Process) リクエストの到着がランダム
- M: マルコフサービス過程 (Markovian Service Process) ポッドでの処理時間がランダム
- c: 処理を行うポッド数
であると仮定します。
到着過程
現実のリクエストはランダムに飛んでくると考えられます。もちろん、特定の時間に周期的に大量のリクエストが来るということはありますが、簡単のためにこの記事では言及いたしません。リクエストのランダムネスは、数学の言葉でポアソン分布というものにモデル化することができます。単位時間の平均リクエスト数を
と与えられます。
(ポアソン分布と調べると、よく馬に蹴られて死んだ兵士の例が出てきますね)

サービス過程
GKEにデプロイされたアプリを担うポッドでの多くの処理は、これまでの処理の履歴に依存しないと考えられます。
例えばあるリクエストの処理に平均50 msecかかるとします。30 msecも経ったから、あともう直ぐで終わるというのは、平均という尺度を見ているから感じる感覚であって、実際は31 msecで終わることもあれば、100 msecかかることだってあります。確率は小さくとも1000 msecなんてことはあるやもしれません。このような事象の時間間隔にランダムネスがあるとき、数学の言葉では指数分布
という確率密度に変換することができます。ここで

モデル
リクエストをして、
と記述されます。これはポアソン分布や指数分布の性質(無記録性)を使うことと、状態間の遷移が隣同士の状態にしか依存しないことから導かれます。
これでポッドのスケールの過渡期を説明するとことができるかもしれませんが、かなり挑戦的な内容になります。オートスケールするタイミングなどを議論する場合には必要な要素で面白い内容だとは思いますが、今回のポッドの最適な数を理論的に見積もるということからは大きく逸脱してしまうので、この式そのままの解析はいたしません。
最適なポッドの数、つまりあるべき状態を定義するということは、あるべき状態になったあと、その状態を維持するということです。状態を維持するということは、確率
実は、このような全体のつり合いの式が成り立つとき、より詳細な状態間のつり合いも成り立ちます(詳細つり合い)。つまり、
です。イメージとしてはポッドにリクエストして、ある程度CPU使用が高い状態を維持しているとき、リクエストの早さと処理の速さが同じ、ということを表しています。
GKE性能指標の導出
さて、上記の議論からGKEの性能指標を導出しましょう!ここまで3つの数式が登場しましたが、ここから使うのは最後の式、詳細釣り合いの式
-
を求めるP_n - 確率の規格化条件から
を求めるP_0 -
を使った指標を定義するP_n
です。
P_n を求める
詳細釣り合いの式から、
結果だけ書くと、
(i) n < c の場合
(ii) n > c の場合
と表せます。
P_0 を求める
確率の規格化条件
を使います。上記の
と表されます。無限和がでてきますが、高校数学ででてくる
評価指標を計算する
平均待ち行列長
平均待ち行列長
これはどう意味かというと、ポッドが全て埋まったときに、系で処理待ちしているリクエストの数です。状態
ところで、
を得ることができます。ここで見やすさのために
ですが、ちょっとよくわかりません。なのでなるべく直感的な説明を考えてみます。
待ちが発生する確率
(a)
(b) では、リクエストがすでに待っている状態
これらを(a), (b)を総計することで、待ちが発生する確率
となるのです。
待ちのやばさ
いい表現が思いつきませんでしたが、ポッドの処理が小さいとき、つまり
一方、
平均待ち時間
待ちの長さがわかれば、処理の平均速度(=サービス率
パーセンタイル応答時間の計算
平均待ち時間が
です。詳細は省きますが、これは冒頭で紹介したポッドの処理時間が指数分布と仮定できる、ということに直接的に関わるものです。
待ち時間がこの時間以下になる確率が95%であることを求めましょう。これを95パーセンタイル待ち時間
です。これを
です。そして、これは待ち時間なので、ユーザが体感する応答時間
となりますね。
具体的な計算例
さて、SLOを設定して、負荷検証を実施して、次が確定したとします:
- SLO: 95パーセンタイル時間が
以内に収める200~{\rm msec} -
リクエストが平均\lambda \lambda = 100件 /{\rm sec} -
: 処理するにの\mu \mu = 20件/{\rm sec}
すると、ポッドの利用率
ここで、技術的要請から
ここまでできたら、
この結果によると、ポッドが6つの時点でレスポンスまでの時間が
では逆にビジネスの要件で指定した「95パーセンタイル時間が

縦軸はリクエストの到着率
※簡単のために、コストの観点は本件では考慮していません。想定としては、図の右側に禁止区域が現れるはずです。
結果
本記事で用いた待ち行列理論と具体的な計算例から、いくつかの知見が得られました。
第一に設定したSLO(今回は例として95パーセンタイル応答時間が200msec以内を採用)、リクエスト到着率
次に、ポッド数を固定した場合に、SLOを満たすリクエスト到着率 (
この図の各線は、指定したポッド数 (
- 曲線の右下の領域: 安全領域です。この領域では、リクエストの到着が比較的少ないか、ポッドの処理性能が高いため、システムはSLOを満たし安定稼働します。
- 曲線の左上の領域: 危険領域です。リクエストが多すぎるか、処理性能が追いついていないため、応答時間がSLOを超過してしまいます。
この図は、システムの性能要件を考える上で有用になる可能性があります。例えば、「秒間200リクエスト (
まとめと展望
この記事では、GKE上のポッドの適切な数を決定するという実務的な課題に対し、待ち行列理論(M/M/cモデル)という数理モデルを適用し、演繹的に解を導出するアプローチを試みました。
具体的なSLOと性能要件(リクエスト到着率
Future workとしては、いくつかの発展的なテーマが考えられます。
まず、理論と現実の比較検証が不可欠です。実際にGKE環境で負荷試験を行い、ここで導出した理論値と実測値のパフォーマンスを比較・評価することで、モデルの妥当性や限界を明らかにできます(今はお金がない泣)。
次に、モデルの精緻化です。今回は最もシンプルなM/M/cモデルを仮定しましたが、現実のトラフィックは必ずしもランダム(ポアソン分布)ではなく、特定の時間に集中するバーストな振る舞いを示すことは十分に考えられます。また、処理時間も常に指数分布に従うとは限りません。より現実に近い分布(例えば、M/G/cモデルなど)を適用することで、さらに精度の高い予測が可能になるでしょう。
最後に、コスト最適化と動的スケーリングについても考える余地があります。本記事ではコストを度外視しましたが、実運用ではパフォーマンスとコストのトレードオフが常に問われます。今回のモデルにコストの概念を加え、費用対効果が最も高いポッド構成を模索することが考えられます。また、定常状態だけでなく、リクエストの増減に応じてポッド数を動的に変えるオートスケーリング(HPA)の挙動をモデル化し、スケールアップ・ダウンの最適な閾値やタイミングを理論的に決定することもできるもしれません。
参考文献
- https://orsj.org/wp-content/or-archives50/pdf/bul/Vol.40_11_649.pdf
- https://www.scirp.org/journal/paperinformation?paperid=51426
- https://queue.acm.org/detail.cfm?id=2898444
- https://cloud.google.com/kubernetes-engine?hl=ja#deploying-and-running-applications
付録
図出力用のスクリプト
ポアソン分布の導出
観測時間を
指数分布の導出
(今後の更新に期待)
Discussion
TYPO報告です。『Google Kubernates Engine (GKE)とは』の場所で下記のようになってました。
ありがとうございます!修正いたしました🙇