NGINX Unit アイツ最近どうなったか気になったので調べた
NGINX Unit は多言語対応したアプリケーションサーバー。2018年にGAしていた。
GitHub に公開されている。
タグを見ると 1.26 とかまでバージョンが進んでいる。開発は継続してると思ってよいのではないか。
nginx/unit としてコンテナイメージも公開されている。タグ違いで、各言語の公式イメージから生やしたイメージも公開されている。
このコンテナイメージの Dockerfile は以下に公開されている。FROMは各言語の公式イメージになっており、そこに NGINX Unit のインストール手順を追加している。
GA前後にチョロっと解説記事が出ていた。
NGINX Unit は、Ruby の Puma, Unicorn, Passenger や、 Java の Tomcat, Jetty などなどと同じ位置で動かすミドルウェア。
RoR で Unicorn つかってるけどホゲホゲな問題があって別のアプリケーションサーバーを検討していて、、、というときに選択肢に挙げるひとつとして、NGINX Unit が出てくる。
仕事柄 Ruby で面倒事にぶつかるので 、NGINX Unit の Ruby サポートを中心に調べる。
2018年のGA時点では、 Ruby 向けにマルチスレッドサポートが無かったため、以下翻訳の元記事では、特に肯定も否定もされてないように読めた。
この投稿時点でドキュメントを見ると、Ruby にも threads
というオプションがあり、いつからか知らんがマルチスレッドサポートが実装されていた。
changelog を見るに、1.21 っぽい。
加えて 1.25 で スレッド開始終了のフックも追加されたようだ。
性能や安定性はわからんけど、機能的には Puma, Unicorn, Passenger などと張り合えそうな雰囲気を感じる。
RoR なウェブアプリを Puma で起動させることの課題として、
- 長時間起動してるとメモリリークでしんどくなる
- 長時間起動してるとメモリ断片化でしんどくなる
- しまいには OOM Killer に掃除される
これ対策として Puma Worker Killer 的なのを導入することもある。けどREADMEにデッッッッかく書いてあるとおり、初手で入れるものではない。まあ終いには入れると思いますけど。
Unicorn でやってても同様のはず。
NGINX Unit には、以上の悩みを緩和してくれそうな、とても良さそうな設定項目がある。 limits
の timeout
と requests
だ。
Object that accepts two integer options, timeout and requests. Their values govern the life cycle of an application process. For details, see here.
see here のリンクを踏むと ↓ 。
つまり一定時間 or 一定数リクエストを捌いたら、NGINX Unit に、アプリケーションプロセスを潰して作りなおさせる設定で、Apache の MaxRequestsPerChild と似たようなもんだと私は理解した。
眺めていくと、
- 一定数リクエスト処理後の kill は、NGINX Unit のみ。Puma Worker Killer に無い。とても助かる状況が多そう。
- 一定時間による kill は、NGINX Unit と Puma Worker Killer の両方にある。
- アプリケーションプロセスのメモリ量による kill は、NGINX Unit に無いが、 Puma Worker Killer には有る。
どうにも一長一短だな。
Apache の MaxRequestsPerChild。
知らんかったのですが 2.4 で MaxConnectionsPerChild にリネームされていた。
時期それぞれで実装言語やアプリケーションサーバー違いで簡易に負荷試験している記事がいくつかあった。どれも ab でやってる。
2017年09月。
2018年09月。
2020年06月。
各言語の地場なアプリケーションサーバーに比較して、NGINX Unit が複数言語に八方美人な動作するのでチューニングが行き届いておらず、、、とかそんな理由で、なんかもっと話にならん劣悪性能と思いきや、NGINX Unit けっこう善戦しており驚いた。
NGINX Unit に設定の投入は、NGINX Unit の設定用HTTPエンドポイントにPOSTするとかの記述しか表面的には漁れず途方に暮れた。クイックスタートとか見てもPOSTしろってあるし。
いや待てよと。固定台数のオンプレサーバーやEC2インスタンスならともかく、Packer & Ansible で AMI を焼いたり、Dockerfile でコンテナイメージを焼いたりするのに、 POST で投入しろとか面倒臭すぎて鼻血が出るわ。
これに NGINX Unit 公式コンテナイメージでは答えが用意されていて、POST させたい json を /docker-entrypoint.d/
に転がしたら起動時に NGINX Unit に読ませてくれるようだ。
コンテナイメージの Dockerfile は
json を NGINX Unit 起動時に POST してくれる仕組みの実装は
独自に NGINX Unit をキッティングしてるなら、これらを参考に自前で仕組みを整備するとよさそうだ。
コンテナ化してるアプリケーションで、実装言語の公式のコンテナイメージをFROMに使っていて、 NGINX Unit を使うなら、NGINX Unit 提供の各言語向けコンテナイメージを FROM に差し替えるのが、最短距離に見える。
ただしこの場合、実装言語の公式のコンテナイメージが、パッチアプデやマイナーアプデをしても、NGINX Unit のコンテナイメージは時間差を置いてからでしか Docker Hub に出てこなさそうな気がする。ちょっと悩ましく思える。
どの言語にしても、その言語特有のアプリケーションサーバーが既に存在しており、pros/consは明らかだし、バッドノウハウふくめ枯れている。
NGINX Unit はどうなんだ。ドキュメントを眺めた雰囲気では特段のつまづきは無さそうに見えるけど、バッドノウハウが世間に蓄積されてなさそうで、「どんな酷い目にあわされるかわからない」感じがある。わざわざ使おうという強烈なprosも乏しい。
結局「明日からアレに使いたいぞ!!!」というのが特になかった。しばらくしたら、また様子見に来ます