とあるサイトで使われているWPを高速化・低負荷化したいという話があり、いくつか提示した中で一番簡単なキャッシュプラグインの導入を試したいということで、W3TCの導入をしました。
その時にテスト用サーバで試して問題が出たこととその対策と、tipsをメモします。
W3TCの基本的な設定
W3TCの導入については下記ページが大変参考になりました。
基本的な設定はここのサイトの設定にしたがっています。
W3 Total Cache のおすすめの設定方法
https://bazubu.com/w3-total-cache-23854.html
ログイン後にW3TCの設定ができなくなる
このWPではマルチサイトで運用されていました。
W3TCの設定終了後にログアウトして再度ログインすると、W3TCの詳細設定メニューが出ないというか、特権管理者(ネットワーク管理者)になれなくなっている感じでした。
これは下記設定で回避出来ました。
「Miscellaneous」の「Use single network configuration file for all sites.」はチェック外す
特定の環境で文字化けが発生した
自分のブラウザ環境では問題なかったのですが、一部の人が文字化けと言うか完全に化けた表示しかされない状況になりました。
見た感じでgzipがそのまま表示されている感じだったので、下記設定で解決できました。
「Browser Cache」の「Enable HTTP (gzip) compression」はチェック外す
同じ症例を探してみると、どうも古いPHP(PHP5.4以前)だとこの現象が発生するらしいです。
【Wordpress】W3TCが原因で文字化けする場合の対処 | TeraDas−テラダス
http://www.teradas.net/archives/24204/
500 Internal Server Error が発生する
毎回ではないのですが、たまに500エラーが発生するようになりました。
エラーログを確認すると、W3TCのオブジェクトキャッシュ処理中にPHPがメモリ不足で落ちていることがわかりました。
その環境ではmemory_limitが128Mになっており、同様の件を探すとやはりW3TC導入でメモリ不足でエラーになっている件がいくつか見つかりました。
その結果からObjectキャッシュとDatabaseキャッシュを利用する場合、512M程度までは上げておいたほうがよい感じでした。
メモリ割り当てを増やしてもメモリ不足でエラーが出る
上記問題に対応するため、memory_limitを512Mにしてもメモリ不足でエラーが出ることがありました。
調査すると、Pageキャッシュでは問題なく、ObjectキャッシュとDatabaseキャッシュで問題が出るため、このキャッシュを利用しないように設定しました。
ObjectキャッシュとDatabaseキャッシュは、Pageキャッシュに比べると速度への貢献が低いので、無理に使わなくても良いと思われます。
また後述のようにObjectキャッシュを使うと、スマホとPCでページ切り替えをしている場合にうまく表示できないという問題がでるようです。
「Database Cache」と「Object Cache」の「Enable」をチェック外す
スマホ用とPC用でページが混在してしまう
このサイトは同一URLでスマホ用とPC用のページが出るサイトだったのですが、スマホ用ページとPC用ページがうまく切り分けられず混在してしまう問題が発生しました。
そこでPC用とスマホ用、携帯用で別々のキャッシュを持つように設定します。
「User Agent Groups」の「1. High」と「2. Low」の「Enabled」をチェックする
PCとスマホを分けて綺麗に高速表示してくれるWPキャッシュプラグイン「W3 Total Cache」の簡単設定方法
https://nelog.jp/w3-total-cache
Objectキャッシュを使っていると、この設定をしてもうまくいかないらしいので、そのためにも前述のようにObjectキャッシュは使わないようにする必要があるようです。
W3 Total Cacheはスマホ版レスポンシブ表示でもキャッシュが効く
https://iphone-lab.net/page-cahe-mobile-397832/
スマホページが表示されるはずがPC版ページが表示されてしまう
キャッシュ導入後、スマホページが表示されるはずの条件でPC版ページが表示されてしまう問題が起こりました。
キャッシュファイルとアクセスログから調べてみると、iPadからの閲覧が行われたときに間違ったキャッシュが生成されていることがわかりました。
このサイトではPCとスマホ、携帯の表示切り替えを行っており、スタイルの切り替えは「Ktai Style」プラグインにより行っていました。
https://wordpress.org/plugins/ktai-style/
そこで、スマホ判定を行っている部分のコードを確認すると
/wp-content/plugins/ktai-style/operators/base.php
preg_match('/\b(iP(hone|od);|Android )/', $ua, $name)
となっていました。
この判定を行なう条件が、W3TCのスマホの条件と違っており、Ktai Style では iPad からのアクセスでスマホページの表示は行わないが、W3TCではスマホページとして扱うため、そこで差異が生じて iPad から見られた場合に、PC版ページがスマホ版のページとしてキャッシュされていることがわかりました。
そこでW3TCの設定を、Ktai Styleの判定条件に合わせるよう変更しました。
User Agent Groups -> Group name: 1.high -> User agents:
android iphone ipod
携帯ページがキャッシュ化されると文字化けする
携帯向けページがキャッシュ生成時には文字化けしないが、キャッシュから表示された場合には文字化けしてしまうことがわかりました。
調査すると、携帯向けはShift-JISで表示しているのですが、HTTPレスポンスヘッダのcharsetではUTF-8になっているためでした。
前述のように携帯向けページ表示はKtai Styleを利用しており、下記ソースから携帯向けは全て「SJIS-win」で出力されていることを確認しました。
/wp-content/plugins/ktai-style/operators/
emobile.php ezweb.php i-mode.php softbank.php willcom.php
$this->charset = 'SJIS-win'
W3TCの標準設定ではUTF-8として出力されるようになっていたため、まずはそこを修正しました。
各ページキャッシュディレクトリの .htaccess に AddDefaultCharset UTF-8 が付けられてしまうことを抑止します。
Page cache -> Advanced -> Charset:
「Disable UTF-8 blog charset support」をチェック
しかし、ここを修正してもUTF-8として返っていました。
/etc/php.ini にあるPHPのデフォルトcharsetでUTF-8が設定されており、キャッシュ表示でそれが強制されてしまっていたためでした。
しかし、キャッシュファイルはHTMLを直接apacheから表示しているはずなのに、なぜPHPのデフォルトcharsetが使われるのかが不思議でした。
ディレクトリ指定で表示されるページが、W3TC が生成した mod_rewrite のルールで _index_low.html などが返されるようになるのですが、元々の apache の PHPの設定で DirectoryIndex の指定が index.php になっており、先にPHPが動く設定が生きてしまうようです。
そこでWPのルートのディレクトリにある .htaccess (W3TCの設定が追記されるファイル)に、PHPのデフォルトcharsetを設定しないように追記しました。
### for W3TC Ktai cache php_value default_charset none ###
これでやっと携帯向けページのレスポンスヘッダに charset=UTF-8 がつかなくなり、文字化けが発生しなくなりました。
カテゴリーページのキャッシュが更新されない
カテゴリー(category)ページだけは、そのカテゴリーのエントリーを編集しても更新がされないという問題がありました。
ページキャッシュの設定で「Purge Policy」の「Post terms pages」などをチェックを入れてもダメでした。
調べてみると同様の問題がレポートされていました。
Page cache for categories not updating with W3 Total Cache - WordPress Development Stack Exchange
https://wordpress.stackexchange.com/questions/25425/page-cache-for-categories-not-updating-with-w3-total-cache
そこでさらに調べると、この問題だけ解決するためのプラグインがありました。
やはりタグやカテゴリーでの生成ページを消去することが出来ないという問題があるようです。
W3 Total Cache Purge All Page — WordPress Plugins
https://ja.wordpress.org/plugins/w3-total-cache-purge-all-post/
非常に小さなプラグインですが、これで解決できました。
動的なコンテンツの含まれるページの更新が遅い
デフォルトのページキャッシュの維持時間が1時間になっているため、動的なコンテンツが含まれる場合、最大で1時間更新が遅れます。
Page Cache -> Advanced -> Garbage collection interval:
で設定が行なわれており、デフォルトは「3600」秒となっています。
キャッシュ保持時間を例えば10分程度と短くすれば、設定時間より最大で10分遅れ(期待値で5分遅れ)でコンテンツが更新されるようになります。
このキャッシュ保持時間ですが、WP-CronというWordPressの持っている疑似cron機能を利用して、そこにキャッシュ削除の呼び出しを登録することで行われています。
このWP-Cron機能は、何分毎という指定ではなく、毎回何時以降に実行という登録を行なう必要があります。
W3TCでは、既にキャッシュ削除の登録が行われていると登録のし直しが行われず、その登録された処理が行われた後に再度登録されるとき、あたらしい設定での登録が行われます。
つまり、キャッシュ保持時間の変更を行っても、次のキャッシュ削除が行われるまではキャッシュ保持時間が変わりません。
また、WP-CronはWordPressへのなんらかのアクセスをトリガとして動くため、ほとんどアクセスがない場合は指定した時間にcronの処理が動くとは限りません。
どうしてもリアルタイムで更新させたい場合、特定ページのみキャッシュさせないようにすることが出来ます。
Page Cache -> Advanced -> Never cache the following pages:
に下記のように指定すると、example_directory以下のページはすべてキャッシュされなくなります。
/example_directory/*
キャッシュの場所
/wp-content/cache 以下のファイルにキャッシュが作られます。
その下の page_enhanced にページキャッシュが、db にデータベースキャッシュ、object にオブジェクトキャッシュが作られます。
ページキャッシュは対応するドメイン/ディレクトリ/ファイル毎に対応するディレクトリが掘られてそこに「_index.html」という名前でキャッシュが作られます。
スマホ用や携帯用のキャッシュは、「User Agent Groups」で設定した名前「high」や「low」を使って「_index_high.html」のようにキャッシュが作られます。
動きがおかしくて、どこまでは正しくキャッシュが生成されているのかを見たい場合にここから確認します。
ページキャッシュの表示方法と有効期間
ページキャッシュは「Disk: Enchanced」の場合、前記キャッシュ場所にHTMLとして保存されます。
そしてページキャッシュの表示は、WordPressやPHPを介さずにapacheからこの場所のファイルが直接表示されるようになっています。
これは /.htaccess にW3TCにより追記された mod_rewrite のルールにより行われます。
キャッシュが存在していればそのキャッシュが表示されるようになっており、キャッシュの有効期間という考えはありません。
編集が行われた時に古いキャッシュが削除されることでキャッシュの同期が行われるようになっています。