symfonyでsuper cacheを実現するsfSuperCachePluginの、symfony1.2での使い方について。
super cacheは、動的にページを生成するWebアプリケーションにおいて、ほとんどの場合にWebサーバの仕組みを使って静的に作成したhtml(等)を直接クライアントに返すことでサーバの応答を早くし、サーバの負荷も軽減する手法です。
よく知られているのはWordPressのSuperCacheプラグインです。これを正しく設定すれば、動的生成でありながら静的生成のパフォーマンスを持つブログを運営することができます。
これまで自作でsuper cache相当の仕組みを作ったことはあるのですが、symfonyのプラグインがあるのでこれが使えるかどうか調べてみました。
とりあえず、READMEにあるように進めてみます。
プラグインのインストール
まず、プラグインはsymfony1.0にしか対応していませんので、普通にsymfonyコマンドでインストールしようとするとエラーになります。
コマンドインストールで失敗したときはいつもそうですが、パッケージを持ってきて自分で展開してみます。バージョンチェックが入ってるだけのことも多いので、これで動いてしまうプラグインも多いです。
> wget http://plugins.symfony-project.org/get/sfSuperCachePlugin/sfSuperCachePlugin-1.0.5.tgz
展開したら、sfSuperCachePlugin-1.0.5 というフォルダを、symfonyの作業フォルダ以下の plugins/sfSuperCachePlugin というフォルダにリネームしつつコピーします。
あとは、pluginsの下のプラグインを全部読むようになっていればsymfony ccするだけで自動的にロードされます。なってなければ、config/ProjectConfiguration.class.php のsetup()で、enableAllPluginsExcept()等を使って読み込まれるプラグインに指定してください。
このまま先へ進んでいくと、1.0と1.2の非互換でエラーになります。先に修正箇所を示すと、sfSuperCacheFilterの次の行
$uri = sfRouting::getInstance()->getCurrentInternalUri();
を、以下のように変更する必要があります。
$uri = sfContext::getInstance()->getRouting()->getCurrentInternalUri();
キャッシュ格納ディレクトリの用意
(symfonyアプリ)/web 以下に、静的ファイルの置き場を作ります。READMEにならって”cache”ディレクトリにします
> cd web
> mkdir cache
Un*xの場合はオーナーやパーミッションも調整してください
フィルタを噛ませる
プラグインの中に入ってるphpは、フィルタファイル一個だけです。これを(frontend)/filters.yml の # insert your own filters here のところに追加します。
supercache: class: sfSuperCacheFilter param: cache_dir: cache with_host: false
ホスト名を複数持たないならwith_hostはfalseでいいです。持つ場合、この後の設定も準じて変わるのでREADMEを読んでください。
リクエストがまず静的ファイルを見に行くように、.htaccessを修正
web/.htaccess を書き換えます。以下の2行のところを、
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
たとえば、以下のように書き換えます。
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/symfony_apps/sandbox/web/cache/supercache/%{PATH_INFO}.php -f
RewriteRule ^(.*)$ cache/$1.php [L]
この書き換え、READMEについてきたREQUEST_URIを使ったものが動かなかったので、自分で動くものを探してこんな風にしました。サブディレクトリにアプリを置いたりしなければREADMEのままのでも動くのかも。mod_rewriteは難しくてよくわからんです。
mod_rewriteが思うように動かないときは、とにかくhttpd.confの設定でrewrite logを取り、出たログを読みましょう。
やってるのは、
web/cache/ほげほげ/ふがふが.php
というファイルがアクセスされて、もしそれがあったら、そのファイルを直に実行して表示してしまう、という処理です。
もしファイルが無かったら、mod_rewriteの処理は下方のルールに落ちて行って、いつものフロントエンドコントローラ(web/index.php)を呼ぶようになっています。
これで、staticファイルが出来てればそのまま表示、出来てなければsymfonyを普通に実行(し、filters.ymlで挟んだフィルタがstaticファイルを生成)、というsuper cacheが完成となります。
super cacheを動かす条件
フィルタファイル sfSuperCacheFilter.class.php の中を読むとわかるのですが、super cacheが発動するには、いろいろな設定がされている必要があります。そうしないと、super cacheを動かしてたつもりが普通のキャッシュされたファイルを見てたりすることにもなります。
- sf_cacheがtrue/onであること
- $_GETや$_POSTのパラメータが無いこと
- sf_debugがfalseであること、つまりデバッグモードでは呼ばれません
- sf_no_script_nameがtrueであること
- エラーコードが200(正常)であること。エラーページとかを403で返しているなら、それはsuper cacheの対象外です
- そのmoduleのdefault cacheが enable: on であること
- そのmodule/actionの cacheが enable: on であること
- そのmodule/actionの with_layout: がtrueであること
キャッシュを使うことになってるページで、ページ全体をキャッシュして問題無く、GET/POSTパラメータも渡ってこない(パラメータが違えば普通ページ内容も変わりますから)という条件。
これ全部満たして、はじめてsuper cacheフィルタが効きます。
sfSuperCacheFilter::execute()のチェック文を、デバッガ等で確認しながらsettings.ymlやcache.ymlの設定を変え、(symfony ccもして、)動く設定になってることを確かめてください。
superキャッシュの動作確認
この状態でモジュールをつくり、適当にアクセスしてください。
frontend_dev.phpとか呼んじゃダメですよ。debug offなのでprodである/ (= index.php)を呼びます。
web/cache/(アプリ名)/(モジュール名)/(アクション名).php
などとファイルが出来ていたら、まずフィルタによるstaticファイル生成は合格です。
次に、もう一度アクセスしたときにこの生成されたファイルが開いてるのか、それともsymfony標準のcacheが開いてるのかを確認します。これは、cache/frontend/prod/template/… 以下の標準のキャッシュファイルを手で消してから、ブラウザでアクセスしてみるとわかります。staticなファイルが呼ばれて開かれていれば、標準のキャッシュは作られないはずです。
super cache完成か?
とまあ、プラグインで用意されているのはここまでです。しかし、生成されたstaticなファイルは拡張子が.phpなんですね。そこでそれらのファイルをエディタで開くと、先頭にphpのコードが一行入ってます。
<?php if (time() > 1241771234) { unlink(__FILE__); header('Location: '.$_SERVER['REQUEST_URI']); exit; } ?>
これで、自身のキャッシュ寿命を計りつつ、もし寿命が来ていたら自分自身を削除してもう一度同じURLにリダイレクト、とすることで、expireの処理を行なっているようです。
と、いうことは、このsuper cache、phpを回避してないのですね。厳密には super cacheと言えないのではと思います。たとえ一行とは言え、phpインタプリタをファイル毎に起動しているのです。
このプラグインはここまでなので、PHPを完全にスルーするsuper cacheの実現には、もう一手間かける必要があります。
生成するのは.phpじゃなく.htmlにし、もちろん先頭にphpコードは入れません。.htaccessの定義も.htmlに変えます。
そうなると、キャッシュのexpire判定は自分でやらせるわけには行きません。別のトリガーでこのキャッシュファイルを消すことになります。
たとえば、cronで動かしたスクリプトで定期的にこのcache/以下を見て、ファイル生成時を見つつ古すぎるものを消す、が一案。
もう一つは、CacheManagerで明示的にキャッシュをクリアされるタイミングで、このcache/以下の該当する静的ファイルも削除することです。
super cacheで用意したcache/以下のキャッシュファイルは、先頭行のPHPでexpireを自己診断した際しか消えないので、どのみちCacheManagerでのクリアをどうするかというのは検討しないといけないですね。
コメント
“symfony1.2でsfSuperCachePluginを使う” への2件のフィードバック
どこがどうわかりにくいのかさっぱり伝わりませんね。
もうちょっと気合入れたコメントお願いしますw
すげーーーー分かりにくい記事だね
もうちょっと気合入れてかいてよww