ハードウェア中級 #9 実践:遅くなったサーバーを診断する — シリーズのまとめ

読了 6分

第8回 までで、リソースごとの部品がすべてそろいました。最後の記事では、その部品を 1 つのケースに当てはめてみます。運用現場でもっともよくある報告「サービスが遅いです」から出発し、原因の確定と処方の検証まで進む診断ウォークスルーです。シナリオは架空ですが、各段階の判断はシリーズで扱ったとおりです。

ステップ 0 — 症状を数字に変える #

報告が入りました。「午後から API がときどき数秒かかります」。診断の最初の一歩はサーバーに接続することではなく、症状を数字で定義すること です。

  • 何が: API 応答時間の 99 パーセンタイルが普段 0.3 秒 → 午後から断続的に 3〜5 秒
  • いつから: 14 時ごろから、数分おきに数十秒ずつ
  • 何ではないか: エラー率はそのまま、全体の平均はわずかに上昇

「断続的」と「テールレイテンシ」という 2 つの手がかりが、すでに方向を示しています。リソースが常時足りなければ症状も常時です。周期的なら、周期的な何か (バッチ、フラッシュ、バックアップ) があります。第1回 で普段の値の記録が重要だと述べた理由が、ここで早速生きます。「普段 0.3 秒」を知らなければ、比較そのものができません。

ステップ 1 — 4 つのリソースをひと通り見る #

第1回 の点検表どおり、使用率・飽和・エラーをリソースの順に見ていきます。

vmstat 5 (症状の時刻)
procs ---------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  9  10240 802340 211456 4.1e+07    0    0    52 91240 980 4100  9  6 41 44  0

この 1 行から読み取れることは多いです。

  • CPU: us 9、sy 6 で暇です。st は 0 なので 第2回 のスティールでもありません。ところが wa は 44 で、CPU が I/O を待って遊んでいます。
  • メモリ: si/so が 0 なのでスワップの流れはありません。第3回 の基準でメモリ不足ではありません。
  • 飽和: b 列 (I/O 待ちで眠っているタスク) が 9。ディスクの前に行列ができています。
  • bo (ブロック書き込み) が普段の数十倍です。誰かが突然大量に書いています。

ロードアベレージが高かったとすれば、その理由も説明がつきます。第1回 で見たとおり、Linux のロードには I/O 待ちが含まれるためです。4 つのリソースのうち ストレージの飽和 に絞り込めました。

ステップ 2 — ストレージにズームイン #

iostat -x でディスクの状態を見て、次に誰が書いているのかを探ります。

iostat -x 5 (該当ディスクのみ)
Device   r/s    w/s   wkB/s  aqu-sz  w_await  %util
nvme0n1  12.0  3100  364000   28.4     9.2     98.7

%util が 98.7、キュー長 (aqu-sz) が 28、書き込みレイテンシ (w_await) が 9.2ms です。第5回 で見たとおり、キューが積み上がるとレイテンシが上がります。普段 0.5ms 程度だった書き込みレイテンシが 20 倍近くに伸びたので、このディスクを待つすべてのリクエスト (DB のコミットを含む) が一緒に遅くなります。API のテールレイテンシと形が合います。

次は「誰が」です。書き込み急増の時間パターン (数分おき、数十秒) が 第3回 のダーティページのフラッシュに似ています。確認してみると、14 時にデプロイされた新機能が大容量のログをバッファード I/O で書き始めており、たまったダーティページをカーネルが周期的に一気に書き下ろしてディスクを飽和させていました。仮説ではなく確認です。ダーティページの量 (/proc/meminfo の Dirty) がフラッシュの直前ごとに数 GB までふくらむことを指標で確定しました。

ステップ 3 — 処方、そして再測定 #

処方は層ごとに複数あり得ます。安くて確実なものから進めます。

  1. 原因の除去 (アプリケーション) — ログを同じディスクに書かないよう分離するか、書き込みの量そのものを減らします。根本的な処方です。
  2. 緩衝の調整 (カーネル) — 分離がすぐには難しければ、ダーティ比率を下げて「少しずつ頻繁に」書き下ろさせます。急増の規模を抑える対症的な処方です。
  3. リソースの増設 (ハードウェア) — 書き込み IOPS が常時足りないのならディスクの増設が答えですが、この事件は常時不足ではなく急増なので、増設は過剰です。

1 番を適用し、ステップ 0 の数字で再測定 します。99 パーセンタイルが 0.3 秒に戻り、wa とディスクのキューが普段の水準なら終了です。症状の定義を数字でしておいたおかげで、「直った気がする」ではなく「直った」で閉じられます。

診断の一般形 #

シナリオは 1 つでしたが、手順は一般形です。

  1. 症状を数字で定義します (何が、いつから、何ではないか)。
  2. 4 つのリソースを使用率・飽和・エラーで見て、1 つのリソースに絞り込みます。
  3. そのリソースにズームインし、誰が・なぜを指標で確定します。
  4. 安くて確実な処方から適用し、ステップ 0 の数字で再測定します。

別の結末でも道は同じです。st が高ければ第2回の移行の処方へ、si/so が動いていれば第3回のメモリ診断へ、ノードの偏りなら第4回の NUMA へ、経路の断絶なら第7回のマルチパスへ分かれるだけです。

最後に、チューニングの原則を 1 つ、シリーズの結論として残します。カーネルパラメータは診断の出発点ではなく終着点です。sysctl のつまみ類は、原因が指標で確定した後に、一度に 1 つずつ、前後の測定とともに触る道具です。測定なしにインターネットのチューニング集を適用するのは診断ではなく宝くじです。具体的なつまみ類は RHEL 上級 #2 が扱います。

よく出会う落とし穴 #

  • サーバーに先に入り、症状の定義を後回しにする — 数字のない診断は「再起動したら良くなった気がする」で終わります。症状の定義がステップ 0 です。
  • 最初の仮説に居着く — wa を見て「ディスクが老朽化した」へ飛ぶと、増設で終わって原因 (書き込みの急増) は残ります。誰が・なぜまで指標で確定します。
  • 直して測り直さない — 処方後の再測定がなければ、次の事件のときに同じ診断を最初からやり直します。前後の数字を記録に残します。

まとめ — シリーズを閉じながら #

9 編を振り返るとこうなります。

  • すべてのリソースに使用率・飽和・エラーを問い、体感を作るのは飽和です (第1回)。
  • CPU はクロックの気まぐれとスティールを (第2回)、メモリは available とダーティページと cgroup の上限を (第3回)、マルチソケットでは NUMA を見ます (第4回)。
  • ストレージは条件をそろえて実測し (第5回)、RAID は死んだ後を設計し (第6回)、ネットワークの向こうのディスクは経路の二重化を確かめます (第7回)。
  • GPU は 5 番目のリソースですが、供給は依然として 4 つのリソースの仕事です (第8回)。
  • そして診断はいつでも症状の数字による定義から始まり、再測定で終わります (第9回)。

ハードウェア基礎 が「遅い」と「高い」を推測から診断の対象に変えるシリーズだったなら、中級はその診断を実際にやり遂げる実践力を身につけるシリーズでした。これからは指標の前で道に迷わないことを願っています。ここまでご一緒いただき、ありがとうございました。

X