nginxのアップストリームを変更する
通常nginxでアップストリームの変更をするにはnginx.conf
を変更した後、nginxをreload
ないしはrestart
しなければなりません。例えば以下のようにアップストリームが定義されている場合、
upstream backends {
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
}
このアップストリームから127.0.0.1:6003
を外すには以下のように該当行にdown
と書いてreload
します。(あるいはコメントアウトする)
upstream backends {
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003 down;
}
あるいはアップストリームの各サーバのパラメータ(weight
、max_fails
、fail_timeout
)を変更するのにもreload
が必要です。(下記の各パラメータはデフォルト値)
upstream backends {
server 127.0.0.1:6001 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6002 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6003 weight=1 max_fails=1 fail_timeout=10;
}
もっと言うとアップストリームにサーバを動的に追加することはできないので、サーバを追加するにはやっぱり手でnginx.conf
を修正した後にreload
が必要です。
upstream backends {
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
server 127.0.0.1:6004; # 追加したサーバ
}
という具合に通常nginxのアップストリームを変更するにはnginxのreload
やrestart
が必要です。
これで十分な場合も多いですが、一方でサービス要件によってはELBのようにアップストリームを動的に変更したいというニーズもあることでしょう。
nginxのアップストリームを動的に変更する
nginxはマルチプロセスアーキテクチャなのでnginx.conf
を変更せずにオンザフライでアップストリームを変更するには何らかの方法でアップストリームの情報を各ワーカプロセス間で共有する必要があります。
アップストリームの情報を各ワーカプロセス間で共有する方法には例えば以下のものが挙げられます。
- NGINX Plusを購入する
- memcached等の外部KVSでアップストリームを共有する
- ngx_luaやngx_mrubyで頑張る
- アップストリームを共有メモリ化する
NGINX Plusを購入する
有償版のnginxであるNGINX Plusにはngx_http_upstream_conf_module
というアップストリームを動的に操作するためのHTTPインタフェースモジュールが付属しており、CLIで簡単にアップストリームを操作できます。
NGINX Plusについては2年近く前の記事ですが、@harukasanが軽くまとめていて参考になります。
memcached等の外部KVSでアップストリームを共有する
そもそもnginxのプロセス内にアップストリームのデータを持つのではなくmemcached等の別サーバプロセスでアップストリームの情報を共有するという方法はどうでしょうか。しかし、この方法だとアップストリームの管理を自前で行わなければならないのでnginxが元々サポートしている以下の機能を利用するのが非常に難しくなります。(というか無理?)
- アップストリーム内サーバへのロードバランスとそのアルゴリズム(e.g. least_conn、consistent-hashing)の利用
- アップストリーム内サーバの重み付けや不調サーバのアップストリームからの取り外し
あと、そもそも外部KVSサーバといい感じに通信してロードバランスするモジュール的なものを書く必要があってなかなか大変です。
ngx_luaやngx_mrubyで頑張る
ngx_luaやngx_mrubyを利用するとnginx.conf
に特殊なロジックを埋め込んだり、Cではなくスクリプト形式でnginxのモジュールを書くことができます。外部KVSサーバと通信してアップストリームの情報をやりとりするのも幾分簡単になるでしょう。しかし、やはりアップストリームの管理を自前で行わなければならないので煩雑なことにかわりはありません。
アップストリームを共有メモリ化する
先月リリースされたnginx-1.9.0のCHANGESを見ると以下の一文があります。
Feature: the "zone" directive inside the "upstream" block.
TCP Load Balancing機能が目立ってたのとあまりにもシレッと書かれていたので1.9.0がリリースされてから1週間ぐらい気付いてなかったのですが、NGINX PlusだけでなくOSS版でもアップストリームを共有メモリ化できるようになりました。(NGINX Plusのソースコードは公開されていないのであくまで推測になります)
こんな感じにupstream
コンテキスト内でzone
ディレクティブを定義します。
upstream backends {
zone zone_for_backends 128k;
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003 down;
}
これでnginxのアップストリームを各ワーカプロセス間で共有できるようになります。
ngx_dynamic_upstreamでnginxのアップストリームを動的に変更する
前置きが長くなりました。さっきも言ったようにnginx-1.9.0からupstream
コンテキストでzone
ディレクティブが利用可能になったのでnginxのアップストリームを共有メモリに格納してワーカプロセス間でアップストリームの情報を共有できるようになりました。しかし、OSS版ではそもそもnginxのアップストリームを動的に変更するためのモジュールがありません。
なので、HTTPインタフェースでアップストリームを動的に変更できるモジュールを書いてみました↓
Quick Start
ngx_dynamic_upstreamはdynamic_upstream
というただひとつのディレクティブを持ちます。このディレクティブはlocation
コンテキストのみで利用可能です。
upstream backends {
zone zone_for_backends 128k;
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
}
server {
listen 6000;
location /dynamic {
allow 127.0.0.1;
deny all;
dynamic_upstream;
}
location / {
proxy_pass http://backends;
}
}
ngx_dynamic_upstream自体はアクセス制御機能を持たないのでallow
やdeny
でIPアドレス制限等をするのを忘れずに。
アップストリームの一覧を取得する
upstream
パラメータにzone
名を指定するとアップストリームの一覧を返します。
$ curl "http://127.0.0.1:6000/dynamic?upstream=zone_for_backends"
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
$
アップストリームからのサーバの一時的な取り外し/復帰
down
とserver
パラメータを組み合わせることでアップストリームから特定のサーバを一時的に取り外し可能です。
$ curl "http://127.0.0.1:6000/dynamic?upstream=zone_for_backends&server=127.0.0.1:6003&down="
server 127.0.0.1:6001 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6002 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6003 weight=1 max_fails=1 fail_timeout=10 down;
$
取り外したサーバを復帰させるにはup
パラメータを指定します。
$ curl "http://127.0.0.1:6000/dynamic?upstream=zone_for_backends&server=127.0.0.1:6003&up="
server 127.0.0.1:6001 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6002 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:6003 weight=1 max_fails=1 fail_timeout=10;
$
まとめ
nginxのアップストリームを動的に変更する方法と戦略について解説しました。ngx_dynamic_upstreamはサーバの動的な追加や削除の機能もありますが、up
とdown
だけでもかなり便利なのではないかと思います。
なお、GWの暇な時に作ったばかりなので、
This module is significantly experimental and still under early develpment phase.
という感じでまだ絶賛開発中です。追記:2015/06/09に「production ready」になりました。