前提
どちらもアプリケーションサーバ(アプリケーションを動作させるためのサーバ)
アプリケーションサーバーは送られてきたリクエストに対して、rubyやphpなどを実行して、動的な処理をした結果を静的な要素に変換してwebサーバーに返すためのもの。つまり、動的なサイトを動かす上で必要なもののうち、静的ではない部分を作ってくれるもののイメージ。
それぞれ、rackというwebアプリとアプリケーションサーバ間のインターフェイスの仕様&実装に準拠していて、それを使ってRailsと通信を行っている(Railsも、もちろんrack準拠)
Railsアプリの動かし方の違い
- Unicorn: マルチプロセス
- Puma: マルチプロセス & マルチスレッド
どちらも、1つのアプリケーションサーバで複数のRailsプロセスを起動して、処理の効率化を図っている
Pumaは更に、プロセスをマルチスレッド化している。これにより、I/O wait が発生した時に、別スレッドの処理を進められるため、マルチプロセスのみより効率が良い
2020/08/07 追記
unicornはマルチプロセスではなく、
thinやmongrelみたいなマルチプロセスによるclusterではなく、forkを使ったmaster-slave
だそうです
master-slave のほうが以下のようなメリットがあるとのこと
- メモリ効率が良いかも
- プロセスが死ぬわけではないのでダウンタイムが発生しない
- 結果的にデプロイ時にダウンタイムが発生しない
- デプロイが早い
Unicronの弱点
スロークライアント(リクエストが遅いクライアント) に弱い
スロークライアントが来た場合、workerが待ちのまま止まってしまうという特徴がある。そのためNginxなどリバースプロキシを挟んで、スロークライアントをバッファしてもらう必要がある
これは、Unicornの不具合というより仕様。Unix哲学の「一つのことをうまくやる」に沿って作られているため。スロークライアントのバッファは、リバースプロキシに任せるように作られている
Pumaはスロークライアントが来ても1つのスレッドが埋まるだけなので、スロークライアント対応のためのリバースプロキシは不要
Pumaのほうが優れているの?
そんなこともない
マルチスレッドということは逆に言うとスレッドセーフな実装をする必要があり、当然使用しているgemもスレッドセーフであることを保証しなければならない(たいへん
また、Pumaにすればリバースプロキシがいらないの? というとそんなこともなくて、リクエストのバッファ以外にもいろいろやりたいことが出てきたりするので (healthcheck.htmlでempty_gif返したり)、結局Nginxなどのwebサーバを間に挟むことが多いはず(多分)
あと、Pumaはマルチスレッドだけど、そもそもRubyが純粋なネイティブスレッドではないので、Pumaを本気を出させるには、JRubyとかネイティブスレッドに対応したRuby実装を使ったほうが良いらしいとのこと
個人的な結論
結局のところ、よっぽど大量のリクエストを高速にさばく必要がなければ、どちらでもいいんじゃないかな...
個人的には、Pumaのマルチスレッドは想定外の所でめんどくさい動きをしそうだから怖いな...
Heroku(Pumaを激推ししている)でRails動かしてる時に、マルチスレッドで困ることあるのかな?
参考
👇 ほぼこの記事の引き写しです
👇 pumaとunicornとpassengerの比較記事。かなりunicornをディスっている