読者です 読者をやめる 読者になる 読者になる

Mercari Engineering Blog

メルカリのエンジニアブログです。技術情報を日々発信していきます。

3つのnginxをうまく使い分けよう〜nginx、OpenResty、Tengine〜

SREチームの@cubicdaiyaです。今回はメルカリで利用実績のある以下の3つのnginxの使い分けに紹介します。

nginxとメルカリ

本ブログや過去のイベントでも何度か紹介していますが、メルカリではパフォーマンスやスケーラビリティが要求される様々なコンポーネントでnginxをヘビーに活用しています。例えば、

  • コンテンツ配信/キャッシュ/リバースプロキシ/TLSターミネーション
  • 20,000 req/secオーバーのAPI(HTTPS)リクエストを捌くロードバランサ
  • gRPC、Apache Solr、Gaurun等のミドルウェアのためのロードバランサ
  • ngx_luaによるログ分析基盤のフロントエンド、ロードバランサやリバースプロキシの拡張

といったものです。メルカリではこれらのコンポーネントをnginxやOpenRestyで用途に応じて使い分けながら構築・運用しています。

3つのnginxとメルカリ

ソフトウェアとしての配布物という観点で言うとnginxには本家とは別に、nginxとngx_luaをはじめとする各種モジュールやLua/LuaJITをバンドルしたソフトウェアであるOpenRestyとnginxのフォークであるTengineが存在します。(あと、nginxの開発元であるNGINX, Incが提供しているNGINX Plusという商用版のnginxもありますが、利用経験が乏しいのでここで紹介するのは控えます)

nginx

まずは本家のnginxです。メルカリでは下記のスライドのようなTLSターミネーション、L7ロードバランサ、リバースプロキシとしての用途がメインになります。(L4ロードバランサとして稼働している箇所も一部あります)

www.slideshare.net

通常のHTTPサーバやリバースプロキシとしてはこれで十分な一方、メルカリでは(主にngx_luaで)より柔軟な設定を行いたい等の理由から内部のロードバランサにOpenRestyを利用する機会が増えてきています。

OpenResty

OpenRestyはnginxのほかにngx_luaをはじめとするCで書かれた各種サードパーティモジュールとngx_luaのAPIを利用したrestyモジュール、そしてLua/LuaJITで構成されています。

OpenRestyに含まれているnginx自体は本家のnginxと基本同じなので、別にOpenRestyを利用しなくても自分でngx_luaを組み込んだり、サーバ上にrestyモジュールを配布することで似たような環境を構築することは可能ですが、OpenRestyであれば主要なモジュールやライブラリが./configuremakemake installの一連の流れですべてゴソッとインストールされますし、OpenRestyのconfigureスクリプトはnginxのconfigureスクリプトを継承したものなのでnginxのconfigureオプションをほぼそのまま利用することもできます。

なので、ngx_luaを利用したいようなケースでは特に理由がなければOpenRestyを利用する方が手っ取り早くそして運用も楽になるのでオススメです。

メルカリでのOpenRestyの利用事例やノウハウについては過去にポストしたものがあるので併せてご覧ください。

tech.mercari.com

tech.mercari.com

Tengine

TengineはAlibaba社によるnginxのforkです。本家のnginxにはない機能の追加や拡張が数多く行われています。しかし、nginxの開発が非常に活発なこともあり、機能面での差は以前と比べると小さくなってきています。例えば、モジュールの動的ローディングやUnbuffered upload、consistent hashによるアップストリームのロードバランス、Socket Sharding、syslogのサポートといった機能の実装はTengineが先行していましたが、現在はnginxでも利用可能です。

一方でSPDY/3.1とHTTP/2の同時サポートといったnginxではサポートされていない機能が今でもいろいろとあるので場合によっては利用するメリットは依然としてあります。

メルカリでは以前SPDY/3.1とHTTP/2を併用する目的でTengineを利用しているサーバがいくつかあったのですが、今はCloudFlare, Inc.がOSSで公開しているSPDY/3.1とHTTP/2の同時利用を可能にするパッチをあてたnginxに置き換わっています。(なので現在はTengineは使っていません。)

