AWS EFSを使ったWordPressシステムをProduction Readyにするまでの道のり

トラストバンクふるさとチョイス事業本部SREの香西(かさい)です。

先月末に「読むふるさとチョイス」というオウンドメディアをリリースしました!

prtimes.jp

本記事ではこのオウンドメディアをEC2+EFS+RDS+ElastiCacheでAutoScalingなWordPressシステムとして構築したので、このシステムをProduction Ready*1にしていくまでの道のりをご紹介したいと思います!

要件

まず要件ですが、今回開発を外部制作会社へ発注していたこともあり、以下のような制約がありました。

デプロイをWordPressプラグインで行い、SFTP経由でのファイル更新するという要件があることで、Gitでソースを管理してCI/CDでデプロイ、ということが難しくなってしまい、プロジェクトから冗長構成でスケールできるようにしてほしいという要件も出てきました。

WordPressは基本的に冗長構成を考慮したアーキテクチャになっていないので冗長化するの大変なんですよね。。。

マスターサーバーを別にしてlsyncdで同期するとか、共有が必要なディレクトリをNFS上に置いたり、画像データをS3に置いたりと色々なやり方はあるもののベストプラクティス的なものは存在せず、デプロイでも悩むことになることも多く、WordPressをスケーラブルでイケてるシステムにするために涙ぐましい努力をしているエンジニア諸氏の屍の上に我々は立っていると言っても過言ではないのです。(過言やろ)

今回はデプロイ部分については制約があり、あまり工夫が出来ないので、どのようにデプロイ要件を満たしつつスケーラブルなインフラにしていけるかを考えていこうと思います。

システム構成

デプロイ

EFS+TransferFamilyの組み合わせで前述のデプロイはWordPressプラグインで行う&SFTP経由でファイルの更新ができるという要件をクリアしていきたいと思います。

Amazon Elastic File System (EFS)AWSが提供するフルマネージドなNFSストレージです。

WordPressプラグインでのデプロイをする&SFTP経由でもファイルを更新したいという要件があるので、EFSを使ってどのサーバーからのアクセスして、プラグイン経由でのデプロイをしても問題ないようにします。

ちなみにEFSでスループットモードをバーストモードにしている場合、クレジットが尽きるぐらいのスループットがあると完全に死ぬことになるのでご注意ください。

