はじめに
AWS の t2.micro の魅力と WordPress 運用における挑戦
こんにちは、KUDs です。
本記事では、AWS EC2 の t2.micro インスタンスを用いた WordPress 運用について記載します。
t2.micro インスタンスは、AWS の12か月の無料利用枠に含まれています。
そのため、低コストでクラウド上に環境構築ができ、多くの人が利用しているかと思います。
コンピューティング
無料利用枠
12 か月間無料
Amazon EC2
750 時間/月
クラウド内でサイズ変更可能なコンピューティング性能。https://aws.amazon.com/jp/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=all&awsf.Free%20Tier%20Categories=all
- リージョンに応じて、750 時間/月の Linux、RHEL、SLES t2.micro または t3.micro インスタンス
- リージョンに応じて、750 時間/月の Windows t2.micro または t3.micro インスタンス
もちろん、EC2 上で WordPress などのウェブアプリケーションを運用できます。
そのため、新規にウェブサイトを始める方にとって、非常に魅力的な選択肢となっています。
しかし、無料枠で利用可能な t2.micro は、1GB のメモリしか提供していません。
そのため、WordPress を運用する際にはリソースの管理が非常に重要となります。
特に、Web サーバである Apache の設定は、サイトのパフォーマンスと安定性に大きな影響を与えます。
よって、Apache の適切な設定と最適化が求められます。
以前の記事の振り返りと今回の目的
上記の記事では、t2.micro インスタンスで WordPress を運用する上で遭遇した、メモリ不足による OOM キラーの発生を確認しました。
※OOM: OutOfMemory
また、top コマンドで、メモリの大部分が httpd プロセスによって食いつぶされていることを確認しました。
top - 05:03:06 up 2:18, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 109 total, 1 running, 65 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.3 st
KiB Mem : 975596 total, 113940 free, 772996 used, 88660 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 86752 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3332 apache 20 0 708148 78772 10428 S 0.0 8.1 0:33.51 httpd
3084 apache 20 0 707876 78676 10428 S 0.0 8.1 0:33.41 httpd
3340 apache 20 0 707876 78660 10428 S 0.0 8.1 0:32.90 httpd
3621 apache 20 0 937276 78640 10584 S 0.0 8.1 0:20.39 httpd
3614 apache 20 0 707840 78624 10584 S 0.0 8.1 0:19.77 httpd
3634 apache 20 0 707688 78464 10436 S 0.0 8.0 0:20.78 httpd
3635 apache 20 0 707828 78460 10436 S 0.0 8.0 0:20.93 httpd
3323 apache 20 0 707972 78416 10428 S 0.0 8.0 0:33.07 httpd
3339 apache 20 0 707828 78308 10428 S 0.0 8.0 0:33.66 httpd
3314 apache 20 0 707852 78296 10428 S 0.0 8.0 0:33.13 httpd
3167 root 24 4 641736 54932 5532 S 0.3 5.6 0:39.20 aws
2971 root 20 0 520032 18424 11796 S 0.0 1.9 0:00.43 httpd
3243 root 20 0 723848 10300 2940 S 0.0 1.1 0:00.28 ssm-agent-worke
3166 root 20 0 255592 9004 3224 S 0.0 0.9 0:00.39 rsyslogd
また、それに対する一時的な対応策としてのスワップ領域の作成について紹介しました。
しかし、その対策はあくまで一時的なものです。
そもそも、スワッピングを頻繁に行うことはパフォーマンスの低下につながります。
スワップ領域を確保しても、慢性的にメモリ使用率が高い場合、その他のアプローチが必要です。
例えば、インスタンスタイプをアップグレードし、メモリを増強することも常套手段です。
しかし、もちろん費用は上がりますし、無料利用枠も対象外となります。
本記事では、この問題に対してメモリ使用率を下げるための根本的な解決を図ります。
具体的には、Apache MPM と PHP-FPM の設定を最適化し、メモリ使用率を改善します。
これによって、OOM の発生を防ぎ、t2.micro インスタンスで快適に WordPress を運用できる環境を作ることが目標となります。
本記事のゴール
まず、先に結果を見ておきましょう。
上記は、CloudWatch Agent で収集した EC2 のメトリクスです。
オレンジ色の線が メモリ使用率(mem_used_percent)です。
まず、Apache 最適化前(前半)はメモリ使用率が 80% を超えています。
一方、Apache 最適化後(後半)はメモリ使用率が 40% 程度に低下しています。
今回の記事では、上記のように メモリ使用率を低下させることを目的としています。
もちろん、設定次第でメモリ使用率を何 % まで下げるかはコントロールできます。
但し、必要以上に下げるとパフォーマンスが低下したり、その他アプリケーションでエラーが発生する可能性がありますので、十分に注意しましょう。
余談ですが、もし EC2 のメモリ使用率を CloudWatch にメトリクス表示したいという方は、以下の記事にて詳しく解説しておりますので、ご参照ください。
Apache の役割と設定の重要性
Apache とその重要性の理解
まず、Apache とは何か、改めて概説です。
- Apache HTTP Server
- オープンソースの Web サーバーソフトウェアです
- クライアントからの HTTP リクエスト※を受け取り、 HTML などのウェブページを返す役割を果たします
※例えば、ウェブブラウザからのページ要求等 - CGI スクリプトや PHP などのサーバーサイドのスクリプトを実行できます
- 豊富なモジュールを通じて、追加の機能を提供します
- セキュリティ強化
- URL の書き換え
- 負荷分散等
Apache 設定の役割と最適化の重要性
Apache は設定ファイル※で制御されます。
※通常は httpd.conf という名前のファイル
ここでは、サーバーの動作に影響を与えるさまざまなパラメータ記述されています。
例えば、以下のようなパラメータがあります。
サーバーがリクエストを受け取るポート番号
Listen 80
ドキュメントルート(サーバーがファイルを探しに行くディレクトリ)
DocumentRoot "/var/www/html"
エラーログの場所
ErrorLog "logs/error_log"
その他、様々なモジュールの設定も含まれます。
特に、今回の記事では、Apache の MPM という設定が重要です。
※MPM: Multi-Processing Module
これは Apache がどのように多数のリクエストを処理するかを決定します。
MPM の設定が不適切であれば、Apache は大量のリクエストを適切に処理できず、サイトのパフォーマンスが低下したり、場合によってはサイトが完全にダウンすることもあります。
また、AWS の t2.micro のようなリソース制約のある環境で Apache を動作させる場合、Apache の設定を最適化することが非常に重要となります。
メモリの制限内で最大限のパフォーマンスを引き出すために、Apache の設定を調整し、リソース使用を効率化する必要があります。
MPM の理解とその重要性
MPM(Multi-Processing Module)の紹介とその役割
前述の通り、今回の記事で、Apache の最適化において非常に重要な要素が MPM です。
これは Apache がどのように並行処理を行うかを制御します。
すなわち、一度に複数の HTTP リクエストをどのように処理するかを決定します。
Apache には様々なタイプの MPM が用意されていますが、一般的には次の 3 つのタイプが主に利用されます。
prefork
- 各リクエストを個別のプロセスで処理します
- これは非スレッド環境や、スレッドセーフでないモジュール※に適しています
※例えば、いくつかの PHP モジュール - しかし、大量のリクエストを処理するにはメモリ消費が大きいです
詳細は、以下の公式ドキュメントをご参照ください。
worker
- 各リクエストを個別のスレッドで処理し、これらのスレッドを少数のプロセスで管理します。
- これによって、プロセスごとのオーバーヘッドを減らしつつ、並行処理を行うことが可能となります。
詳細は、以下の公式ドキュメントをご参照ください。
event
- workerと同様にスレッドベースのMPMですが、保持している接続をより効率的に管理できます。
- これは特に同時に多数の接続を開いている長期間のクライアント※に対して効果的です。
※例えば、 Comet や WebSocket
詳細は、以下の公式ドキュメントをご参照ください。
プロセスとスレッドのおさらい
プロセスとは、システム上で実行される独立したプログラムのことを指します。
それぞれのプロセスは、自身のメモリ空間やシステムリソースを持っています。
一方、スレッドとは、プロセス内で実行される個々のタスクのことを指します。
スレッドは同じプロセス内でメモリなどのリソースを共有しながら実行されます。
このため、プロセスに比べてスレッドの生成や切り替えのコスト※は小さいです。
※コンテキストスイッチ
しかし、スレッドが同じプロセス内でリソースを共有するため、スレッド間でデータを共有したり同期を取ったりする際の設計やデバッグは複雑になる可能性があります。
Apache の MPM の設定を調整するときは、プロセスとスレッドのこれらの特性を理解して、システムのリソース(特にメモリ)と性能の最適なバランスを見つけることが重要です。
Worker MPM への変更の決定
前述の通り、各 MPM はそれぞれ異なる特性と特徴を持っています。
本記事の前提は、t2.micro インスタンス上での WordPress 運用です。
この場合、Worker MPM が最適な選択であると判断しました。
以下では、その理由について解説します。
- マルチスレッドによるリクエストの効率的な処理
- レイテンシーの低下
- リソース消費の削減
- ELB 配置による 5xx エラー発生の回避
補足: ELB 配置による 5xx エラー発生
特に、ELB 配置によるエラーについては注意が必要です。
これは、前段に ELB ( ALB / CLB ) が配置されている EC2 インスタンスにて Event MPM を使用している場合に発生します。
詳細については、以下の repost 記事が参考になるかと思います。
Apache: Apache MPM イベントモジュールは、ロードバランサーからの接続を早期に切断する可能性があります。接続が早期に切断されると、Application Load Balancer では HTTP 502 エラーが、Classic Load Balancer では HTTP 504 エラーが生成されます。この動作を抑制するためには、代わりに MPM ワーカーモジュールを使用するのがベストプラクティスです。
https://repost.aws/ja/knowledge-center/apache-backend-elb
( Event の特徴である Keep Alive Problem の回避 (コネクションの切断) が問題になっているんですかね )
上記の理由から、今回は Worker MPM を選択します。
ただし、Worker MPM はスレッド型モジュールである注意が必要です。
つまり、非スレッドセーフなモジュールとの互換性がありません。
具体的には、Apache の mod_php(php_module) は非スレッドセーフなモジュールであり、Worker MPM との互換性がありません。
WordPress は PHP で動作するため、PHP-FPM を用いる方法に変更する必要があります。
次の章では、実際の切り替え手順とその結果について説明していきます。
Apache Worker MPM の設定手順
では、いよいよ設定手順の説明に入ります。
なお、環境次第では重大なエラーにつながる可能性もあるため、事前にバックアップを取得しておくことを強くお勧めします。
Prefork の無効化と Worker の有効化
まず、モジュールそのものの無効化・有効化を設定しましょう。
設定には、モジュールの設定ファイルを修正する必要があります。
vi /etc/httpd/conf.modules.d/00-mpm.conf
mpm_prefork_module は無効化するため、行をコメントアウトします。
mpm_worker_module は有効化するため、行のコメントを外します。
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
…
LoadModule mpm_worker_module modules/mod_mpm_worker.so
これで、Apache Worker MPM の設定は完了です。
設定の確認は、以下のいずれかのコマンドで確認可能です。
$ httpd -V | grep MPM
Server MPM: worker
$ httpd -M | grep mpm
mpm_worker_module (shared)
PHP-FPM の設定手順
概説とメリット
まず、PHP-FPM とは、ウェブサーバーと PHP の間の高速なインターフェイスを提供する PHP の代替バージョンです。
※FPM: FastCGI Process Manager
このツールは、FastCGI と互換性があり、リクエストごとに新しい PHP プロセスを起動する代わりに、事前に起動しておいたプール内のプロセスを再利用します。
これによって、PHP-FPM はパフォーマンスを向上させ、リソースの使用を最小化します。
また、非スレッドセーフな mod_php に代わるスレッドセーフな解決策として、Apache の Worker MPM と組み合わせて使用することができます。
インストールと設定
PHP-FPM のインストールは、パッケージマネージャーを用いて簡単に行うことができます。
例えば、Amazon Linux 2 では次のコマンドで PHP-FPM をインストールできます。
sudo yum install php-fpm
次に、インストールが完了したら、PHP-FPM を Apache と統合する必要があります。
vi /etc/httpd/conf.d/php.conf
ここでは、以下の行を追加または更新します。
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</FilesMatch>
これによって、PHP リクエストを PHP-FPM にリダイレクトされます。
要するに、.php 拡張子を持つすべてのファイルは PHP-FPM によって処理されます。
※ファイルパスは環境により異なる可能性があります
mod_php の無効化
最後に、mod_php(php_module)を無効にします。
これによって、Apache が Worker MPM とともに正しく動作し、同時にメモリ使用量を抑えることが可能となります。
具体的には、Apacheのモジュール設定ファイルを編集します。
vi /etc/httpd/conf.modules.d/15-php.conf
mod_php に関連する Import 行をコメントアウトします:
# LoadModule php_module modules/libphp.so
…
# LoadModule php_module modules/libphp-zts.so
※ファイルパスとモジュール名は環境により異なる可能性があります
プロセス・スレッド数の調整
ここまでの設定で、httpd と php-fpm プロセスがそれぞれ独立して動作するようになります。
試しに、この段階で各種サービスを再起動して、違いを確認いただいても構いません。
これだけでも、パフォーマンスは向上していることが確認できるかと思います。
しかし、t2.micro インスタンスでは、php-fpm プロセスが多数同時起動することがボトルネックになりかねません。
以下では、適切な処理が行えるよう、設定ファイルで指定するパラメータの例を確認しましょう。
各種パラメータ設定例
まず、以下の設定ファイルでパラメータを指定可能です。
vi /etc/php-fpm.d/www.conf
例えば、以下はアクセス数が非常に少ない場合の、各種パラメータの設定例です。
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
あくまで設定例なので、リソース状況をモニタリングしつつ調整してみてください。
各種パラメータ概要
- pm:
- これはプロセスマネージャーの設定です
これによって、PHP-FPMがどのように子プロセスを管理するかが決まります
- 有効な値はstatic、dynamic、ondemandのいずれかです
dynamic を設定した場合、子プロセスの数は必要に応じて増減します
- これはプロセスマネージャーの設定です
- pm.max_children:
- 子プロセスの最大数を設定します
これは同時に処理できるリクエストの最大数に相当します
- 子プロセスの最大数を設定します
- pm.start_servers:
- サーバーの起動時に生成される子プロセスの数を設定します
これは pm が dynamic か ondemand のときに有効です
- サーバーの起動時に生成される子プロセスの数を設定します
- pm.min_spare_servers:
- アイドル状態の子プロセスの最小数を設定します
これは pm が dynamic のときに有効です
なお、アイドル状態の子プロセスの数がこの値よりも少なくなると、新たな子プロセスが生成されます。
- アイドル状態の子プロセスの最小数を設定します
- pm.max_spare_servers:
- アイドル状態の子プロセスの最大数を設定します
これは pm が dynamic のときに有効です
なお、アイドル状態の子プロセスの数がこの値よりも多くなると、余分な子プロセスが終了します。
- アイドル状態の子プロセスの最大数を設定します
その他のパラメータや、詳細については公式ドキュメントをご参照ください。
これで、PHP-FPM の設定は完了です。
設定反映と結果確認
ここまでで、各設定が完了しました。
設定反映
まず、設定内容を反映するために、各種サービスを再起動しましょう
sudo systemctl restart httpd
sudo systemctl restart php-fpm
設定に問題がなければ、正常に起動するかと思います。
一例ですが、php_mod の無効化を忘れていると以下のようなエラーが発生します。(体験談)
httpd: [php:crit] [pid 4177:tid 140319625552448] Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP.
自動起動設定
また、必要に応じて自動起動設定もしておきましょう。
sudo systemctl enable httpd
sudo systemctl enable php-fpm
結果確認
最後に、top コマンドや CloudWatch で、メモリ使用率が下がっていることを確認しましょう。
top - 09:44:44 up 8:56, 1 user, load average: 0.02, 0.05, 0.05
Tasks: 105 total, 1 running, 62 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 975596 total, 424116 free, 372996 used, 178484 buff/cache
KiB Swap: 1048572 total, 1017720 free, 30852 used. 462260 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8216 apache 20 0 476844 91216 13088 S 0.0 9.3 0:09.29 php-fpm
8219 apache 20 0 474140 88740 13092 S 0.0 9.1 0:06.51 php-fpm
8215 apache 20 0 470704 85952 13140 S 0.0 8.8 0:09.99 php-fpm
7712 root 24 4 792268 56724 9248 S 0.3 5.8 0:28.81 aws
7129 root 20 0 789336 29688 15304 S 0.3 3.0 0:26.12 amazon-cloudwat
7474 root 20 0 326744 19448 14528 S 0.0 2.0 0:00.29 php-fpm
無事、メモリ使用率が大幅に低下させることができました。
ここで、死活監視等を実装していない人は、きちんとサービス (WordPress等) が正常稼働しているか確認しておきましょう。
本記事の設定では、php-fpm プロセス数・スレッド数を抑制しているため、パフォーマンスへの影響が出ていないかも確認することをお勧めします。
さいごに
本記事では、EC2 t2.micro で WordPress を運用するにあたって陥りがちなメモリ不足問題(OOM)の根本的な対策として、Apache Worker MPM と PHP-FPM を用いた最適化について解説しました。
途中、割愛しましたが、php-fpm ももちろんエラーログを出力してくれます。
# grep "error_log" /etc/php-fpm.conf
error_log = /var/log/php-fpm/error.log
今後、アプリケーションエラーが発生した際にきちんと調査ができるよう、CloudWatch Logs へ出力設定することをお勧めします。
具体的な設定方法については、以下の記事で詳細に解説しておりますので、ご参照ください。
コメント