ソフトウェアの良し悪しとは別に気をつけるところ

ソフトウェアの良し悪しとは別に3つのnginxを使い分けるにあたって以下の項目を念頭に置いておくとよいでしょう。

  • OpenRestyあるいはTengineと本家のnginxとの互換性
  • リリースサイクルの違い

OpenRestyあるいはTengineと本家のnginxとの互換性

OpenRestyに含まれているnginx自体は本家のnginxと基本同じです。 また、OpenRestyに含まれているのがどのnginxのバージョンなのかはOpenRestyのバージョンで判別できます。 例えば執筆時点でのOpenRestyの最新バージョンは1.9.7.4ですが、これはnginx-1.9.7をベースにしています。 そして次期リリース候補版の1.9.15.1 RC1はnginx-1.9.15をベースにしています。つまり先頭3つの数字がnginxのバージョン番号を指しているということです。

Tengineは元のnginxをかなり拡張しているにも関わらず互換性は非常に高いですが、リリースサイクルが長いのでベースにしているバージョンが古くなる傾向があります。例えば執筆時点での最新版である2.1.2はnginx-1.6.2をベースにしています。(公式のREADME.mdによると「All features of nginx-1.6.2 are inherited, i.e., it is 100% compatible with nginx.」)

リリースサイクルの違い

本家のnginxにはmainlineとstableという2つの開発ブランチがあり、大体1〜2ヶ月毎にmainlineブランチの最新バージョンがリリースされる傾向があります。一方stableブランチでのリリースは緊急性の高い修正がメインであまり頻繁には行われません。nginxのmainlineブランチとstableブランチの違いについてはnginxの公式ブログで紹介されている以下の記事が参考になります。

www.nginx.com

OpenRestyやTengineは本家nginxのある時点でのバージョンをベースにしてリリースされるので、自ずとリリースサイクルは本家のnginxより長くなる傾向にあります。OpenRestyやTengineを利用する際はこの点に注意しましょう。

おまけ〜nginx-buildによるnginx、OpenResty、Tengineのビルドの自動化〜

似たようなソフトウェアが3つもあるとビルドや各サーバへの配布が面倒なので、メルカリではnginx-buildを利用して各種ビルドタスクを自動化しています。

github.com

nginx-buildは本家のnginxだけでなく、OpenRestyとTengineのビルドにも対応しているのでどれでも簡単にビルドすることができます。

# nginxをビルドする
nginx-build -d work -v 1.11.0
# OpenRestyをビルドする
nginx-build -d work -openresty -openrestyversion=1.9.7.4
# Tengineをビルドする
nginx-build -d work -tengine -tengineversion=2.1.2

また、最近公開されたCloudFlare, Inc.によるSPDYとHTTP/2の同時サポートを可能にするパッチの他に、過去にSPDYやHTTP/2の実装といった大きな変更が行われる際にアルファ版として公式パッチが提供されたこともあるので、そういったケースに備えて先日nginx-buildに任意のパッチを取り込むためのオプションを追加しました。

nginx-build \
 -d work \
 -patch nginx__http2_spdy.patch \
 -patch-opt "-p1" \ 
 -v 1.9.7 \
 --with-http_spdy_module \
 --with-http_v2_module

まとめ

メルカリで利用実績のある3つのnginxの使い分けについて解説しました。通常のHTTPサーバとして利用する分には本家のnginxだけでも十分なケースが多いですが、ロードバランサーやリバースプロキシでLuaのようなスクリプト言語で拡張できると何かと便利なので最近はOpenRestyの利用箇所が増えてきているほか、以前はSPDYとHTTP/2の同時サポートのためにTengineを利用していたこともありました。

OpenRestyやTengineを利用する際は機能面だけでなく本家のnginxとの互換性やリリースサイクルの違いに注意を払いましょう。それではよいnginxライフを。