ブログ一覧

「CPUはまだ80%」は大丈夫なのか

· 約9分で読めます

容量の見積もりに要る式は4つで、どれも掛け算と割り算で済む。ピーク時に毎秒3,000件が届くAPIを例に、台数・余力・接続数を順に決めていく。

平均だけでは、容量は決まらない

平均のQPSに平均のレイテンシを掛けて「足りている」と判断するのは、よくある失敗だ。障害が起きるのは平均の時間帯ではない。ピークの数分間、遅いほうの1%、AZが1つ落ちた瞬間に起きる。

この記事では、ひとつのAPIについて、同時処理数、台数、余力、接続数の順に見積もる。

リトルの法則は、3通りに使える

安定したシステムでは、中にある件数の平均Lは、到着率λと1件の滞在時間Wの積になる(L = λ × W)。中身がキューでもサーバーでも成り立つので、どの段にも当てはめられる。

知りたいこと式例
必要な同時処理数L = λ × W毎秒500件 × 0.1秒 = 50件
上限から決まる到着率λ = L ÷ Wプール100 ÷ 0.2秒 = 毎秒500件
列の長さから見た待ち時間W = L ÷ λ列500件 ÷ 毎秒1,000件 = 0.5秒

2行目が特に役に立つ。プール100で応答100msなら毎秒1,000件まで受けられるが、DBが遅くなって200msになると、トラフィックは同じなのに受けられる量が半分になる。プールが詰まる障害は、この式で説明できる。

利用率と待ち時間は、曲線の関係にある

リクエストの到着にはばらつきがある。利用率が上がるほど、前の処理がまだ終わっていない瞬間が増え、待ちが生まれる。いちばん単純なモデル(M/M/1)では、処理時間をS、利用率をρとすると、平均の応答時間は S ÷ (1 − ρ) になる。

処理時間10msのサーバーの平均応答時間(M/M/1)
  • 利用率50%: 20 ms
  • 利用率70%: 33 ms
  • 利用率80%: 50 ms
  • 利用率90%: 100 ms
  • 利用率95%: 200 ms

同じ10ポイントの上昇でも、効き方がまるで違う。50%→60%では20msが25msになるだけだが、85%→95%では約67msが200msになる。遅くなる量は約27倍だ。

台数を決める

ピーク時に毎秒3,000件が届き、1件あたりのCPU時間が20msのAPIを考える。

  1. 必要な処理量: 3,000 × 0.02秒 = 60コアが常に埋まる量。
  2. 目標の利用率で割る: 上限を60%とすると、60 ÷ 0.6 = 100コア。
  3. AZ障害に備える: 3つのAZのうち1つが落ちても残りで100コアを持つには、各AZ50コア、合計150コア。

150コアだと、平常時のピークでも利用率は40%しかない。障害の間だけ80%まで許すなら、残り2つのAZに75コアあればよく、合計114コアで済む。

AZが1つ落ちたときの利用率(3つのAZで運用)
  • 100コア(余力なし): 90%(応答は約4倍)
  • 114コア(障害時は80%まで許す): 約79%
  • 150コア(障害時も60%を保つ): 60%

150と114のどちらを選ぶかは、技術では決まらない。障害中にどこまで遅くなってよいかという合意の問題だ。

平均ではなく、遅いほうの1%を見る

複数のバックエンドに並列で問い合わせ、全員の応答を待つ処理では、遅い1台が全体を遅くする。1台が遅い確率をp、台数をnとすると、遅くなるリクエストの割合は 1 − (1 − p)^n だ。

各サーバーが1%の確率で遅いとき、遅くなるリクエストの割合
  • 1台に問い合わせ: 1%
  • 10台に並列: 9.6%
  • 100台に並列: 63%

逆算すると、もっと厳しい。100台にファンアウトして全体の遅いリクエストを1%に抑えるには、1台あたりの遅い確率を約0.01%にする必要がある。全体のp99を守るには、各シャードのp99.99が同じ目標に収まっていなければならない。

接続数を決める

DBから見た接続数は、台数 × プロセス数 × プールの大きさだ。アプリを横に増やすと、掛け算で増える。

DBへの接続数(各台のプール20、DBの上限500)
  • 平常時 10台: 200
  • デプロイ中 新旧で20台: 400
  • セールの日 40台: 800(上限超え)

プールの大きさもリトルの法則で見積もれる。1台に毎秒250件が届き、1件が接続を8ms握るなら、使うのは平均2本。DBが5倍遅くなっても10本で足りる。プールを20にしても、効くのはDBがすでに遅いときだけで、そのとき同時のクエリを増やすとDBはさらに遅くなる。

上限はDBの側から決める。HikariCPのWikiは「DBのコア数 × 2 + ディスク数」を出発点に挙げていて、16コアなら30本強だ。40台のアプリで分けると1台1本にも満たないので、台数が大きく変わる構成では、PgBouncerやRDS Proxyのような接続のプロキシを間に置く。

1枚の見積もりシート

項目式この記事の例
同時処理数ピークの到着率 × p99の処理時間500 × 0.2秒 = 100
必要な処理量ピークの到着率 × 1件のCPU時間3,000 × 20ms = 60コア
台数必要な処理量 ÷ 目標の利用率60 ÷ 0.6 = 100コア
AZ障害の余力台数 × AZ数 ÷ (AZ数 − 1)100 × 3 ÷ 2 = 150コア
ファンアウトのテール1 − (1 − p)^np = 1%、n = 100 → 約63%
DBへの接続数最大台数 × プロセス数 × プール40 × 1 × 20 = 800

面接での使い方

式を先に書いてから数字を入れると、面接官が途中で前提を確かめやすい。

最後の一文のように、余力の値段と、それを下げる選択肢まで自分から出すと、数字を覚えているのではなく、トレードオフで決めていることが伝わる。

この記事で深掘りしたTips