Amazon Web Services ブログ

Amazon EFS を使用して WordPress のパフォーマンスを最適化する

多くの組織は、単一ノードインストールを使用して WordPress のようなコンテンツ管理システム (CMS) を使用していますが、マルチノードインストールがパフォーマンスと可用性の面でメリットを提供するベストプラクティスであることから、これを使用することで恩恵を受けることができます。AWS Well-Architected フレームワークの信頼性の柱では、次の設計原則を推奨しています。すなわち、「水平方向にスケールしてシステム全体の可用性を高める: 1 つの大規模なリソースを複数の小規模なリソースに置き換えることで、単一の障害がシステム全体に与える影響を軽減します。リクエストを複数の小規模なリソースに分散させることで、共通の障害点を共有しないようにします」というものです。 このブログ投稿では、Amazon Elastic File System (Amazon EFS) を可用性の高い WordPress デプロイの共有コンテンツストアとして使用する方法について説明し、サイトのパフォーマンスを改善するための最適化のヒントを紹介します。

マルチノードの WordPress サイトを実行する 1 つのアプローチは、ファイルを 1 か所に保存し、ブートストラッププロセス中にこのデータをダウンロードすることです。これでも機能しますが、このオプションを使用すると、ウェブサイトの進化に合わせてコンテンツを常に同期することが難しくなります。Amazon EFS のような共有ファイルシステムを使用すると、複数のノードが同時に WordPress ファイルにアクセスできます。これにより、水平スケーリングとウェブサイトの更新のプロセスを大幅に簡略化できます。

ページをロードする時間を理解する

Amazon EFS は、AWS クラウドサービスおよびオンプレミスリソースで使用するための、シンプルでスケーラブルで伸縮自在な完全マネージド型の NFS ファイルシステムを提供します。アプリケーションの運用を妨げることなく、オンデマンドでペタバイト単位にまで拡張できるように構築されており、ファイルを追加および削除すると自動的に拡大および縮小するため、成長に対応するためにキャパシティーをプロビジョニングしたり管理したりする必要はありません。Amazon EFS はリージョナルサービスであり、複数のアベイラビリティーゾーン内およびこれらにまたがってデータを保存し、高可用性と耐久性を実現しています。

ネットワーク化されたファイルシステムについては、クライアントとサーバー間のネットワーク通信に関連するオーバーヘッドがあります。シングルスレッドアプリケーションから小さなファイルを操作する場合、このオーバーヘッドも併せて大きくなります。多くの場合、マルチスレッド I/O およびより大きなファイルの I/O はパイプライン処理できるため、ネットワークのレイテンシーをより多くの操作で償却できます。

例えば、PHP ウェブサイトがホームページを生成するには、100 個の小さなファイルにアクセスする必要があるとします。これは、PHP ファイル、インクルード、モジュールなどです。PHP パーサーにページをロードするときに小さな 1 桁のミリ秒の低レイテンシーを導入すると、ユーザーがウェブサイトにアクセスするときに数百ミリ秒のさらなる遅延が発生します (100 ファイル X 数ミリ秒の遅延)。ウェブページのロードに対するユーザーの許容度はそれほど高くないため、これは重要です。

この図は、ページをロードするために実行する必要があるさまざまな手順を示しています。各ステップで追加のレイテンシーが発生します。私たちは、WordPress ウェブサイトを最適化して Amazon EFS で実行し、できるだけ早く「最初のバイト」を提供する方法を生み出すことに注力しています。

この図は、ページをロードするために実行する必要があるさまざまな手順を示しています。各ステップでさらなる遅延が発生しています

レイテンシーの影響

PHP はインタプリタ言語です。インタープリタは、アプリケーションへの要求ごとに、アプリケーションのコードを読み取り、解釈し、コンパイルする必要があります。単純な <?php echo ”Hello world” ?> の場合、インタープリタは単一のファイルにアクセスする必要がありますが、WordPress のような CMS を実行している場合は、ページを生成する前に何百ものファイルを読み取る必要があります。イメージを持っていただくために、PHP インタープリタは、新しくインストールされた WordPress から「ようこそ」ページを生成する前に、227 個のファイルを順番に読み取ります。

ネットワーク経由で直接ファイルを連続的に取得するときにウェブサーバーが経験するパフォーマンスを示すために、新しくインストールした WordPress (v5.4) のウェブサイトから、すぐに使える「ようこそ」ページを作成しました。ウェブサイトは t2.medium Amazon EC2 インスタンスで実行されていました。WordPress ディレクトリは、すべてのデフォルト設定 (汎用パフォーマンスモードおよびバーストスループットモード) を使用して作成した Amazon EFS ファイルシステムに保存されていました。さらに、ディレクトリは Amazon EFS マウントヘルパーを使用してマウントされました。これはデフォルトで推奨マウントオプションを使用します。セットアップが完了したら、いくつかのテストを実行しました。最初のテストでは、デフォルトの「ようこそ」ページをロードし、テスト #2~#5 では、さまざまなサイズの静的ファイルをロードします。

