メモ: puma on heroku, worker と thread
web serverとしてpumaを用い、Railsアプリケーションをherokuで運用するにあたり workerやthreadという話が出てきたのでメモ。
ネタ元は: Deploying Rails Applications with the Puma Web Server | Heroku Dev Center
Workers
Workerとは
pumaの文脈でいうworkerは、herokuでいうworkerとは別の概念であることに注意。 herokuのworkerはそれ用のdynoでバックグランド処理などを行うプロセス。一方、pumaのworkerは、pumaがforkする OSのプロセス。これによりRailsは並行してリクエストを処理できるようになる。
Worker processはOSレベルで独立なので、thread safeである必要はない。 自身のアプリがthread safeかどうかわからない、もしくはthread safeでない場合とりあえずworker processだけ増やせば安全にパフォーマンスの向上を図れるのだろうか。
設定
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
のように環境変数でWEB_CONCURRENCYを設定する。ここら辺の詳細はProcfileの設定にて: Deploying Rails Applications with the Puma Web Server | Heroku Dev Center
Worker数について
workerはプロセスなので増やすごとにメモリ使用量が増える。なのでdyno一つにつきどれぐらいworkerを生やせるかはメモリ使用量による。
free
, hobby
, standard-1x
dynoでは、典型的なRailsアプリだとだいたい2-4のworkerが目安らしい。個々の環境においては、dynoで利用可能なメモリの上限を超えた時に生じるR14 errorsを監視して設定する。
詳しくは: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#workers
Threads
Pumaはそれぞれのリクエストをthreadを使い処理できる。なのでworker数がリクエストの並行処理数を決め、thread数がそのそれぞれのリクエストの並行処理数を決める感じだろうか。
MRIにおいてはGILがあるので実行されるthreadは常に1つ。しかしIOの処理時にはGILはロックされない。そしてほとんどのRailsアプリは大量のIOを伴う。そのため、thread数を増やすことでPumaは複数のthreadを処理できるようになり、その結果スループットは上がる。
Pumaはthread数の上限と下限を設定できるが、heroku的には同じ値を設定するのがお勧めとのこと。
詳しくは: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#threads
参考リンク
Deploying Rails Applications with the Puma Web Server | Heroku Dev Center
マルチスレッド/プロセスまとめ(Ruby編) - Qiita
余談
thread safeなRailsとかそういう情報って少ない
How do I know whether my Rails app is thread-safe or not? - by Jarkko of Bear Metal