Deployerというデプロイツールを使って、CakePHPのアプリケーションを複数台のサーバへデプロイするときにハマった話。Deployerに限らずデプロイツールなら何でもあり得る話だと思う。
Webサーバをスケーラブルな構成にした時に、セッションやキャッシュ情報などを共有して使いたいので、RedisやMemcachedのキャッシュエンジンを使用すると思うけどCakePHPの一部の情報は 共有させてはいけない ということが分かった…。
cake_core は各サーバでキャッシュする
Config/core.php
の下の方にキャッシュに関する記述があるけど、デフォルトで存在している_cake_core_
。こいつは複数台で共有してはいけない。
cake_core の中身
"a:67:{s:9:\"Configure\";s:82:\"/var/www/example.com/releases/20151028025606/lib/Cake/Core/Configure.php\";s:4:\"Hash\";s:80:\"/var/www/example.com/releases/20151028025606/lib/Cake/Utility/Hash.php\";s:5:\"Cache\";s:79:\"/var/www/example.com/releases/20151028025606/lib/Cake/Cache/Cache.php\";s:11:\"RedisEngine\";s:92:\"/var/www/example.com/releases/20151028025606/lib/Cake/Cache/Engine/RedisEngine.php\";s:11:\"CacheEngine\";s:85:\"/var/www/example.com/releases/20151028025606/lib/Cake/Cache/CacheEngine.php\";s:12:\"ErrorHandler\";s:86:\"/var/www/example.com/releases/20151028025606/lib/Cake/Error/ErrorHandler.php\";s:7:\"CakeLog\";s:79:\"/var/www/example.com/releases/20151028025606/lib/Cake/Log/CakeLog.php\";s:19:\"LogEngineCollection\";s:91:\"/var/www/example.com/releases/20151028025606/lib/
こんな感じでCakePHPライブラリへのファイルパスがキャッシュされている。
Deployerでデプロイすると(capistaranoもそうだけど)、/releases/の下にタイムスタンプでディレクトリを作成し、実ファイルを配置する。これが複数台にデプロイすると若干ずれることがある。
・サーバA : /releases/20151028025606/
・サーバB : /releases/20151028025607/
みたいに。
つまり、先にアクセスがあった方のサーバのファイルパスがキャッシュされ、別のサーバからアクセスがあった際に、そんなファイルないよーといってInternalServerErrorを引き起こす。
Cache::config('_cake_core_', array(
'engine' => 'File',
'prefix' => $prefix . 'cake_core_',
'path' => CACHE . 'persistent' . DS,
'serialize' => ($engine === 'File'),
'duration' => $duration
));
そういったわけで、_cake_core_
のキャッシュ設定はなにがあってもFile
もしくはApc
とか各サーバで完結するようなキャッシュ方式を採用しよう。
はー…、分かっていれば常識レベルなんだろうけどなー。