最初の 1 バイトを受信するまでの時間 (TTFB) メトリクスは、各テストの結果を測定するのに役立ちます。誰かがウェブサイトを開くと、ブラウザはサーバーに情報を要求します。これは「GET」リクエストと呼ばれます。TTFB は、ブラウザがウェブサーバーから最初の 1 バイトを受信するのにかかる時間です。TTFB をできるだけ小さくするのが理想です。結果に干渉するネットワークレイテンシーが発生しないように、WordPress のインストールをホストしているのと同じ Amazon EC2 インスタンスで各テストを実行しました。

Linux curl コマンドを使用して、これらのテストを実行しました。最後に、各テストの「time_starttransfer」の 250 のサンプルを記録しました。これは、さまざまな条件下でさまざまなファイルの TTFB をキャプチャするために使用したサンプルスクリプトです。

これは bash スクリプトのサンプルです。

#!/bin/bash
for i in {1..250}
do 
    curl -o /dev/null \
    -s \
    -w "%{time_starttransfer}\n" \
    http://127.0.0.1/wordpress/ >> /tmp/wordpress-efs-ttfb.txt
done

以下はテスト結果です。

テスト

GET 操作

受信したバイト数

読み込んだファイル数

平均 TTFB

1

wordpress/ 3 KB 227 759 ミリ秒

2

hello.txt 12 B 1 3 ミリ秒
3 small-file 1 MB 1

5 ミリ秒

4 medium-file 10 MB 1

5 ミリ秒

5 large-file 100 MB 1 6 ミリ秒

レイテンシーの影響のテスト結果

レイテンシーは、静的ファイルのファイルサイズに関係なく比較的一定です。動的に生成されたページのロードには時間がかかります。これは、ページがブラウザに提供される前に、PHP がファイルを順次取得することで、レイテンシーが蓄積されるためです。

OPcache による改善

Zend OPcache は、プリコンパイルされたスクリプトバイトコードを共有メモリに格納することで PHP のパフォーマンスを改善し、各リクエストで PHP がスクリプトをロードして解析する必要をなくします。この拡張機能は PHP 5.5.0 以降にバンドルされており、PHP バージョン 5.2、5.3、および 5.4 の PECL で利用できます。

実行したのは同じ「GET wordpress/」テストですが、今回は OPCache を有効にしました。このようにしたのは、ディスクから読み取る必要がなく、すべてのリクエストでコードをコンパイルする必要がない場合に、レイテンシーをどの程度削減できるかを知るためです。

OPcache の構成内で opcache.revalidate_freqopcache.validate_timestamps=1 を設定することで、PHP バイトコードを期限切れにする頻度を決定し、Amazon EFS への新しいラウンドトリップを強制できます。この例では、再検証の頻度を 15 分 (900 秒) に設定しています。OPCache を使用すると、他のキャッシングシステムと同様に、共有ファイルシステムで使用可能なファイルを即座に表示するための速度が遅くなるので留意してください。

; Zend OPcache 拡張モジュールを有効にします
zend_extension=opcache
; Zend OPCache を有効にするかどうかを決定します
opcache.enable=1
; OPcache の共有メモリストレージサイズ。
opcache.memory_consumption=128
; インターンされた文字列のメモリ量 (MB)。
opcache.interned_strings_buffer=8
; OPcache ハッシュテーブル内のキー (スクリプト) の最大数。
opcache.max_accelerated_files=4000
; OPcache ブラックリストファイルの場所 (ワイルドカードを使用できます)。
opcache.blacklist_filename=/etc/php.d/opcache*.blacklist
; 無効になっている場合、ファイルシステムへの変更を有効にするには、OPcache を手動でリセットするか、
; ウェブサーバーを再起動する必要があります。
opcache.validate_timestamps=1
; 共有メモリストレージ割り当ての変更についてファイルのタイムスタンプをチェックする頻度 (秒単位)。
; (「1」は、1 秒に 1 回検証することを意味しますが、
; リクエストごとに 1 回のみです。「0」は常に検証することを意味します)
opcache.revalidate_freq=900

以下はテスト結果です。

テスト

GET 操作

受信したバイト数

読み込んだファイル数

平均 TTFB

1

wordpress/

(OPCache なし)

3 KB

227

759 ミリ秒

2

wordpress/

(OPCache あり)

3 KB

227

22 ミリ秒

改善:

35 倍

