そのキャッシュ正しく動作していますか?
WordPressの高速化とキャッシュは切っても切れない存在です。
「わかっているけど難しいから全てプラグイン任せ」
または
「解説サイトの設定をコピペ」という方も多いのではないでしょうか?
私もそんな1人で、この記事のきっかけは、とある作業中に「W3 Total Cacheのキャッシュが意図した期限より短くなっている」ということに気が付いたからです。
キャッシュ系プラグインの雄、W3 Total Cacheはバージョンが上がるごとにますます多機能になっています。
「せっかく再設定するならW3 Total Cacheを通して各種キャッシュの仕組みについて掘り下げてみよう。」という趣旨の記事です。
WordPressにおけるキャッシュとは何か
キャッシュと一口に言っても実は様々なキャッシュがあります。今回はWordPressを高速化する上で重要な2つのキャッシュについて解説します。
ページキャッシュについて
通常WordPressでは初回アクセス時に以下のような流れでWebページが表示されます。(わかりやすくするために簡略化した図です)
このように様々な処理を組み合わせて動的にページを生成するのがWordPressの特徴です。
柔軟なページ生成が可能な反面、これらの処理をリクエストするごとに行うため、サーバのリソースを多く消費します。これが「WordPressは遅い」と言われる原因です。
今回は詳しく解説しませんがサーバ側には様々なキャッシュが存在します。 例えば上のイラストの 「2」であればWordPressのオブジェクトキャッシュ。 「3」であればAPC。 「4」であれば各種クエリキャッシュやmemcached。 「5」であればリバースプロキシサーバなど。 W3 Total Cacheではこうした処理もキャッシュする仕組みが用意されています。しかしサーバ側で効果的にキャッシュを利用している場合は、W3 Total Cacheのキャッシュ機能を使うと逆に遅くなることもあります。 キャッシュ系プラグインの導入にはサーバ管理者と相談した上で行うようにしてください。
ではページキャッシュを有効にするとどのようになるのか見てみましょう。
このようにサーバは既に生成されたHTMLを返すだけなので、高速に表示することができます。
イラストにある通り、ページキャッシュはサーバーサイドにキャッシュを保存する仕組みです。
ブラウザキャッシュについて
ブラウザキャッシュとは、初回アクセス時にユーザー側のブラウザに表示結果を保存しておき、次回アクセス時に利用するという仕組みです。
以下の様な流れでキャッシュが利用されます
初回アクセス時はサーバがHTMLファイル生成して送信してきます。ブラウザはこのファイルをキャッシュとしてPCに保存します。
2回目以降はキャッシュが有効かどうかをサーバに問い合わせ、更新がなければブラウザに保存されたキャッシュを利用。更新されていれば、サーバで再度HTMLファイルを生成して送信し直します。
キャッシュが更新されていない場合、サーバは更新されていないことを示す304 Not Modifiedというレスポンスを返します。
この方法だとページを生成したり、HTMLファイルを送信して回線を使うこともないので、サーバリソースの節約になります。
利用者側としてもネット回線を通してデータを受け取るよりもディスクに保存されたキャッシュを表示するほうが高速なので、利用者側にとっても利点の多い仕組みです。
以上がWordPressを高速表示する上で重要なキャッシュの仕組みです。次はW3 Total Cacheの細かな設定について見ていきます。
W3 Total Cacheの機能について
W3 Total Cacheをインストールすると「編集画面」に「Performance」というメニューが追加されます。
まず、そのメニューの多さに驚かされます。
あまりに多機能で全て解説すると長くなってしまうので、キャッシュに関する解説に絞って進めます。
General Settings – 一般設定
ここが全体の設定をする場所です。ここで大まかに設定をして、後述するページで細かな設定をするという流れになります。
General(一般設定)
プレビューモードのオン、オフを切り替えます。W3 Total Cacheの動作を確認するための設定です。
プレビューモードの場合、擬似的にキャッシュは作成されますが有効にはなっていません。プレビューモードでサイトのソースを見ると詳細なデバック情報を見ることができます。
Page Cache(ページキャッシュ)
キャッシュの保存形式は特別な理由がない限りEnhancedがお薦めです。
しかし「.htaccess」が書き換えられない場合など、サーバの環境によっては利用できない事があります。その場合はBasicを選んでください。
Enhancedを選ぶと「wp-content/page_enhanced/」にキャッシュが作成されます。パーマリンク通りに作成されるため、キャッシュの内容が把握しやすいというメリットがあります。
WordPressのパーマリンク設定がデフォルト(http://example.com/?p=123といった形式)だとBasicしか選ぶことができないので注意してください。
Minify (最適化)
JavascriptやCSSを最適化する設定。
HTMLの構文を修正するHTML Tidyや、Javascriptを圧縮するYUI Compressorなど、どれも実績のある方式です。しかし、バージョンや関数の組み合わせは無限にあるため、バグや競合も十分考えられます。
そのため慎重に導入してください。
通常配布されているJavascriptは圧縮されていることが多いので、既存のjQuery等を利用するだけならチェックする必要はありません。
自分で作成したJavascriptやCSSは、Web上で手軽に最適化できるので、以下のようなツールで個別に行うことをお勧めします。
有名な圧縮ツール
Online YUI Compressor
CSS & JavaScript Compressor
Google Closure Tools -JavaScript専用
Database Cache(データベースキャッシュ)
データベースのクエリをキャッシュする。
MySQLにアクセスする必要がなくなるので特にCPUリソースの節約になります。膨大なデータベースをソートしたり全文検索などを行う場合は非常に有効です。
反面、十分なメモリが用意されたMySQLの場合、クエリはメモリ上にキャッシュされているため、ディスクに保存されたキャッシュを利用するほうが遅くなることもあります。
以上のことから、SQLの処理が遅い共用サーバなどに向いていると言えます。
Object Cache(オブジェクトキャッシュ)
こちらはWordPressで生成されるグローバル変数などをキャッシュします。
この設定もデータベースキャッシュ同様、メモリが潤沢にある場合はAPC(Alternative PHP Cache)で処理したほうが高速なため、導入には注意が必要です。
これで一般設定は終了です。次からはそれぞれのキャッシュの詳細設定を見ていきます。
Page Cache(ページキャッシュ)
W3 Total Cacheの根幹部分、ページキャッシュの詳細設定です。
Page Cache – General
どのページをキャッシュするか選ぶことができる。
「Cache 404 (not found) pages」以外のページはキャッシュしておいて問題ない。
Page Cache – Cache Preload(キャッシュの自動生成)
プリロードとは先読みで実行すること。W3 Total Cacheではユーザーがアクセスした時点でサーバにページキャッシュが生成されます。
プリロードを設定すると、登録したサイトマップにあるURLのうち、キャッシュ期限の切れたURLのキャッシュを予め生成してくれます。
予めキャッシュファイルを生成することで、初回アクセス時のユーザーに対してもページキャッシュを返すため、応答が早くなります。
しかしこの設定はデメリットにつても考える必要があります。
詳細は後述しますが、ページキャッシュの有効期限は3600秒(1時間)に設定されているため、デフォルトの900秒で10ページ生成する設定だと、生成したキャッシュの内40ページ分だけが有効という計算になります。
キャッシュする間隔を短くしたり、キャッシュするページ数を増やせばサーバに負担がかかります。
キャッシュ期限までアクセスされるかわからないページのキャッシュを生成するのはリソースの浪費でしか無いので慎重に設定してください。
Page Cache – Purge Policy: Page Cache, Varnish
コメントの投稿や投稿の修正などページが更新された場合に連動してキャッシュを更新するページを指定。
Page Cache – Advanced(高度な設定)
「Late initialization」は詳細不明。
「Garbage collection interval」は期限切れのキャッシュを削除するタイミングの指定。cronと連携が必要なのか、環境によって動作しないという報国多数。そのためキャッシュを削除する場合は手動で削除したほうが確実です。
そもそも古いキャッシュは新しいキャッシュで上書きされるため、logファイルのように無尽蔵にサイズが増えることはありません。気にならなければそのままで良いと思います。
他にもキャッシュから除外する項目を正規表現で指定したり、レスポンスヘッダへの出力を制御することもできます。
Minifyの詳細項目
基本的な構成はPage Cacheの詳細設定と同じ。
こちらは除外項目なども設定できる。全体を有効にしたとしても、Adsenseやソーシャルメディアのボタンなどを導入している場合は除外項目に登録したほうが良い。
Database cacheの詳細項目
こちらも除外する項目などを指定する。他のキャッシュに対して有効期間は短め。
Object cacheの詳細項目
同じく除外する項目などを指定します。
Browser Cacheの詳細項目
WordPressを高速化する上でページキャッシュと双璧をなす重要項目、ブラウザキャッシュ。
W3 Total Cacheではかなり詳細に設定することができます。それゆえに内容を把握しにくく、そもそもブラウザキャッシュの仕様が複雑なため、要注意ポイントです。
ヘッダフィールドについて
ブラウザキャッシュの制御はヘッダフィールドを使います。
設定の意味については適宜解説しますが、詳しく知りたい方は以下のサイトで解説されているので参照してください。
ヘッダ情報を見る方法
ブラウザキャッシュが正しく設定できているかどうかは、ヘッダ情報を見る必要があります。
しかしソースなどに表示されるわけではないので、普通にブラウザでページを表示するだけでは見ることができません。以下に主要ブラウザでキャッシュを見る方法を紹介します。
Chromeでヘッダ情報を見る方法
1.Webページを表示した状態で「右クリック>要素を検証(もしくはF12)」をクリック。
2.ネットワークタブをクリックした状態でヘッダ情報を見たいページへアクセス。
3.ヘッダ情報をみたいファイルをクリック
以上の操作で以下のようにヘッダ情報が表示されます。
Internet Explorerでヘッダ情報を見る方法
1.F12を押す。
2.ネットワークタブで、「キャプチャの開始」ボタンをクリックした状態で、目的のWebページヘアクセス。
3.ヘッダ情報をみたいファイルをクリック
以上の操作で以下のようにヘッダ情報が表示されます。
Firefoxでヘッダ情報を見る方法
Firefoxの方法は「以前の投稿」で書いたのでそちらを参照してください。
それではブラウザキャッシュの設定について見ていきます。
Browser Cache – General
ここで訪問者のブラウザに、どのようなヘッダーを渡すか指定します。項目を見ればわかりますが、キャッシュの保存期限、キャッシュをコントロールするためのヘッダー情報、ファイルの圧縮の有無など、細かく設定できることがわかります。
サーバの設定をしたことのある方ならピンとくると思いますが、従来Apacheで設定する部分です。W3 Total Cacheではこれらの設定を、WordPressのルートディレクトリにある「.htaccess」を編集することで設定しています。
CSS&JSやHTML&XMLなどの設定
ファイルの種類ごとに設定が分かれていますが、基本的な構成は同じなので、まとめて解説します。
Set Last-Modified header
Last-Modifiedとは最終更新日の意味です。この値を元にキャッシュの整合性を検証します。
初回アクセス時にブラウザは、サーバからのレスポンスヘッダでLast-Modifiedを受け取ります。
次回アクセス時にブラウザはリクエストヘッダにIf-Modified-Sinceに付加して送信します。
値を受け取ったサーバはLast-Modifiedの値と照合して更新されていなければ304 Not Modifiedを返します。
304 Not Modifiedを受け取ったブラウザはクライアント側に保存されたキャッシュを再利用します。
Last-Modifiedの例
Last-Modified Tue, 06 May 2014 00:00:00 GMT
Apacheでは特別指定しない限りLast-Modifiedが付加されます。
無効にしたい場合は以下のように「.htaccess」でmod_headersディレクティブを利用して削除することもできます。
<IfModule mod_headers.c> Header unset Last-Modified </IfModule>
Apache公式、mod_headersのドキュメント
http://httpd.apache.org/docs/2.4/ja/mod/mod_headers.html
Set expires header
expiresでは有効期限を指定します。指定された日付までファイルが新しくなることは無いという宣言をします。
「キャッシュの整合性を確かめるだけなら上記Last-Modifiedだけで良いのでは?」と考えると思いますが、一部のブラウザでキャッシュのヘッダーの解釈が異なるため、主要ブラウザでキャッシュを有効にするにはLast-Modifiedとexpiresを併記する必要があります。(ここでもIEが原因です…。)
詳しくはこちらへ
ブラウザキャッシュによる HTTP 高速化チューニング – drk7jp
expiresの例
Expires Tue, 13 May 2014 11:25:20 GMT
Apacheでexpiresを有効にする場合
<IfModule mod_expires.c> ExpiresActive On </IfModule>
Apache公式、mod_expiresのドキュメント
http://httpd.apache.org/docs/2.4/ja/mod/mod_expires.html
Expires header lifetime
このオプションで指定した期間だけブラウザキャッシュが有効になります。
Apacheで設定する場合はmod_expiresディレクティブでファイルの種類と有効期限をセットで指定します。
Apacheで設定する場合(この例でいうA604800の部分を指定している)
<IfModule mod_expires.c> ExpiresActive On ExpiresByType text/html A604800 </IfModule>
Expiresを設定し場合の例
キャッシュの有効期限を、アクセスした時間であるDateから604800秒(7日)後に指定した場合。
Date Wed, 07 May 2014 00:00:00 GMT Expires Wed, 14 May 2014 00:00:00 GMT
もう一つ、後述するCache-Controlヘッダーフィールドの値もこの指定で決まります。Cache-Controlフィールドには多くのディレクティブを指定することができますが、W3 Total Cacheではmax-ageの値を決めるのに利用しています。
Cache-Controlの付加は後述する「Set cache control header」で制御されています。
Cache-Controlの例
Cache-Control max-age=604800
Set cache control header
Cache-Controlヘッダを付けるかどうかを指定します。
Cache-ControlをApacheで指定する場合
<IfModule mod_headers.c> Header set Pragma "public" Header set Cache-Control "public, must-revalidate, proxy-revalidate" </IfModule>
Cache-Controlの挙動ですが、ブラウザやバージョンによって異なります。詳しく知りたい方は、以下のページで解説されているので参照してください。
ブラウザキャッシュとレスポンスヘッダ – murankの日記
Cache Control policy
Cache-Controlヘッダーに何を指定するかを設定します。
Cache-Controlヘッダーとは前出のExpiresで指定したキャッシュの挙動を制御する役割をします。
重要な部分ですので、設定の意味をしっかりと理解して指定するようにしてください。
cache (“public”)
publicディレクティブは全クライアントで共通のキャッシュを参照するという指定。反対の意味を持つ指定にprivateディレクティブがある。
「cache (“public”)」を選んだ場合のCache-Controlの例
Cache-Control public
ブラウザによってはキャッシュの有効期限内であればサーバへのリクエストをしなくなる。またサーバ側で更新チェックもしないためリソースの節約には有効。反面、サーバ側でキャッシュを変更してもクライアントのキャッシュが置き換えられないので注意してください。
cache with max-age (“public, max-age=EXPIRES_SECONDS”)の例
今度は「max-age=604800」が付加されました。
「max-age」はキャッシュの有効期限を指定するディレクティブです。Last-Modified(最終更新日)とExpiresByTypeの有効期限で計算します。
ちなみに、全体の設定をするExpiresDefaultディレクティブという設定もありますが、併記された場合はmax-ageが優先されます。
cache with max-age (“public, max-age=EXPIRES_SECONDS”)の例
Cache-Control max-age=604800, public
cache with validation (“public, must-revalidate, proxy-revalidate”)
バリデーションという名前から分かるように、キャッシュの検証を行います。
「must-revalidate」は次回アクセス時にキャッシュの整合性を必ず確認するように促す設定です。
「proxy-revalidate」は中間のキャッシュサーバに対して整合性を確認するように促す設定です。こちらはnginxやCDN等のリバースプロキシ用。
cache with validation (“public, must-revalidate, proxy-revalidate”)の例
Cache-Control public, must-revalidate, proxy-revalidate
cache with max-age and validation (“max-age=EXPIRES_SECONDS, public, must-revalidate, proxy-revalidate”)
これはキャッシュの有効期限をmax-ageで指定して、かつキャッシュの整合性を確認する指定です。最も多くのブラウザでキャッシュを適用でき、キャッシュの検証も行える設定です。デフォルトはこの設定になっています。
cache with max-age and validation (“max-age=EXPIRES_SECONDS, public, must-revalidate, proxy-revalidate”)の例
Cache-Control max-age=604800, public, must-revalidate, proxy-revalidate
cache without proxy (“private, must-revalidate”)
privateは特定のユーザー(ブラウザ)に対して専用のキャッシュであることを指定します。個人情報が記載されたページなど、特定のユーザー向けコンテンツの場合に指定します。
特定のユーザー用なので、中間のキャッシュサーバやリバースプロキシなどにキャッシュは保存されません。
cache without proxy (“private, must-revalidate”)の例
Cache-Control private, must-revalidate
ちなみに個別のユーザーに対してはキャッシュを利用することを禁止していません。
no-cache (“max-age=0, private, no-store, no-cache, must-revalidate”)
これは単純にキャッシュを無効にする設定です。
Cache-Controlのmax-ageはExpiresより優先されるため、全てのキャッシュに関するヘッダを無視してキャッシュが無効になります。
no-cache (“max-age=0, private, no-store, no-cache, must-revalidate”)の例
Cache-Control max-age=0, private, no-store, no-cache, must-revalidate
Set entity tag (ETag)
ETagとはエンティティタグの略で、キャッシュとサーバーのinode情報から作成されるユニークな識別子です。
サーバ側からはEtagとしてレスポンスが帰ってきて、Webブラウザ側ではIf-None-Matchとして問い合わせを行います。両方の値が一致すればキャッシュは更新されていないということで、サーバは304 Not Modifiedを返します。
リクエストヘッダにIf-None-Matchと、If-Modified-Sinceが両方含まれる場合は、ETagのIf-None-Matchが優先されます。
Last-ModifiedとETagのヘッダでの表記
リクエスト時 | レスポンス時 | |
---|---|---|
Apacheの標準 | If-Modified-Since | Last-Modified |
ETag | If-None-Match | ETag |
ETagがあれば、Last-Modifiedが無くてもキャッシュの適合性は調べられるのではないかと思い検証したところ、ChromeのみETagだけではキャッシュが有効になりませんでした。そのためLast-Modifiedなども併記したほうが良さそうです。
ETag注意点として負荷分散のために複数のサーバでキャッシュを生成している場合、同じ内容のキャッシュであってもサーバによってinode情報が異なるため、ETagも異なります。キャッシュサーバを複数おいている場合などは注意が必要。
レスポンスのETagの例
Etag 756dfe72eb16f2640898a35cd6c2cdc7
リクエストのIf-None-Matchの例
If-None-Match 756dfe72eb16f2640898a35cd6c2cdc7
Set W3 Total Cache header
何も指定しないとX-Powered-ByにはPHPのバージョンが付加されます。細かなことですがセキュリティ上、非表示のほうが好ましいのでチェックしておいたほうがいいと思います。(W3 Total Cacheにも脆弱性が見つかったりしているので、一概にどちらがいいかは言えませんが…。)
何も指定しない場合のレスポンスヘッダの例
X-Powered-By PHP/5.4.12
ヘッダーにW3 Total Cacheの情報が付加されたレスポンスヘッダの例
X-Powered-By W3 Total Cache/0.9.4
ちなみにサーバ管理者なら「php.ini」に「expose_php = Off」と指定することで非表示にすることもできます。
Enable HTTP (gzip) compression
ファイルを圧縮して転送することで転送量を減らします。mod_deflateで指定されます。
CSSやHTMLファイルは効果が高いのでぜひ導入しましょう。
サーバ側の設定ですでに有効になっていることもあるので、ヘッダー情報で確認してみてください。このサイトを設置しているロリポップ!ではデフォルトで有効になっています。
詳しくは「以前の投稿」でまとめたので参照してください。
gzipが付加されたレスポンスヘッダの例
Content-Encoding gzip
mod_deflateについては「過去の投稿」でまとめたので、必要な方は参照してください。
注意点1 W3 Total Cacheの生成するキャッシュの有効期限について
今までキャッシュに関する設定をしていて「W3 Total Cacheがサーバに作成するページキャッシュの有効期限って、どこで決めるの?」と疑問に思っている方もいるのではないでしょうか?
ネット上で情報を探しても「ブラウザキャッシュで設定した値と連動する」といった話や、「Empty All Cashesをクリックした時だけ削除される」と諸説飛び交う状況でした。
今回W3 Total Cacheについて調べてみようと思ったのも「設定したキャッシュの期限より早いタイミングでページキャッシュが再生成されている」と気がついたからです。
実はこのキャッシュの有効期限を決める設定は、プラグインの設定画面にはありません。
ページキャッシュの期限はmaster.phpで指定する
先に答えを書きましたが、調べてみたところ「/wp-content/w3tc-config/master.php」の92行目あたりにある「pgcache.lifetime」の値でページキャッシュを制御しているようです。
デフォルトで3600秒(1時間)に設定されています。
設定を変更するには、この値を任意の秒数に変更してファイルを保存した後、W3 Total Cacheのプラグインページに移動して、変更はしなくて良いので「Save all settings」ボタンを押してください。
すると新しいページキャッシュの有効期限が設定されます。
注意点2 全ての設定を無駄にするpgcache.lifetime
「pgcache.lifetime」で設定された有効期限を過ぎると、ブラウザキャッシュの「Last-Modified」や「Cache-Control max-age」の設定を無視して再度ページキャッシュを生成します。
つまり、デフォルトの1時間でキャッシュを破棄する設定では、1時間に1回以下のアクセスの場合、無駄にページキャッシュを作成して、毎回破棄するという不毛な動作を繰り返します。
つまり、ブラウザキャッシュの項目でHTML&XMLの有効期限を1時間以上に設定する場合は、合わせてpgcache.lifetimeも変更する必要があります。
個人的にはバグと言えるのではないかな?と思っているのですが、どうなんでしょうか。
注意点3 .htaccessの設定について
普段からWordPressの高速化に敏感な方は、mod_deflateやmod_expiresといった設定を「.htaccess」にしていると思います。
上で解説したようにW3 Total CacheもWordPressのルートディレクトリにある「.htaccess」を利用して設定をしています。
思わぬエラーの原因になるためブラウザキャッシュやファイルの圧縮をする場合は、全て自分で設定するか、全てW3 Total Cache任せるか、どちらか一方にしたほうが良いと思います。
私の場合は両方で設定したところ「どちらの設定も無効になりブラウザキャッシュが機能しない」という最悪の結果になりました。
これでW3 Total Cacheのキャッシュに関する設定と注意点の解説は終わりです。
他にもユーザーエージェントによる振り分けや、CDN用の設定もありますが、既にかなり長くなってしまったので別の機会がありましたら解説します。
多機能なのは嬉しいですが、ここまでくると、Apacheの設定をするのと変わらない知識が必要です。
もはや手軽に導入できるキャッシュプラグインではなく、サーバ管理者用のチューニングプラグインといった認識でいいかもしれません。
ピンバック: WordPress 独学者にありがちな9つの致命的な失敗
ピンバック: WordPress SEO 基本カスタマイズの7ステップ
商用ページをWPで運営している場合などは広告の関係などがあるので、PreLoadはonにしたほうが良いと思います。
PreLoadを行っていないと、過去に作成されたページキャシュは更新対象のフラグがつかず(拡張子に.oldを付加してリネーム)、いつまでも残ってしまっている気がします。
PreLoadを行うとサーバの負荷は増大しますがPreLoadは必須だと考えています。
というかPreLoadの動きを見てみると、再作成をするというより事前に.oldにリネームする処理を行っているだけな気がします。
コメントありがとうございます。
これは個人的な考え方ですが、キャッシュの有効期限はキャッシュを管理するために用意されたものを使うのが適切だと思います。
このページのW3 Total Cacheで言えばpgcache.lifetimeや、webサーバで言えばnginxのリバースプロキシの設定などです。
そうしないと、仰るとおりブラウザに正しく更新フラグが渡せず、古いページを参照してしまうということも起きます。
また、更新フラグをPreLoadに頼ると、数千、数万のページが存在する場合、PreLoadがボトルネックになりかねません。
ちなみにPreLoadの動作ですが、wp-cronで擬似的に行っているためサーバ環境によってはキャッシュが正しく作成されないことも多いようです。
ピンバック: W3 Total Cache を導入してみた « Everyday Pieces ::