そして、クレジット枯渇を回避するためにプロビジョニングモードにするととてもお高いのご注意ください・・・(ツライ

AWS Transfer FamilyAWSが提供するSFTP、FTPS、FTP プロトコルを使用してS3やEFSとデータ転送できるようにするフルマネージドサービスです。

今回のSFTP経由でファイル更新の要件をこのTransferFamilyで実装していきます。

可用性&冗長性

次に、ALB+EC2+AutoScaling+RDSで冗長構成でスケールできるの要件をクリアしていきます。

また、RDS部分のスケールにはWordPressプラグインであるHyperDBを利用します。

ja.wordpress.org

これでWordPressのプログラムファイル群をすべてEFS上に置いて、各EC2サーバーからNFSマウントする形にし、スケールしてどのサーバーにアクセスしても問題がないようになりました。

構成図

全体のシステム構成は図としてはこんな感じになります。

システム構成

しかし、このままではとても遅くて使い物にならないので様々なキャッシュ機構を活用してスピードアップを図っていきます。  

キャッシュ戦略

というわけで以下キャッシュ機構を導入していきます。

  • PHP(OPcache)
  • Redis(ElastiCache)
  • CDN(Cloudflare)

PHP (OPcache)

PHP処理の高速化を実現する代表的な方法の一つにバイトコード(オペコード)をキャッシュする、所謂PHPアクセラレータを利用する方法があり、 そのPHPアクセラレータ機能を提供するのがOPcacheです。

OPcacheの導入方法は環境毎に異なるので割愛しますが、以下のようにopcache.enable => On => OnとなっていればOPcacheは有効になっています。

$ php -i | grep opcache
Additional .ini files parsed => /etc/php.d/10-opcache.ini,
opcache.blacklist_filename => /etc/php.d/opcache*.blacklist => /etc/php.d/opcache*.blacklist
opcache.consistency_checks => 0 => 0
opcache.dups_fix => Off => Off
opcache.enable => On => On
opcache.enable_cli => On => On
opcache.enable_file_override => Off => Off
opcache.error_log => no value => no value
opcache.file_cache => no value => no value
opcache.file_cache_consistency_checks => On => On
opcache.file_cache_only => Off => Off
opcache.file_update_protection => 2 => 2
opcache.force_restart_timeout => 180 => 180
opcache.huge_code_pages => Off => Off
opcache.interned_strings_buffer => 8 => 8
opcache.lockfile_path => /tmp => /tmp
opcache.log_verbosity_level => 1 => 1
opcache.max_accelerated_files => 10000 => 10000
opcache.max_file_size => 0 => 0
opcache.max_wasted_percentage => 5 => 5
opcache.memory_consumption => 128 => 128
opcache.opt_debug_level => 0 => 0
opcache.optimization_level => 0x7FFEBFFF => 0x7FFEBFFF
opcache.preferred_memory_model => no value => no value
opcache.preload => no value => no value
opcache.preload_user => no value => no value
opcache.protect_memory => Off => Off
opcache.restrict_api => no value => no value
opcache.revalidate_freq => 2 => 2
opcache.revalidate_path => Off => Off
opcache.save_comments => On => On
opcache.use_cwd => On => On
opcache.validate_permission => Off => Off
opcache.validate_root => Off => Off
opcache.validate_timestamps => On => On

細かいチューニングは環境毎に異なるため割愛しますが、一般的に推奨される設定について興味がある方は以下を参考にしてみてください。 まぁ、ほぼデフォルトで推奨設定になっていますがw

www.php.net

Redis(ElastiCache)

オブジェクトキャッシュとPHPセッションの保存先にRedisを利用するため、ElastiCacheでRedisを構築します。

オブジェクトキャッシュ

オブジェクトキャッシュには以下のWordPressプラグインを利用します。

ja.wordpress.org

このプラグインを利用することによりWordPressのオブジェクトキャッシュにより生成された値をキャッシュすることができ、同じオブジェクトに対して2回クエリを実行せずに、キャッシュされたオブジェクトを再利用できるので、DBの負荷を軽減し、ウェブサイトの応答時間を短縮させることができます。

設定としてはwp-config.phpに以下のようにエンドポイントを指定してあげるだけです。

define('WP_REDIS_HOST', '{Redisエンドポイント}');
define('WP_REDIS_MAXTTL', 3600);

PHPセッション

AutoScaling環境となるため、PHPセッションをRedisに保存&共有できるようにして可能性を高めたいのでphp-redisを利用します。

github.com

インストール方法については各環境毎に異なるため割愛しますが、基本的な設定としてはphp.iniに以下設定を入れるだけです。

session.save_handler = redis
session.save_path = "tcp://{Redisエンドポイント}:6379"

CDN(Cloudflare)

最後に弊社ではCDNにCloudflareを利用しているのでCloudflareのチューニングをしていきます。

キャッシュレベルはスタンダードのまま、以下の機能を有効化しました。

機能 概要
Mirage 画像の読み込みを高速化
Polish 画像のメタデータ除去&最適化によりダウンロード速度を改善させる
Rocket Loader Time to First Paint (TTFP)、Time to First Contentful Paint (TTFCP)、Time to First Meaningful Paint (TTFMP)、Document Loadのパフォーマンス向上
Auto Minify HTML/CSS/JavaScriptのサイズ縮小による転送量削減

詳細な説明は公式に委ねますが、基本的には上記設定を有効化するチューニングのみを実施しました。

Lighthouseの結果

前述のキャッシュ関連の設定を実装した状態でのLighthouseの結果は以下のようになりました。

Lighthouse結果

サーバーの台数を増やすことでスループットが伸びることも確認できたのでこれでProduction ReadyなWordPressシステムと言えるようになったのではないでしょうか!???

おわりに

今回EFSを使ったWordPressシステムを構築してみて、EFSはWordPressで冗長構成を取りたい場合には中々良い選択肢になり得るのかなと思いました。

以前は遅くて使いにくいイメージがありましたが、読み取りスループットが3倍になるアップデートもありCDNありきではありますが、Production ReadyなWordPressシステムのアーキテクチャの選択肢としては悪くないのではと現在は思っております。

aws.amazon.com

そしてまた大きなアップデートがあったのでこれはもうEFSっきゃないっしょという状況ですね。

www.itmedia.co.jp

本記事がProduction ReadyなWordPressシステム構築に挑戦しているエンジニア諸氏の参考になってくれると嬉しいです。

そんな弊社トラストバンクでは様々な職種で絶賛採用中なので気になった方は是非お気軽にご連絡くださいー!

www.wantedly.com

*1:Production Readyとは、サービスが本番トラフィックを任せられるほどの信頼性がある状態、その状態にするための考え方