CPUもメモリも余っているのにサイトだけが返ってこず、どこで詰まっているのかを落ち着いて確かめようとしている一人運用の保守担当者

リクエストが詰まって返らない|ワーカー枯渇の見つけ方と一次対処

「サイトがまったく返ってきません」と連絡が入って、あわててサーバーに入る。ところが top を見ても CPU はスカスカ、メモリにも余裕がある。ディスクも埋まっていない。なのに、ブラウザで開くとぐるぐる回ったまま返ってこない——保守運用をしていると、この「リソースは余っているのに詰まっている」という状況に一度は出くわしますよね。

数字が正常だと、どこを見ればいいのか分からなくなります。でも、こういうときに疑いたいものがひとつあります。受け口(ワーカー・スレッド)の枯渇です。サーバーは「同時に何本まで処理を受けるか」という上限を持っていて、その席がすべて埋まると、あとから来たリクエストは待たされるだけになります。席が埋まっているだけなので、CPU もメモリも忙しくは見えません。

この記事では、この「受け口が埋まって詰まる」状態を、見つけ方 → 犯人の探し方 → 安全な一次対処の順で一緒に整理します。構成(Apache、nginx+php-fpm、アプリサーバー+DB など)で見る場所は変わりますが、考え方はそのまま使えます。

結論:リソースに余裕があるのにサイトが返らないときは、同時処理数の上限(受け口)が埋まっていないかをまず見ます。手順は、①ワーカーの使用数と待ち行列を見る(何席中、何席が埋まっているか) → ②埋めている処理の中身を見る(どの画面・どの処理が長く居座っているか) → ③一次対処は「上限を上げる」より先に「詰まりの元を止める」。上限を上げるのはメモリと引き換えの応急処置で、遅い処理をそのままに数字だけ増やすと、席が増えたぶんメモリを食い尽くして別の障害に化けることがあります。

何が起きているか:CPUが暇でも「席」は埋まる

Web サーバーやアプリサーバーは、リクエストを無制限に受けるわけではありません。「同時にここまで」という受け口の数が決まっています。呼び方は構成によって違いますが、役割は同じです。

大事なのは、この席は「処理が終わるまで」返ってこないということです。だから、次の式のような関係になります。

ここが「CPU が暇なのに詰まる」の正体です。遅い処理の大半は、CPU を使って計算しているのではなく、何かを待っているからです。DB の応答待ち、外部 API の応答待ち、ロックの解放待ち——待っている間、席は占有されたままなのに、CPU はほとんど働いていません。だから top は静かなのに、受け口だけが満席になります。

そして満席になると、あとから来たリクエストは順番待ちの列に並びます。列が伸びるほど待ち時間は長くなり、やがて手前のプロキシがしびれを切らして 502・504 を返す——という形で表に出てきます。

つまり、詰まりの本当の原因は「席の数が足りない」ことではなく、席に長く座り続けている処理がいることのほうが多いのです。次から、その席の埋まり具合を確かめる順番を見ていきます。

詰まりを見つける順番:席 → 列 → 中身

窓口の席がすべて埋まり、後ろに順番待ちの列ができている様子で、ワーカー枯渇によってリクエストが待たされる状態を表した図
席(ワーカー)が埋まると、あとから来たリクエストは列に並んで待つだけになる

順番はシンプルです。いま何席埋まっているか(席)→ どれくらい待たされているか(列)→ 誰が座っているか(中身)。この順で見ると、上限を触るべきか、処理を直すべきかが見分けられます。

① 何席中、何席が埋まっているかを見る

まずは「本当に満席なのか」を確かめます。ここが分からないまま設定をいじると、当てずっぽうになります。

見るポイントは、上限に対して何割埋まっているかです。「たまに8割」なら余裕あり。「ずっと10割に張り付き」なら、すでに満席で列ができています。

② 待ち行列ができているかを見る

満席かどうかと同じくらい大事なのが、あとから来たリクエストが待たされているかです。

ここでひと呼吸。数字が正常なのに障害が起きていると、「自分が見落としているだけでは」と不安になりますよね。でも、CPU もメモリも正常なのに詰まるというのはよくある型で、あなたの見落としではありません。見る場所が一つ違っただけです。

