日進日歩で日々進捗

非情報系学生による技術の備忘録。進捗出していきたい

なぜRailsのWebアプリにunicornが必要なのか

Railsを開発、デプロイする際に、unicornだのpumaだのwebrickだのpassengerだの、、
HTTPサーバーであることは理解しているものの、なぜこれが必要なのか理解していない人も多いのではないでしょうか。
私自身も理解が深いわけではありませんが、現在の段階で自分の理解をまとめてみたいと思います。かなり殴り書きです。

疑問1: なぜ、nginxとunicornを同時に使うのか。片方じゃダメなのか

結論から言うと、nginxがあってもなくてもいいですが、unicorn及びRackに対応しているHTTPサーバーは必須、となります。
なぜかというと、Rails単体ではHTTPサーバーの機能を持っていないため、RackというRailsが対応している規格に対応したwebサーバ0がRailsと紐づいている必要性があるからです。
ではunicornなどのアプリケーションサーバーが必要な理由はそれで良いとして、なぜnginxが必要なのでしょうか。

Railsのよくある構成で使われているnginxはリバースプロキシである

今回はHTTPサーバーがunicornであると言う前提で、話を進めます。
よくある本番環境で動かしているRailsアプリケーションの基本的な構成は下記のようだと思います。

f:id:low_programing:20191010172133p:plain
https://medium.com/@yucunli/a-gentle-intro-to-deploy-rails-application-with-unicorn-c99fee29cb6e

一番手前にnginxがあり、その下にunicornがあり、さらにその下にRailsアプリケーションが動いていて、一番奥にBackendDB(psqlmysql, redis ... etc)があります。

この画像だと、Railsアプリどこにあるの??と思う人がいるかもしれませんが、unicornのworkerプロセスの中でRailsが動いているイメージです。
これを聞くと、あれ??じゃあunicornRailsが一体化しちゃってるじゃん!と思うかもですが、それが正しい認識です。

先ほども言ったようにRails自体は、HTTPサーバーの機能を持っておたず、ただのバックエンドのデータをいい感じにまとめて、データをよしなに加工するだけのアプリケーションなのです。そして、先ほど登場したRackと言うインターフェイスに対応したイベントから呼ばれる前提で設計されています。
よくRailsとはWebアプリケーションフレームワークと言われていますが、正確にはHTTPサーバーとしての機能は提供しておらず、あくまでHTTPリクエストが入ってきた前提で動くものです。

nginxの役割はリバースプロキシ

上の図のように、nginxが外側のリクエストを受け付けています。具体的には、TCP/IPプロトコルで入ってきたリクエストをUNIXドメインソケット通信(同一PC内での通信)に変換して、unicornに渡しています。
unicornはnginxから渡ってきたHTTPリクエスト情報rackのインターフェイスに変換して、Railsに渡しています。

じゃあ、なぜnginxが必要なの?と言う話ですが、これはnginxの特徴として、大量で軽量な処理をさばくのに、向いているアーキテクチャであるからです。
ノンブロッキングI/Oというアーキテクチャで実装されています。詳しくはググるとたくさん出てきますが、難しいです。

Railsアプリケーションは自体はRubyで実装されており、バイナリ形式で動くnginxと比較してもパフォーマンスが良いとはいえません。
なので、簡単な処理、例えばファイルシステムに保存されている画像形式のファイル(静的ファイル)をHTTPレスポンスとして返す、などの簡単な処理においては、railsに処理を渡さない方が、高速にレスポンスを返すことができるからです。

nginxが得意な領域はnginxが引き受けて、面倒な処理が入ってくるようなリクエストの場合だけrailsに渡す、と言うやり方が一番システムとしてパフォーマンスが出るわけです。

逆に、多くのリクエストを同時にさばけるようなパフォーマンスが求められていないような場合は、nginxは必要ありません。
ローカル開発環境では、nginxを起動せずにwebrickやpumaでRailsサーバーを立ち上げていると思いますが、それが理由です。

unicornの内部アーキテクチャ・実装、特徴など

unicornは、基本的にマルチプロセス、ブロッキングI/Oのアーキテクチャを採用しています。
つまり、各プロセスが担当する処理が終わるまでプロセスが解放されないため、大量にリクエストがきた場合、リクエストの待ち行列が増えることになり、パフォーマンスが悪化します。このアーキテクチャはWebサーバーのAppacheと同等のものです。

こちらの記事が大変参考になりました。
blog.willnet.in