RaspberryPiでPhusion Passengerが使えないという場面に出くわしてから、Railsを動かす構成について幾つか検討をしていました。なんとなく流れでapacheからnginxへの移行も考えたのですが、よく考えたら別にApache(http server)が悪いわけではないので、そちらはボツに。Passengerの代わりにPumaをそのまま使えばいいんじゃないか、と原点に立ち戻ってみましたが、certbot(letsencrypt)の証明書をうまく読み込めないので単体で動かすのもボツ(自分でコピーしてくればいけるんですが、更新がめんどくさくなりそう)。
ということで、Apache + Pumaを組み合わせて以下のようにプロキシモジュールで対応しています。
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
これまで多くの環境で導入してきたApache + Passengerは以下のような感じ。
DocumentRoot /var/www/myapp/public
PassengerAppEnv production
PassengerRuby /home/lmuser/.rbenv/versions/3.1.5/bin/ruby
同じサーバで上記2つの設定を入れ替えてレスポンスを比較してみました。使用したのは ab
コマンドで、以下が実際に与えたパラメタと共通の出力部分(抜粋)です。
ab -n 10000 -c 100 https://foobar.lmlab.net/testpath
Server Software: Apache/2.4.58
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-ECDSA-CHACHA20-POLY1305,256,256
Server Temp Key: ECDH X25519 253 bits
:
Concurrency Level: 100
Document Length: 11820 bytes
:
結果はそれぞれ以下の通り。
Apache + Puma(6.4.2):
Time taken for tests: 239.695 seconds
Complete requests: 10000
Failed requests: 0
Requests per second: 41.72 [#/sec] (mean)
Time per request: 2396.951 [ms] (mean)
Time per request: 23.970 [ms] (mean, across all concurrent requests)
Transfer rate: 513.92 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 119 225 281.3 157 2385
Processing: 65 2154 12638.1 1474 231541
Waiting: 63 2151 12638.2 1472 231540
Total: 198 2379 12647.2 1642 231810
Apache + Passenger(6.0.17):
Time taken for tests: 156.430 seconds
Complete requests: 10000
Failed requests: 2
(Connect: 1, Receive: 0, Length: 1, Exceptions: 0)
Requests per second: 63.93 [#/sec] (mean)
Time per request: 1564.297 [ms] (mean)
Time per request: 15.643 [ms] (mean, across all concurrent requests)
Transfer rate: 797.64 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 180 41.2 174 815
Processing: 83 1375 166.5 1372 14995
Waiting: 74 1370 93.9 1369 1993
Total: 265 1554 161.4 1546 14995
Passengerの方が幾分応答が速いですが、1万回のリクエストの中で2回エラーが発生しています。対するPumaはエラーこそ0ですが、ものすごく時間がかかってるレスポンスも存在します。単にタイムアウトの規定値の違いでしょうか?(今回そうしたパラメタは全く触っておらず、規定値のまま動作しています)
あと、Pumaの方は以下のオプションを有効にしています。
Environment="RAILS_SERVE_STATIC_FILES=true"
以下の要領でプロキシの対象から除外してDocumentRootを読ませれば、Pumaを介さずに配信可能ですが、結果にほとんど差は見られませんでした。
ProxyPass /assets !
DocumentRoot /var/www/myapp/public
Passengerは導入がややこしかったりするので、そういう場面ではPumaを使ってもいいのかな、という感じで捉えておこうと思います。