Rails アプリケーションを本番環境で稼働させる際、unicorn + nginx という組み合わせがメジャーです。github も、その様な構成になっています。色々な Rack サーバーがありますが、github での採用によって、unicorn が流行った感じがあります。
しかし、その一方で、unicorn 単体で利用される例は見かけません。nginx を利用する事のメリットは多くあり、nginx を挟んだ方がよいのですが、unicorn を nginx と共に使わなければならない理由は何でしょうか?
Slow Client Attack による障害
DoS Attack の手法の一つに、Slow Client Attack (あるいは Slow Rate Attack)という手法があります。これは、クライアントがサーバーに接続して、ファイルをリクエストする時に、クライアントの速度を遅くすることによって、サーバーとの接続を永続的に保持するというものです。沢山のクライアントが永続的にコネクションを保持してしまうと、新しいクライアントが接続できなくなってしまいます。これは悪意のある攻撃者でなくても、4GやWifiなどの遅い回線において成り立つので、ウェブ・サーバー設計の一つの課題です。
unicorn は unix 思想に基づき「一つの事を上手くやる」ように設計されており、Slow Client を考慮していません。技術的には、ブロッキングIOを利用している為に、遅いクライアントによる永続的な接続がリソースを専有してしまいます。これは、unicorn のバグではなく、ウェブ・サーバーの設計方針の一つであって、悪いものではないです。しかし、この設計方針により、unicorn は、ローカル・ネットワーク以外からのアクセスを許可してはいけません。
unicorn は keep alive も pipeline も実装していない
unicorn は永続的な接続を回避するために、keep alive も pipeline も実装されていません。これらをクライアントに提供するためには、対応したリバースプロキシが必要です。
unicorn は静的ファイルを効率的に配信できない
unicorn は静的ファイルを効率的に配布する実装にはなっていません。nginx は、ユーザ空間でのデータ・コピーを最小にするために、静的ファイルを sendfile というシステムコールを使って配信します。
nginx が最適なリバースプロキシである理由
unicorn は高速で単純に実装されており、幾つかのウェブサーバーに必須の機能を持っていません。これは設計上のトレードオフです。unicorn 単体で公開することも可能ですが、前述の弱点があるために、現実的ではありません。unicorn 単体では Slow Client Attack に対して脆弱です。
リバースプロキシを先頭に置くと、一旦、リバースプロキシがリクエストをバッファリングし、それをウェブ・サーバーに食べさせます。これは Spoon Feeding と呼ばれるウェブ・サーバーの高速化の手法です。親が赤ちゃんにスプーンで食べさせてあげる様から、過保護にするという意味らしいです。これによって、Slow Client からウェブ・サーバーを保護します。
その他、unicorn に実装れてない機能を nginx は有します。unicorn を ngixn と一緒に使ったほうが良い理由なら沢山ありますが、以上が unicorn を nginx と共に使わなければならない理由です。nginx は unicorn の弱点を完全にカバー出来るリバースプロキシです。
Puma は単体で機能するウェブ・サーバー
Heroku では unicorn ではなく、Puma の利用が推奨されています。これは Heroku のアーキテクチャ的に、nginx を先頭に置くのが難しいためです。Heroku の前段には、リバースプロキシとロードバランサーがありますが、unicorn の弱点をすべてカバーするだけの機能はありません。