TT Lab
はじめる
学ぶ 学習パス コース

負荷テスト

平均で毎秒 100 件、では負荷を説明できない

TT Labで続きを見る

一言でいうと

「1秒あたり25件」は、負荷を半分しか説明していません。同じ平均でも、到着が均等か偏るかによって、待ち行列とレイテンシが分かれ、クローズドループでは、リクエスト率を決めることさえできません。

なぜ必要なのか

容量の見積もりは、たいていこう始まります。ピークが1秒あたり25件で、1件に40ミリ秒かかるので、必要なワーカーは25 × 0.04で1個。余裕を見て4個を置きます。計算は合っています。ところがデプロイすると、待ち行列が数十まで跳ね上がり、p95が10倍に跳ねます。

間違っているのは算数ではなく、仮定です。あの計算は、リクエストが40ミリ秒ごとに1つずつ均等に来ると仮定しています。実際のトラフィックは、そうは来ません。人が使うサービスは、通知1回で集中し、機械が使うサービスは、cronが正時に目を覚まして集中します。平均は同じでも、瞬間の同時リクエスト数が違い、待ち行列は、平均ではなく瞬間に反応します。

反対方向の誤解もよくあります。負荷テストのツールに「同時ユーザー100人」を入れて、1秒あたり何件出るかを、あらかじめ書いてしまう場合です。クローズドループでは、リクエスト率は入力ではなく結果です。サーバーが遅くなると、ユーザーが次のリクエストを出すのが遅れるので、リクエスト率が自然に下がり、そのためテストは、サーバーがどれだけ壊れても「よく持ちこたえている」という絵を描きます。

どう動くのか

到着過程は、「リクエストがいつ来るか」の形です。3つだけ知っていれば十分です。

形 間隔 変動係数(CV) どこで見られるか
一定間隔 常に1/リクエスト率 0 合成負荷テストのデフォルト
指数分布(ポアソン) 平均1/リクエスト率の指数分布 1 互いに独立した多数のユーザー
バースト 複数件が一度に来て、そのあと長い休み 1よりはるかに大きい cron・リトライストーム・通知の送信

変動係数は、間隔の標準偏差を平均で割った値です。平均リクエスト率が同じでも、この値が大きくなるほど、待ちが長くなります。待ち行列理論の近似式(Kingman)が示す方向も同じです。待ち時間は、利用率だけでなく、到着とサービスの変動性にも比例します。そのため、「利用率25%だから安全だ」という文は、到着の形を言わなければ、何の意味もありません。

クローズドループ側には、別の法則があります。ユーザーN人がリクエスト1つを送ってシンクタイムZだけ休み、応答時間がRなら、実効リクエスト率XはN / (R + Z)です。これは、リトルの法則を、ユーザー1人のラウンドトリップに適用した形で、ユーザー数とシンクタイムだけを決めれば、リクエスト率はサーバーが決めるという意味です。Rを抜かしてN / Zで予測すると、常に実際より高く出て、サーバーが遅いほど、その誤差が大きくなります。

k6のドキュメントは、この2つをエグゼキューター(executor)で分けて呼びます。リクエスト率を入力として渡す到着率エグゼキューターがオープンモデルで、仮想ユーザー数を渡すエグゼキューターがクローズドモデルです。どちらを使うかは、好みではなく、測りたい対象が何かで決まります。

現場での姿

最もよく見る事故は、リトライストームです。普段は均等に来ていたリクエストが、1回タイムアウトを出すと、クライアントが同じ瞬間に再試行するので、到着がバーストに変わります。平均リクエスト率は数パーセントしか増えていないのに、待ち行列が10倍になり、その待ちがまたタイムアウトを生みます。ジッターなしのリトライを禁止する理由が、ここにあります。

正時に目を覚ますバッチも同じです。cron式がすべて0 * * * *なら、1日の平均負荷は低くても、毎時正時の同時リクエスト数は、ワーカー数をはるかに超えます。こうしたサービスの容量は、平均ではなく、バーストの大きさで決める必要があります。

そして、テストツール側の事故がもう1つあります。到着率エグゼキューターでテストすべきサービスを、仮想ユーザー数でテストすると、サーバーが遅くなるときに負荷も一緒に減って、飽和点が見えません。レポートには「1秒あたり何件まで持ちこたえた」と書かれますが、その数字は、サーバーの限界ではなく、テスト設定の限界です。

そのため、負荷をドキュメントに書くときは、平均の隣に2つを一緒に書く必要があります。1つは到着の形で、均等なのか、互いに独立なのか、バーストなのか。もう1つは、バーストなら1回に何件かです。この2つがなければ、「1秒あたり25件」は、ワーカー数を決めるのに使えない数字です。観測からこの値を取り出す方法も単純です。アクセスログの時刻を短いウィンドウ(たとえば100ミリ秒)でまとめて数えてみると、均等なトラフィックはウィンドウごとに似た数が出て、バーストのトラフィックは、ほとんどが0で、いくつかのウィンドウだけが大きく跳ねます。その跳ねるウィンドウの大きさが、そのまま、容量計算に入れるべき数字です。

残る質問は、余裕をどれだけ置くかです。正解は、サービスが何を約束したかで決まります。ユーザーが待っているリクエストなら、バーストをそのまま受け止められるだけのワーカーを置く必要があり、裏で動く仕事なら、待ち行列を長く置いて、ゆっくり消化してもかまいません。重要なのは、その選択を測定したバーストの大きさの上で行うことであって、平均だけを見て行うことではありません。

次のラボですること

ワーカー数が決まっているサーバーを起動し、同じ平均リクエスト率で、一定間隔・指数分布・バーストの3つの到着を、自分で作って送ります。3つの計画の間隔の変動係数を測って、平均は同じで形だけが違うことを確認したあと、サーバーが記録した待ち行列の長さと応答時間の分布を比べます。続いて、クローズドループのジェネレーターを作って、シンクタイムが実効リクエスト率をどう決めるかを、法則と実測で突き合わせ、最後に、均等な到着を仮定した容量の見積もりが、実際のバーストの到着で何倍外れるかを数字で見せたあと、このサービスの到着モデルとワーカー数を、根拠とともに決めます。