Passenger は fork 時の copy-on-write により複数のアプリケーションプロセスが消費する実メモリのサイズが小さくなるようになっていて、その fork も以下のような3段階で行っているようです。
- 最初に起動する spawn server から fork して、 Rails をロード (framework spawner)
- framework spawner から fork して、アプリケーションをロード (application spawner)
- application spawner から fork して、リクエストを処理する過程で必要なファイルをオートロード (application instance)
spawn server は apache が終了するまで生きているようなんですけど、 framework spawner と application spawner にはタイムアウトする時間が設定されていて、 Passenger 2.0.3 のデフォルトではそれぞれ、30分、10分となっています。
したがって、前回のアクセスから10分過ぎると、再度 application spawner から生成し直すのでレスポンスに時間がかかります。
ということは、 application spawner のタイムアウト時間を十分に長くすればよいということで、無理矢理 passenger のファイルを変更。
/usr/lib/ruby/gems/1.8/gems/passenger-2.0.3/lib/passenger/constants.rb:
- FRAMEWORK_SPAWNER_MAX_IDLE_TIME = 30 * 60
- APP_SPAWNER_MAX_IDLE_TIME = 10 * 60
+ # keep them alive for a week
+ FRAMEWORK_SPAWNER_MAX_IDLE_TIME = 7 * 24 * 60 * 60
+ APP_SPAWNER_MAX_IDLE_TIME = 7 * 24 * 60 * 60
Passenger 2.0.3 の段階では上記のような変更が必要ですが、 将来のバージョンでは apache の設定ファイルで RailsFrameworkSpawnerIdleTime, RailsAppSpawnerIdleTime を指定すれば変更できるようになるようです。
また、 Phusion Passenger users guide - 8.3 Capistrano Recipe の note に書いてあるように、デプロイ後に新しい application spawner が生成されても古いのが残ったままになるので、デプロイするときに kill。
config/deploy.rb:
namespace :passenger do
namespace :application_spawner do
desc "kill Passenger ApplicationSpawner"
task :kill do
run "kill $( passenger-memory-stats | grep 'Passenger ApplicationSpawner' | awk '{ print $1 }' ) || true"
end
after "deploy:update_code", "passenger:application_spawner:kill"
end
end
Passenger のドキュメントに書かれているように "Passenger spawn server" を殺すには root 権限が必要なので代わりに application spawner を kill。なんとなく不安定な気もするけど、これで様子を見ることにします。
参考資料:
Wishlist — passenger — GitHub
RailsFrameworkSpawnerIdleTime and RailsAppSpawnerIdleTime - Phusion Passenger Discussions | Google Groups
Modrails ... Slow first request ... - Phusion Passenger Discussions | Google Groups
2 comments:
デプロイを繰り返すと古い application spawner が溜まってしまう問題について追記。
Passenger 2.2.0 でデプロイしたときに application spawner が残る問題は解消されたようです。
Post a Comment