これは、OPCache メトリクスを表示する phpinfo() 関数です。WordPress がホームページをメモリに表示するために必要な 227 のスクリプトをすべてキャッシュしたことに注目してください。

OPCache メトリクス。WordPress がホームページをメモリに表示するために必要な 227 のスクリプトをすべてキャッシュしたことに注目してください。

Amazon EFS に保存されているファイルで OPCache を使用すると、35 倍の改善があります (759 ミリ秒から 22 ミリ秒)。

Amazon EFS に保存されているファイルで OPCache を使用すると、35 倍の改善があります (759 ミリ秒から 22 ミリ秒)。

静的コンテンツのキャッシュ

PHP は動的ページをレンダリングしますが、ウェブサーバーは HTTP(s) を介したページへのアクセスを容易にします。ウェブサーバーは、画像、CSS、JavaScript などの静的ファイルへのアクセスも提供します。これらのファイルは Amazon EFS から直接提供でき、ユーザーは 1 桁のミリ秒の低レイテンシーを体験できます。順次ロードされる静的ファイルが数百 (またはそれ以上) あるウェブサイトの場合、これらのレイテンシーの合計により、ページのロード時間が長くなる可能性があります。

この問題の解決策は、Amazon CloudFront などのコンテンツ配信ネットワーク (CDN) やローカルストレージなど、静的ファイルをどこかにキャッシュすることです。Apache を使用している場合は、「mod_cache_disk」モジュールを確認できます。これは、mod_cache のディスクベースのストレージマネージャーを実装しています。これは、キャッシュされた応答のヘッダーと本文が、指定した場所に個別に格納されるという仕組みになっています。この構成により、リクエストがキャッシュから提供されるときに、共有ファイルシステムへのネットワークラウンドトリップが回避されます。

デモのために、非 PHP ファイルをキャッシュして最初のアクセスが発生してから 15 分後に再検証するように Apache を設定する設定ファイルを用意しました。ファイルは /var/cache/httpd/proxy に保存されており、この場所はローカルディスクを使用しています。新しいリクエストが来ると、Apache はまずファイルがキャッシュされているかどうかをチェックします。ファイルの有効期限が切れていない場合、Apache はこの場所からファイルを取得します。それ以外の場合は、Amazon EFS 上にある wwwroot フォルダーからファイルを取得します。Apache キャッシュは、htcacheclean ユーティリティを使用して、簡単にフラッシュするか、サイズ制限内に保つことができます。

# キャッシュされたファイルを格納するためのディスク上のディレクトリ 
CacheRoot "/var/cache/httpd/proxy"
# すべてをキャッシュ
CacheEnable disk "/"
# キャッシュを有効にし、15 分キャッシュをデフォルトとして設定します
ExpiresActive On
ExpiresDefault "access plus 15 minutes"
# PHP ファイルのキャッシングを強制しないようにします
<FilesMatch "\.(php)$">
    ExpiresActive Off
</FilesMatch>   

サーバーが構成された後、「hello.txt」テストを実行して、15 分ごとに結果を比較しました。

テスト

GET 操作

受信したバイト数

読み込んだファイル数

平均 TTFB

1

GET hello.txt

(mod_disk_cache なし)

12 B

1

3 ミリ秒

2

GET hello.txt

(mod_disk_cache あり)

12 B

1

0.6 ミリ秒

改善:

5 倍

キャッシュが有効にされた後、ファイルは最初のリクエスト後にローカルディスクから提供されるため、ファイルがローカルディスクにあるか、Amazon EFS にあるかは関係ありません

キャッシュを有効にすると、Amazon EFS に保存されている静的アセットを提供するときに 5 倍の改善があります。

最後に、多くの場合、これらの設定は WordPress インストールに十分ですが、さらに最適化する必要がある場合もあります。例えば、一部のプラグインはログを書き込むように設定できます。ログに行が追加されるたびに共有ファイルシステムへのネットワークラウンドトリップが発生しないように、これらのログファイルがローカルディスクで書き込まれるようにするのが理想的です。

まとめ

このブログ投稿では、AWS Well-Architected フレームワークがワークロードを水平方向にスケールアウトすることをどのように推奨しているのかについて説明しました。さらに、WordPress ワークロードのネットワーク共有ファイルシステムとして Amazon EFS が優れた選択肢である理由についても説明しました。これは、Amazon EFS を使用すると、複数のノードが同時に WordPress ファイルにアクセスできるため、スケーリングとデプロイが簡素化されるためです。キャッシュを使用して静的ファイルのパフォーマンスを 5 倍、動的ファイルのパフォーマンスを 35 倍に最適化するテクニックのデモンストレーションが、読者の皆様に役立つように願っています。

お読みいただきありがとうございました。コメントや質問はコメント欄からお寄せください。

その他のリソース