はじめに
いま開発中のRailsアプリケーションのRackサーバーは最初Unicornを使っていたのですが、諸々の事情でPumaの方を使いたいということになった。 まだリリースもしていないのでやるなら早めに変えちゃおうということでPumaについて調べてみた。
Pumaとは
Pumaとはスピードと並列性を追求したRubyのWebサーバーです。 RubyでWebサーバーを作るときの標準となっているRackに対応したライブラリになっています。
スレッドベースのWebサーバー
Pumaではリクエストの並列処理を実現するためにスレッドを利用しています。 リクエストを処理するためのスレッドを予めスレッドプールに指定した数だけ用意しておきます。リクエストが来るとそのスレッドに処理を任せることでスレッドベースの並列処理を行っています。
Rubyの処理系について
Pumaではスレッド用いるため、Rubyの処理系はRubinusやJRubyを推奨していますが、MRI(Ruby標準の処理系)でも利用することが可能です。
MRIにおけるスレッドの扱い
MRIでのスレッドはGlobal Interpreter Lockという機能によって利用が制限されています。 Global Interpreter Lockとは「同時には一つのスレッドしか動かないようにする」というものです。
たとえばRubiusのようにスレッドによる並列処理をサポートしている処理系では3つのスレッドを立ち上げて処理を行った場合、同時に処理をおこないます。 ただしMRIはGlobal Interpreter Lockのよって3つのスレッドを立ち上げて処理を行っても一度に一つのスレッドしか処理をおこないません。1つのスレッドが処理をおこなっている最中にBlocking IO(ファイルやの書き込みやTwitterAPIを叩くなど)によって待ち時間が発生したタイミングで別スレッドに切り替えて処理を進めます。
使い方
起動
Pumaを起動する場合、以下のコマンドを実行します。
$ bundle exec puma
railsの場合、以下のコマンドでも実行可能です。
$ bundle exec rails s Puma
もしサーバーをデーモンとして実行したい場合は-d
オプションを付けましょう
$ bundle exec puma -d
設定ファイルを指定する場合は-C
オプションのあとに設定ファイルへのパスを指定します。
$ bundle exec puma -C config/puma.rb
停止
Pumaを停止するにはプロセスに対してQUIT
シグナルを送ります。
rails s Puma
で起動した場合のデフォルトのpidファイルはtmp/pids/server.pid
にありますので、そこに記載されているプロセスIDに対してシグナルを送信します
$ kill -QUIT `(cat tmp/pids/server.pid)`
設定ファイルconfig/puma.rbを指定して起動した場合、その設定ファイルから*.pidファイルを探せるのでpumactl
というコマンドを使って簡単に停止することもできます。
$ bundle exec pumactl halt
再起動
Pumaの再起動はhot restartに対応しています。 hot restartとはnginxやunicornと同様にサーバーのソケットを開いたままリスタートすることを可能にします。それにより、ユーザーからのリクエストを待たせる事なくサーバーを再起動して新しいバージョンのアプリケーションに切り替える事ができます。
hot restartするにはpumaのプロセスに対してSIGUSR2
シグナルを送信します。
$ kill -SIGUSR2 `(cat tmp/pids/server.pid)`
設定ファイルを指定した実行した場合、pumactlで再起動をかけることも出来ます。
$ bundle exec pumactl restart
設定ファイル
puma起動時のオプションの指定である程度カスタマイズできるがやはり設定ファイルに書いて起動する方が管理しやすいです。 pumaの設定ファイルでなにをどう設定できるかまとめておきます。
ちなみに設定ファイルのサンプルはpumaのgithubレポジトリのpuma/examples/config.rbから手に入ります。
environment
pumaをどの環境で動作させるかを指定します。デフォルトは'development'になっています。 railsで使う場合は環境変数RAILS_ENVを直接environmentに指定するのが良いと想います。
# Set the environment in which the rack's app will run. The value must be a string # # The default is "development". # # environment 'production' environment ENV['RAILS_ENV'] # Railsで使う場合
daemonize
rackサーバーをデーモンにして起動するかどうかを設定します。
# Daemonize the server into the background. Highly suggest that # this be combined with "pidfile" and "stdout_redirect". # # The default is "false". # # daemonize # daemonize false daemonize true
pidfile
pidファイルを配置するパスを指定します。 Railsの場合、tmp/pids/puma.pidに配置するほうが良いと思います。
# Store the pid of the server in the file at "path". # # pidfile '/u/apps/lolcat/tmp/pids/puma.pid' pidfile "#{Dir.pwd}/tmp/pids/puma.pid"
state_path
サーバー情報を記載したstateファイルを配置するパスを指定します。 stateファイルはpumactlコマンドでサーバーを操作するのに使用します。 railsの場合、特別このようなファイルを配置するディレクトリはないので今回はtmp/pids/以下に配置しておきます。
# Use "path" as the file to store the server info state. This is # used by "pumactl" to query and control the server. # # state_path '/u/apps/lolcat/tmp/pids/puma.state' state_path "#{Dir.pwd}/tmp/pids/puma.state"
Cluster mode
クラスタモードとは複数のワーカープロセスを起動し、そのプロセスそれぞれでスレッドプールを持ちリクエストを処理する仕組みです。 ワーカープロセスの数は以下のように指定します。 Workerの数をマシンが持つCore数を超えないように気をつけて下さい。
# === Cluster mode === # How many worker processes to run. # # The default is "0". # workers 2
Thread Pool
Pumaはスレッドによってリクエストを処理します。スレッドをスレッドプールに貯めておく数の下限から上限を指定することが出来ます。
# Configure "min" to be the minimum number of threads to use to answer # requests and "max" the maximum. # # The default is "0, 16". # # threads 0, 16 threads 16, 16
bind
サーバーをどのように接続するかをURIで指定できます。
シンプルにTCPで接続する場合tcp://0.0.0.0:80
、またWebサーバーの前段にnginxをなどを置き、そこからUNIX Socket経由で接続する場合はunix:///var/run/puma.sock
のように指定します。
# Bind the server to "url". "tcp://", "unix://" and "ssl://" are the only # accepted protocols. # # The default is "tcp://0.0.0.0:9292". # # bind 'tcp://0.0.0.0:9292' # bind 'unix:///var/run/puma.sock' # bind 'unix:///var/run/puma.sock?umask=0111' # bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert' bind 'unix:///var/share/sockets/puma.sock'
その他、なにが設定可能か調べるには
上記で指定したこと以外にも設定可能な項目はあります。 それを調べるには設定ファイルのサンプルか、設定ファイルのDSLが定義されたファイルを読んで探してみると大体何ができるか把握出来ます。