社内勉強会でUnicornについて発表したけどあまりの準備不足に全俺が泣いたので少しずつまとめていく〜その2
Unicornの哲学(PHILOSOPHYより)
Unicornの詳細に降りていく前に、どのような哲学でもって設計・実装されているのか把握しておきたい。
Unixの哲学
「一つのことを行い、それをうまくやる。」
複雑さの排除
低速なクライアントに対応する代わりに、Unicornはバッファリング可能なリバースプロクシを信頼して代替させる。
UnicornはブロッキングI/Oと旧来のpreforkモデルを採用している。この処理モデルはモダンな方法(スレッドモデル、イベントとノンブロッキングI/O)へのアンチテーゼ。
低速なクライアントについて
「低速なクライアント」と呼ぶのは、データセンタ(ローカルネットワーク)の外側にいるクライアント(物理法則的な問題)。
HTTP/1.1の永続コネクションによって遅延を減らすことができるが、クライアントがアイドルしている間はサーバリソースが無駄に消費される。
永続コネクションはワーカープロセスの一つがコネクション維持だけで何もせずに時間を消費することを意味する。シングルスレッドかつブロッキングI/Oであるため、コネクションが生きている間ワーカーはほかのクライアントに応えることはできない。
そのため、Unicornでは永続コネクションを実装しない。
ソケットバッファ以上のレスポンスや巨大なリクエストを扱う場合、クライアントコネクションの速度がワーカープロセスのボトルネックとなる。そのため、ローカルネットワークの外にいるクライアントをUnicornで受けるべきではない。
Application Concurrency != Network Concurrency
CPUとメモリは高速であるため、通常はこららによるストレスを感じることはない。Unicornでは遅いI/Oから守るためにリバースプロクシを頼る。
リバースプロクシによる性能改善
リバースプロクシを低速なI/OとUnicornの緩衝材として働かせることで余計なデータコピーによるオーバーヘッドが発生してしまうが、ローカルネットワークによるI/Oは十分に高速でHTTPリクエスト・レスポンスと比べれば無視できる。
Unicornの弱点を補うことができる理想的なリバースプロクシの条件は以下の通り。
- すべてのHTTPリクエスト・レスポンスにとって十分なバッファを持っているべき
- ユーザスペースで過ごす時間は極小であるべき
- コンテキストスイッチとCPUスケジューリングによるオーバーヘッドを避けるべき
- 低速なクライアントのために永続コネクションとパイプライニングを効率敵に管理できるべき
- 静的なファイルを提供できるべき
- sendfileを使うとユーザスペースでのデータコピーを完全に避けられる
これらを満たすフリーソフトウェアはNginxしか知らない、とのこと。