Ruby on Railsアプリケーションを本番環境で動作させるためのアプリケーションサーバとして、unicornを利用するのが一般的です。 ここではunicornの概要やNginxとの違いなどについてまとめてみました。

次回の記事ではunicornの設定などについてもまとめましたので、こちらもあわせてご覧ください。

unicornとは

unicornは、Railsなどでつくられたアプリケーションを動かすアプリケーションサーバです。

unicornはプロセス上で動作するサーバで、プロセスには(1)masterプロセスと(2)workerプロセスがあります。 masterプロセスがアプリケーションのソースコードを保持しており、これをforkしたworkerプロセス群が実際のリクエストを処理します。

ソースコードをロードするのがmasterプロセスのみであるため、起動が早い、デプロイ時のダウンタイムがない、などのメリットがあります。

シグナル

unicornはプロセスで動作すると書きましたが、このプロセスにシグナルを送ることでサーバの起動関連を指示することができます。 詳細は公式ドキュメントのSignal handlingで確認できますが、ここでは代表的なUSR2シグナルについて説明します。

USR2

masterプロセスがUSR2シグナルを送られると、masterプロセスは自身を再起動します。 また、このとき新しいmasterプロセスをforkした新しいworkerプロセス群も生成されます。

注意すべき点として、古いプロセスは勝手に終了されないので、設定ファイルで終了指示を行なう必要があります。

nginxとの違い

サーバをつくる際にunicornとnginxの役割を理解しておくことが重要なので、nginxについても一度整理しておきます。

nginxはクライアントからのリクエストを受け、なんらかの処理(SSLや圧縮など)を行なうWebサーバです。

単にアプリケーションを動作させるだけなら、nginxは必要ありません。 実際に、開発環境などではnginxなどなくても、unicorn(あるいはWEBrick、Puma)単体で動作します。

開発環境と本番環境の違いはリクエストの数で、unicornはworkerプロセスがせいぜい数個であるのに対し、nginxは数千ものコネクション数が存在します。 もしnginxを置かなければ、ネットワークの遅いクライアントが同時に接続してきたときにunicornプロセスをすべて占有してしまい、その他のクライアントからの接続を受け付けられなくなってしまいます。

nginxを置くことで、たくさんのリクエストを受け、それをunicornのプロセスにいい感じに振り分けています。

リクエストの流れ

この2つのサーバがクライアントからのリクエストを処理する流れは次のようになります:

  1. Webサーバ(nginxなど)からリクエストがunicornに渡される
  2. unicornはRackをとおしてRailsアプリケーションのルータに処理を渡す
  3. Railsアプリケーションの結果をunicornが受け取る
  4. unicornはこれをWebサーバに渡し、最終的にクライアントへと渡る

この流れを理解しておくと、レスポンスの遅延といった問題が生じたときに原因を特定しやすいかと思います。

備考

unicornはプロセスにコードを保持する、と前述しました。

ここで、たとえばActiveRecordのキャッシュなどでメモリを使用すると、プロセス単位のメモリ使用量がどんどん増えてしまします。 このプロセスは自動で再起動することはないので、放っておくとレスポンスの大きな低下につながってしまいます。

これを解決するのがunicorn-worker-killerというGemで、メモリ使用量などを基準に自動でworkerプロセスを再起動してくれます。 パフォーマンス遅延の原因がunicornの場合は、これを導入すると改善するかもしれません。

参考記事

おわりに

以上でunicornの概要、nginxとの違いについてまとめました。 次の記事では、実際の設定について見ていきたいと思います。