③ 席に座り続けている「中身」を見る

満席と分かったら、誰が長く居座っているかを見ます。ここが分かると、対処が「数字いじり」から「原因つぶし」に変わります。

よくある居座りの正体は、だいたいこのあたりです。

具体例:「CPUは10%なのにサイトが返らない」を追う

よくある一件を、順番に切り分けてみます。

もしここで「とりあえず pm.max_children を10から50に増やす」だけをしていたら、一時的には返るようになったかもしれません。でも、1子プロセスあたりのメモリ × 50 がメモリを超えれば、今度はメモリ不足でプロセスが落ちる障害に化けます。席を増やす前に「誰が座っているか」を見られたから、次に効く直し方にたどり着けました。

影響:見る場所を1つ足すだけで、何が変わるか

「リソースは正常なのに返らない → 受け口を疑う」という一手を持っておくと、直す力そのものより先に、迷う時間が減ります

逆に、毎回「上限を上げる」だけで乗り切っていると、席とメモリの綱引きが少しずつ苦しくなり、ある日まとめて効いてきます。見る順番は、その日の自分を助ける道具です。

明日やること:自分の現場の「席の数」を1枚に書く

障害のときに調べ始めると、どうしても遅くなります。明日できる、いちばん小さな一歩はこれです。

  1. 自分が担当するサーバーで、受け口の上限値を書き出す。php-fpm の pm.max_children、Apache の MaxRequestWorkers、アプリサーバーのワーカー数、DB の max_connections。分からないものは「未確認」と書くだけでも十分です。
  2. いまの使用数を1回だけ見て、横に書き添える(「10席中、平常時は2〜3席」など)。これが平常値になり、次に見たときの比較対象になります。
  3. ステータスの見方を1行メモする。php-fpm なら pm.status_path のURL、Apache なら server-status のURL、DB なら SHOW PROCESSLIST;障害中に調べ直さなくていい状態にしておくのが目的です。
  4. まだ有効にしていなければ、php-fpm のステータスと slowlog(またはアプリの遅延ログ)を検証環境で試してから有効にする。ステータス画面はアクセス制限をかけてから公開設定にします。
  5. アクセスログに応答時間が出ていなければ、出す設定を検討する。次の詰まりのとき、時刻の特定が一気に楽になります。

きれいな資料でなくて大丈夫です。「何席あって、普段は何席使っていて、どこで見られるか」の3行があるだけで、次の自分(や引き継ぐ人)が、正常な数字の前で立ち尽くさずに済みます。

ワーカー枯渇チェックリスト

「リソースは正常なのに返らない」ときに確認する項目です。コピーして、自分のメモに当ててみてください。全部を毎回そろえる必要はありません。

まず外せない最低ラインはこの3つです。急いでいても、ここだけは押さえます。

次の項目は、手前で片づかないとき・原因が奥にありそうなときに追加で確認します。当てはまらなければ飛ばして大丈夫です。

全部に○が付かなくても大丈夫です。最低ラインの3つ、とくに「上限を上げる前に、誰が座っているかを見る」さえ押さえられれば、数字を大きくして様子を見るより、ずっと確かな一歩になります。

よければ、こちらも

受け口の詰まりは、5xx や「サイトが重い」と地続きです。近い切り分けを対にしておくと、次の一件がだいぶ軽くなります。

詰まっていた処理を止めてサイトが正常に戻ったことを画面で確認し、肩の力が抜けた保守運用の担当者

「リソースは全部正常なのに、サイトだけが返らない」——この状況がこわいのは、頼りにしている数字が何も教えてくれないからです。でも、サーバーには数字に出にくい「席の数」があって、そこが埋まっているだけ、ということがよくあります。席の埋まり具合を見る場所を1つ知っておくだけで、霧はかなり晴れます。

多くの場合、サーバー全体が壊れているのではなく、ただ一つの重い処理が、席を長く占有していただけです。今日は、自分の現場の「席の数」を3行メモしてみるところからで十分です。その3行が、次の「返ってきません」を、手探りではなく手順に変えてくれます。

ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。

関連用語