大量のアクセスが来た時にサーバーで何が起きているのか

この記事は [レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku) の15日目の記事となります。 

こんにちは。株式会社レコチョクの望月です。普段は主にフロントエンド領域の開発をしています。
音楽はいろんなジャンルをかじって聞くことが多いのですが、最近はCö shu Nieをよく聴いています！

## サーバーが高負荷状態になっているというアラートがあった

サーバーに入れている監視設定により、CPU使用率とロードアベレージが高くなっているアラートがありました。
確認したところ、原因は一度に多くのアクセスが来ていたためのようでした。

一度に大量のアクセスが来ると負荷が高くなる、というのはなんとなくわかる…。
ですが、実際何がどう作用して負荷が高くなるの？というところがわかっておらず、原理のわかっていないアラートに怖いなという気持ちが出てしまったので、大量のアクセスによって高負荷状態になる時にサーバーではどのようなことが起きているか、噛み砕いて確認していきたいと思います。

## アクセスが来た時の処理の流れ

まずブラウザからアクセスが来た時の処理の流れは以下のようになります。

1. ドメイン名から取得したIPアドレスに対してサーバーとの接続を確立する

2. 接続確立後、HTTPS(またはHTTP)でサーバーへリクエストを送信する

3. サーバーでリクエストを受け取り、リソースを処理する準備をする

4. 動的なページである場合、リクエストがWebサーバーからアプリケーションサーバーに渡され、ページの生成が行われる

5. アプリケーションサーバーで実行した結果がWebサーバーを通じてユーザーに送信される

6. ブラウザがHTMLを解析し、CSSやJS、画像などのリソースを追加でダウンロードし、画面を描画する

## アラートが出ていたもの

### CPU使用率

- 一定の時間に対してどれだけCPUが稼働したかの割合を示すもの
- 0%であれば全く稼働していない、100%であればフル稼働しており新しい処理を受け付ける余裕はない状態

### ロードアベレージ

- 1つのCPUに対して割り当てられた実行中、または実行待ちのプロセスの平均数を示すもの
- ロードアベレージが「2」の場合、2つのプロセスが同時に実行中、または実行待ちの状態
- 基準として、CPUが1コアなら1未満、2コアなら2未満であれば問題ないと考えられる

## 高負荷状態になるとは

大量のアクセスが来た時に高負荷状態になるというのは、 **「リクエストの量に対して、CPUの処理能力が追いつかなくなってきている状態」** です。

### CPUの処理について

CPUでの処理について、どのように行われているかもう少し突っ込んで確認してみたいと思います。
まず、サーバーはリクエストを受け取った時、そのリクエストごとに1つの **「スレッド」** を割り当てます。
**「スレッド」** とは実行される処理の最小単位です。
スレッドはCPUの **「コア」** によって実行されます。
**「コア」** はCPUで物理的に計算を行う部分のことです。
CPU内のコアは独立しており、それぞれで異なるスレッドを同時に処理することができます。

例えば、「4コア4スレッド」のCPUの場合、サーバーが同時に処理できるリクエストは最大で4つ、「4コア8スレッド」のCPUの場合は最大で8つになります。

### キューについて

このように、性能により量は異なりますが、CPUが一度に処理できる量には限界があります。

それでは、その限界以上のリクエストが来た時どうなるかというと、あふれたリクエストは **「キュー」** (待ち行列)に入り処理の順番待ちをすることになります。

しかし、キューは無制限にリクエストを待機させておけるかというとそんなことはなく、 **「保持時間」** と **「容量」** の制限があります。

保持時間を超えた場合エラーレスポンスを返し、かつキューに入っていたリクエストは削除されます。

容量を超えた場合もエラーレスポンスを返しますが、リクエストが来た時点でもう新しいリクエストを受け付けられないことがわかっているため、即座にエラーを返します。

### メモリについて

また、これらの処理を支えているのが **「メモリ」** です。
CPUでの処理もキューの格納も、全てメモリ上で行われます。
大量のリクエストが同時に来ると、それだけ対応するプロセスやスレッドが増えることでメモリの使用量が増加します。

メモリが不足すると、OSは一部のデータを **「スワップ領域」** というところに避難させます。
スワップ領域はメモリが足りなくなった時に補助としてHDDやSSDなどストレージ上に作成されます。

しかしストレージはメモリと比べるとアクセス速度がとても遅く、スワップ領域を利用すると処理速度の低下につながります。
その他にも、メモリ不足になるとメモリ上のキューの容量が圧迫されて新しいリクエストを保持できなくなりエラーが返る割合が高くなります。

リクエストが多すぎて全てを正常に処理できず、処理遅延が発生している、キューにも入れずエラーが返っているなどの状態が **「リクエストの量に対して、CPUの処理能力が追いつかなくなってきている状態」** です。

## サーバーが落ちる(停止する)のはなぜか

キューの制限を超えたためにエラーレスポンスが返る場合、制限を超えた一部のリクエストにはエラーが返る一方で、一部のリクエストは処理が続けられるため正常なレスポンスが返る、という状態になります。

この状態だと処理しきれなかったリクエストに対してはエラーが返りますが、サーバーが停止しているわけではないため、できる範囲で処理が続行されます。
この仕組みがあるならギリギリサーバーは処理を続けられるのではないか？と思ったのですが、「アクセス集中でサーバーが停止する」ということもよく聞きくかと思います。

負荷が高くなった結果、システムがCPUやメモリなどのリソースを適切に管理することができなくなり、処理を行うために必要なリソースを確保できずパフォーマンスが低下します。
(メモリ不足によりスワップ領域への避難をした結果処理速度が落ちることもパフォーマンス低下の一例です)

その状態が続いた結果、リソースの過剰消費を回避するための仕組みも間に合わなくなり、最終的には応答しない、停止するなどの状態につながるようです。

## 最後に

実際に上がったアラートをもとに、大量のアクセスが来た時どのようにして高負荷状態になっているか、少し具体的にできたかと思います。

実際に負荷対応を行う際には、システム内部で正常に動作していない箇所（ボトルネック）を特定し、それに対して適切な調整（チューニング）を行うことが大切です。

また、負荷状態になった原因や状態によっては今回確認した箇所以外にも合わせて検討・調整していかなければならないところもあり、まだまだ奥が深いなと思うばかりです。

少しでも「負荷状態」の状況を具体的に把握できるようになることで、もしものトラブル発生時にも落ち着いて原因を切り分けて対応ができると良いなと思います。

## 参考

[新人エンジニアが知っておきたいサーバ負荷の考え方](https://qiita.com/ichimura/items/0d11dbc9739aa9e9db78)
[【解説】アクセス集中時にシステム障害が起こる理由とは？](https://queue-it.com/jp/blog/how-high-online-traffic-can-crash-your-website-jp/)

明日の [レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku) は16日目「PerplexityのChrome拡張機能が便利」です。お楽しみに！

この記事はレコチョクのエンジニアブログの記事を転載したものとなります。 
 
https://techblog.recochoku.jp/11343