2026年9月3日
2026年9月3日
Apacheのプロセス数・スレッド数のチューニング|メモリから上限を決める手順
Apacheのプロセス数・スレッド数は、「同時に処理できるリクエスト数の上限(MaxRequestWorkers)」を、サーバーのメモリに収まる範囲で決めるのが基本です。値を大きくすれば速くなるわけではなく、メモリを超えるとスワップやOOM Killerでかえってサイトが止まります。この記事では、使っているMPMの確認、1プロセスあたりのメモリの測り方、MPMごとの設定例、上限に達しているかの見分け方を、WordPressサーバーを例に説明します。
まず使っているMPMを確認する
Apacheは、リクエストをどう並行処理するかをMPM(Multi-Processing Module)で切り替えます。設定すべきディレクティブがMPMによって変わるため、最初に確認します。
sudo apachectl -V | grep -i mpm
# 例: Server MPM: event
- prefork: 1リクエストを1プロセスで処理する。スレッドを使わないため、スレッドセーフでないPHP(mod_php)と組み合わせる場合はこれになる。1プロセスのメモリが大きい。
- worker: 複数のプロセスがそれぞれ複数のスレッドを持つ。メモリ効率がよい。
- event: workerを発展させたもの。Keep-Aliveで待機している接続を専用のスレッドがまとめて管理するため、待機中の接続が処理用スレッドを占有しにくい。
WordPressでは、PHP-FPMとevent MPMを組み合わせる構成が、主要ディストリビューションで一般的です(2026年10月現在)。mod_phpを使っている場合はpreforkのままになるので、まずはその前提で上限を決め、余裕ができたらPHP-FPMへの移行を検討するとよいでしょう。
主要なディレクティブの意味
名前が似ていて混乱しやすいので、役割で整理します。
| ディレクティブ | 役割 | 主なMPM |
|---|---|---|
MaxRequestWorkers |
同時に処理できるリクエスト数の上限(旧名 MaxClients) | 共通 |
ServerLimit |
起動できる子プロセス数の上限 | 共通 |
ThreadsPerChild |
1つの子プロセスが持つスレッド数 | worker / event |
ThreadLimit |
ThreadsPerChild に設定できる値の上限 | worker / event |
MinSpareThreads / MaxSpareThreads |
待機スレッドの最小・最大 | worker / event |
MinSpareServers / MaxSpareServers |
待機プロセスの最小・最大 | prefork |
MaxConnectionsPerChild |
子プロセスが処理する接続数の上限。超えると入れ替わる(旧名 MaxRequestsPerChild) | 共通 |
worker/eventでは、MaxRequestWorkers は ServerLimit × ThreadsPerChild 以下でなければなりません。超えた値を書くと、Apacheが起動時に警告を出して自動的に値を切り下げます。preforkでは ServerLimit の既定が256なので、MaxRequestWorkers を256より大きくしたい場合は ServerLimit も上げます。
もう1つの注意点として、ServerLimit と ThreadLimit の変更は graceful restart(reload)では反映されず、Apacheを停止して起動し直す必要があります。
1プロセスあたりのメモリを測る
上限の決め方の中心は「使えるメモリ ÷ 1つあたりのメモリ」です。推測ではなく、実際に動いている環境で測ります。ある程度アクセスがある時間帯に計測すると、現実に近い値が取れます。
# Apache の子プロセス数と平均RSS(Debian/Ubuntu は apache2、RHEL系は httpd)
ps -o rss= -C apache2 | awk '{s+=$1; n++} END {printf "%d procs, avg %.1f MB\n", n, s/n/1024}'
# PHP-FPM を使っている場合はワーカーのメモリも測る(プロセス名は環境で異なる)
ps -eo rss,comm | grep php-fpm | awk '{s+=$1; n++} END {printf "%d procs, avg %.1f MB\n", n, s/n/1024}'
# サーバー全体のメモリ
free -m
RSSには共有メモリ分も含まれるため、合計すると実際の使用量より大きめに出ます。上限を決める用途では、大きめに見積もるほうが安全側に倒れるので、そのまま使って構いません。
使えるメモリの見積もり
サーバーのメモリから、OS、MySQL/MariaDB、キャッシュ系のサービス(Redisなど)が使う分を引き、さらに1〜2割の余裕を残した残りが、Webサーバーとして使える量です。
たとえばメモリ4GBのVPSで、OSと常駐サービスに0.5GB、MySQLに1GB、余裕を0.5GB残すと、使えるのは約2GBです。
preforkの場合(mod_php)
preforkでは、1プロセスの中でPHPも動くため、1プロセスあたり数十MBになるのが普通です。平均60MBなら、2GB ÷ 60MB ≒ 34 なので、MaxRequestWorkers は30前後が目安になります。
# Debian/Ubuntu: /etc/apache2/mods-available/mpm_prefork.conf
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 30
MaxConnectionsPerChild 1000
</IfModule>
MaxConnectionsPerChild を0(無制限)ではなく1000程度にしておくと、プラグインのメモリリークなどで太ったプロセスが定期的に入れ替わります。値が小さすぎるとプロセスの作り直しが増えて負荷になるので、数百〜数千の範囲で様子を見ます。
eventの場合(PHP-FPM)
event + PHP-FPMの構成では、Apacheのスレッドは静的ファイルの配信とPHP-FPMへの受け渡しをするだけなので軽く、メモリの大部分はPHP-FPMのワーカーが使います。そのため、考える順番は次のようになります。
- PHP-FPMの
pm.max_childrenを「使えるメモリ ÷ PHPワーカー1つのメモリ」で決める。 - Apacheの
MaxRequestWorkersは、静的ファイルやKeep-Alive中の接続も扱えるよう、PHP-FPMの同時処理数より多めにする。
# Debian/Ubuntu: /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
StartServers 2
ServerLimit 8
ThreadsPerChild 25
ThreadLimit 64
MinSpareThreads 25
MaxSpareThreads 75
MaxRequestWorkers 200
MaxConnectionsPerChild 0
</IfModule>
この例では 8 × 25 = 200 なので、MaxRequestWorkers 200 は上限内に収まっています。Apacheのスレッドをいくら増やしても、PHP-FPMのワーカーがすべて埋まっていれば、PHPのリクエストはPHP-FPM側で順番待ちになります。PHPの処理が詰まっているのに Apache 側だけを増やしても改善しない、という点がよくある誤解です。
RHEL系では、MPMの選択は /etc/httpd/conf.modules.d/00-mpm.conf、値の設定は /etc/httpd/conf.d/ に置く独自の設定ファイルで行うのが一般的です。
上限に達しているかを見分ける
チューニングが必要かどうかは、症状とログで判断します。
# 上限到達の記録(RHEL系は /var/log/httpd/error_log)
sudo grep -i "MaxRequestWorkers" /var/log/apache2/error.log
# mod_status でビジー/待機中のワーカー数を見る(サーバー内部から)
curl -s "http://localhost/server-status?auto" | grep -E "BusyWorkers|IdleWorkers"
# メモリ不足でプロセスが強制終了されていないか
sudo journalctl -k | grep -i "out of memory"
エラーログに「server reached MaxRequestWorkers setting」という行があり、そのときサーバーのメモリに余裕があったなら、上限を少しずつ引き上げます。逆に、OOM Killerの記録がある、スワップが常に使われている、という場合は上限が大きすぎるので下げます。
BusyWorkers が常に上限近くに張り付いているのに、CPUもメモリも余っていない場合は、プロセス数ではなくPHPの処理そのもの(重いプラグイン、遅いデータベースクエリ、外部APIの待ち)が原因のことが多いです。その場合はページキャッシュやオブジェクトキャッシュを入れるほうが、同時処理数を増やすより効果が出やすくなります。
変更の進め方
設定ファイルはバックアップしてから編集し、本番の前にステージング環境で負荷をかけて確認します。
sudo cp /etc/apache2/mods-available/mpm_event.conf ~/mpm_event.conf.bak
sudo apachectl configtest
# ServerLimit / ThreadLimit を変えたときは restart、それ以外は reload で可
sudo systemctl restart apache2
負荷試験は、ab(ApacheBench)などのツールを使い、自分が管理するステージング環境に対してだけ行います。同時接続数を段階的に上げながら、応答時間、エラー率、free -m の空きメモリを並べて記録すると、そのサーバーで安全に処理できる上限が見えてきます。値は一度で決めず、アクセスの多い時期やプラグイン追加の後に計測し直すのがおすすめです。
まとめ
- 最初に
apachectl -VでMPMを確認する。mod_phpならprefork、PHP-FPMならeventが一般的。 - 上限は「使えるメモリ ÷ 1プロセス(またはPHPワーカー)のメモリ」で決め、実測したRSSを使う。
- worker/eventでは
MaxRequestWorkers ≤ ServerLimit × ThreadsPerChild。ServerLimitとThreadLimitの変更には restart が必要。 - PHP-FPM構成では
pm.max_childrenが実質的な上限。Apache側だけ増やしても詰まりは解消しない。 - エラーログの MaxRequestWorkers の記録、mod_status、OOMの記録を見て増減を判断し、キャッシュ導入も合わせて検討する。