WordPress サーバのパフォーマンスチューニング(キャッシュ編)

スタッフブログ

インフラエンジニアのキリヤマです。
先日、弊社の商品の紹介や販売を行っているサイト prefer.jp の運用サーバを共用レンタルサーバから、クラウドサービスへ移設しました。
今回は移設に併せて行ったサーバのパフォーマンスチューニングについてお話したいと思います。

サーバ移設の経緯

移設前は某レンタルサーバの共用プランで稼働していましたが、共用のサーバということもあり、お世辞にも早いとは言えないものでした。
弊社でもたくさんのドメインを1つの契約内で運用していますが、多くの会社が同じようにサーバを使っているであろうことを考えるとレスポンスが悪くなるのも当然です。
WebサーバだけでなくDBサーバも共有のもので、レスポンスにも大きくばらつきがあり、実際に遅くなっているタイミングで調べてみると、大抵の場合はこれらの応答時間が長くかかってしまっているようでした。
レスポンスを改善しようにも共用のレンタルサーバではできることが限られていますので、思い切ってサーバを移設することにしました。

パフォーマンスチューニングするもう一つの理由

今回のサーバの移設先は、クラウド上のインスタンスにWebサーバとDBサーバを構築しています。CPUなどのリソースが不特定多数のコンテンツと共用されることがなくなるので、これだけでも十分に早くなることが期待できますが、最近のWebサイトはより高速なレスポンスが求められています。

Googleの調査でも……

  • モバイルサイトの読み込みに3秒以上かかると、訪問者の53%が離脱する
  • ページの読み込み速度が1秒から5秒に増えると、モバイルサイトの訪問者の直帰率は90%増える

という報告があり、さらにGoogleは2018年に「ページの読み込み速度をモバイル検索のランキング要素に使用する」と宣言しています。よりモバイル向けに高速なWebサイトをつくる必要があるということです。

※ 参考: Googleウェブマスター公式ブログより ページの読み込み速度をモバイル検索のランキング要素に使用します

チューニングを行う箇所

Webサイトへのアクセスで発生する一連の流れは以下のようになります。

今回は ②動的処理 の中で MySQLとNginx の2つについて キャッシュ を使ってパフォーマンスチューニングを行います。
キャッシュを使ったチューニングのポイントは以下の2つです。

  • 一度実行した処理はできるだけ再利用してCPUを動かさない
  • メモリを効率的に利用してネットワークやストレージにアクセスさせない

効率的にキャッシュをつかうことで、WebサーバのCPUを使ったり、DBサーバにアクセスしてデータを取得していたものを軽減することができ、その結果WordPressのサイトの高速化に繋がります。

DBサーバ MySQL の設定

MySQLでは Query CacheInnoDB Buffer Pool の2つのキャッシュ機構を使って、できるだけキャッシュだけで応答ができるように設定します。

Query Cache

Query Cacheは、参照系クエリ(SELECT)の実行結果をメモリにキャッシュし再利用させます。同じクエリが増えるほど効果が大きくなり、場合によっては1000%以上の効果も期待できます。

[mysqld]
query_cache_size=128M

設定値は想定されるデータベースサイズの10%程度が目安といわれていますが、今回は128Mに設定しています。

InnoDB Buffer Pool

InnoDB Buffer Poolは頻繁にアクセスされるデータとインデックスをメモリーにキャッシュさせます。メモリにキャッシュするため大きいほど有利に働きます。

[mysqld]
innodb_buffer_pool_size=3G

今回のDBサーバはMySQLのみが稼働する搭載メモリ4Gのインスタンスなので、innodb_buffer_pool_sizeを3Gと設定していますが、搭載メモリの範囲内であっても、他のプロセスの影響などでスワップアウト(swap out) が発生してしまうかもしれません。スワップアウトが発生すると、メモリの中身をディスク上で読み書きするI/Oが発生してしまい、一気に速度が低下します。設定値は、搭載メモリの8割程度が目安と言われていますが、システムや他のプロセスが使用するメモリ量などを考慮する必要があります。

Webサーバ Nginx の設定

WebサーバのNginxでは、 FastCGI(PHP)をキャッシュする FastCGICache を中心に、ブラウザのキャッシュ Expire や ファイルのopenやcloseで発生するオーバーヘッドを軽減する open file cache を使ってキャッシュ化を行います。

FastCGICache

FastCGICacheはFastCGI(PHP)のレスポンスを直接キャッシュすることでバックエンドに処理をさせずに応答させることができます。

fastcgi_ignore_headers  Cache-Control Expires Set-Cookie Vary;
fastcgi_cache_path /var/cache/nginx/prefer.jp  keys_zone=prefer.jp:30m levels=1:2 inactive=600m max_size=512M;

キャッシュの最大サイズ512Mを超えると利用されていないものから削除され、600minの間アクセスが無いキャッシュも削除される設定にしています。

Expires

HTTPクライアントにコンテンツのキャッシュ有効期限を返すためのHTTPレスポンスヘッダです。クライアント側ブラウザのキャッシュを利用するため、高速にコンテンツを表示できます。通信やリクエストが削減されるのでサーバ負荷の軽減にもつながります。

location ~ .*\.(html?|jpe?g|gif|png|css|js|ico|swf|inc|svg) {
    expires 3d;
    access_log off;
}

一致する静的コンテンツのファイルを3日間キャッシュするように設定しています。

open file cache

ファイルを閉じる処理を遅らせ、キャッシュすることで次のアクセス時にファイルを開く処理を省略する機能です。CSSなどの特定のファイルにアクセスが集中する場合に有効です。

open_file_cache  max=100000 inactive=20s;

キャッシュの最大数を100000、アクセスのないキャッシュの有効期限を20秒としています。

まとめ

今回はインフラエンジニアらしく、効果がある程度見込めるサーバ側でのキャッシュを中心としたパフォーマンスチューニングをまとめました。キャッシュを有効に使ってサーバの負荷が軽減されることでによって多くのアクセスにも対応できることになり、コストの削減にも繋がります。
今回は触れていませんが、通信を HTTP/2 にしたり、静的コンテンツの圧縮をしたり、サーバのカーネルを私の「秘伝のタレ設定」でチューニングするなど、数週間かけて設定や調整を行っています。機会があればこれらの設定やカーネルの「秘伝のタレ設定」についてもこのブログで紹介したいと思います。

後日談

FastCGICache が優秀なためか、とにかくキャッシュしてしまうため、本来であれば可変なはずのデータが毎回同じ内容で応答されてしまうという障害を数回発生させてしまいました。
キャッシュしてよい部分とキャッシュしてはいけない部分の調査は事前にしっかり行いキャッシュから除外するようにしておきましょう。