NGINX ロードバランス


NGINX ロードバランス

このセクションでは、複数のサーバの間でのload balancing、ひとまとまりのサーバへのリクエストの渡し方、それらのサーバを監視する方法について説明します。

ひとまとまりのサーバへのプロキシ

NGINXをひとまとまりのサーバと一緒に使い始めるには、upstreamディレクティブを使って名前付きのグループを定義する必要があります。個々のサーバはserver ディレクティブを使って設定されます(nginx上で実行されるバーチャルサーバを定義する server ブロックと混同しないでください)。例えば、次の設定では"backend"という名前で3台のサーバ設定から成るグループを定義します(3台以上の実サーバになるかも知れません):

upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

upstreamディレクティブはhttp コンテキストに配置されます。

リクエストをサーバグループに渡すために、グループの名前を proxy_pass ディレクティブの中に指定します((fastcgi_pass, memcached_pass, uwsgi_pass, または scgi_pass). 次の例では、NGINX上で動いているバーチャルサーバが全てのリクエストを前の例で定義されたバックエンドのサーバグループに渡されます:

server {
    location / {
        proxy_pass http://backend;
    }
}

ロードバランスの方法

デフォルトでは、NGINXはラウンドロビンアルゴリズムを使って、リクエストを重みに応じてグループ内のサーバに配布します。serverディレクティブのweightパラメータがserverの重みに設定されます。デフォルトは1です。上のサーバグループの例では、最初のサーバは重み5を持ち、その他の二つのサーバはデフォルトの重み(1)を持ちます。しかしそのうちの一つはバックアップサーバの印を付けられていて、通常は何もリクエストを受け取りません。そのため6つのリクエストがあった場合、5つのリクエストは最初のサーバに送信され、一つのリクエストは二つ目のサーバに送られるでしょう。

全体としては、NGINXは三つのロードバランス方法をサポートします:

  • デフォルトは重み付きのラウンドロビンメソッドです。
  • least_conn メソッド : リクエストはアクティブな接続とserverの重みが考慮された数がもっとも少ないサーバに送られます。
  • ip_hash メソッド: リクエストが送信されるサーバは、クライアントのIPアドレスで決定されます。この場合、ハッシュ値を計算するために、IPv4アドレスの最初の3オクテットか、IPv6アドレスの全てが使われます。

最後のメソッド (ip_hash) は、サーバが利用可能で無い場合を除き、同じアドレスからのリクエストは同じサーバに到達することを保証します。デフォルト以外のメソッドが使われた場合は、serverディレクティブの前のupstreamの中に それぞれleast_conn または ip_hashディレクティブが指定されなければなりません。例えば:

upstream backend {
    ip_hash;

    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
    server backend4.example.com;
}

down パラメータ、これはip_hashとのみ一緒に使われる、は、サーバを利用不可として印を付けます。このサーバで処理されるとされたリクエストは自動的にグループ内の次のサーバに送られます。

受動的なヘルスモニタ

サーバが利用できないとNGINXがみなした場合、サーバが再び有効になったと見なされるまで一時的にリクエストを送信するのを停止します。server ディレクティブの後のパラメータはサーバが利用できないと見なす時の条件を設定します。

  • fail_timeout パラメータは指定した回数の失敗の試行が起こる期間を設定し、まだサーバが利用できないと見なす期間を設定します。別の言い方をすると、サーバは fail_timeoutで設定された期間は利用できません。
  • max_fails パラメータは指定した期間の間に指定回数の失敗の試行が起こる回数を設定し、まだサーバが利用できないと見なす回数を設定します。

デフォルト値は10秒と1回の試行です。そういうわけで、もしNGINXが幾つかのサーバにリクエストを送信するのに失敗するか、このサーバから少なくとも一回応答を受け取るのに失敗すると、NGINXは10秒の間そのサーバを利用不可と見なします。次の例ではこれらのパラメータを設定する方法を示します:

upstream backend {
    server backend1.example.com;
    server backend2.example.com max_fails=3 fail_timeout=30s;
    server backend3.example.com max_fails=2;
}

サーバの可用性を追跡するもっと良い方法があります。それらはnginxのcommercial subscription で利用可能です。

能動的なヘルスモニタ

グループ内のサーバの可用性は、定期的に特別なリクエストをそれぞれのサーバに送り、特定の条件を満たす応答であるかどうかを調べることで、監視することができます。

この種類のヘルスモニタを有効にするには、nginx.confファイルの中でグループにリクエストを渡すlocationに、health_checkディレクティブを含めなければなりません。更に、サーバグループはzoneディレクティブを使って動的に構成する必要もあります:

http {
    upstream backend {
        zone backend 64k;

        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
        server backend4.example.com;
    }

    server {
        location / {
            proxy_pass http://backend;
            health_check;
        }
    }
}

この設定はサーバグループと、全てのリクエストをサーバグループに渡す一つのlocationを持つバーチャルサーバを定義します。デフォルトのパラメータのヘルス監視も可能です。この場合、5秒おきに、NGINXはバックエンドグループのそれぞれのサーバに"/"リクエストを送信します。通信エラーまたはタイムアウトが起きた場合(あるいは、プロキシされているサーバがステータスコード2xxまたは3xx以外で応答した場合)、このプロキシされているサーバのヘルスチェックは失敗するでしょう。ヘルスチェックに失敗したサーバは全て健康ではないと見なされ、NGINXは次にヘルスチェックに通るまでクライアントリクエストを送信するのを止めるでしょう。

zone ディレクティブはworkerプロアセスで共有されるメモリ領域を定義し、サーバグループの設定を保持するために使われます。これによりworkerプロセスはグループ内のサーバからの応答を追跡するために同じカウンターのセットを使うことができます。zoneディレクティブはまたグループを動的な設定が可能にします。

この挙動はhealth_checkディレクティブのパラメータを使うことで上書きすることができます。

location / {
    proxy_pass http://backend;
    health_check interval=10 fails=3 passes=2;
}

ここで、2つのヘルスチェックの間の持続期間は、intervalパラメータを使って10秒まで増加します。更に、failsパラメータを3に設定することで、サーバは3回連続してヘルスチェックに失敗した後で、健康では無いと見なすでしょう。最後に、passes パラメータを使うことで、再び健康であると見なされるには2回連続してチェックに通る必要があるようにすることができます。

特定のURIをヘルスチェックで使うように設定することができます。このためには、uri パラメータを使います:

location / {
    proxy_pass http://backend;
    health_check uri=/some/path;
}

指定されたURIは、upstreamディレクティブの中でサーバのために指定されたサーバドメイン名またはIPアドレスに追加されるでしょう。例えば、上で定義されたバックエンドグループの最初のサーバについて、ヘルスチェックのリクエストはhttp://backend1.example.com/some/path のURIになるでしょう。

最後に、ヘルス応答が満たすべき固有の条件の設定することができます。この条件はmatch ブロックで指定され、 health_check ディレクティブのmatchパラメータで定義されます。

http {
    ...

    match server_ok {
        status 200-399;
        body !~ "maintenance mode";
    }

    server {
        ...

        location / {
            proxy_pass http://backend;
            health_check match=server_ok;
        }
    }
}

この場合、もし応答のステータスが200から399であり、ボディが指定された正規表現に合致しない場合に、ヘルスチェックが成功します。

match ディレクティブにより、NGINXは応答のステータスとヘッダフィールドとボディを調べることができます。このディレクティブを使って、ステータスが指定の範囲にあるかどうか、応答にヘッダが含まれるかどうか、ヘッダまたはbodyが正規表現に合致するかどうかを検証することができます。match ディレクティブには、一つのステータスの条件、一つのボディの条件、複数のヘッダの条件を含めることができます。match ブロックに一致するには、応答がブロックの中に含まれる全ての条件を満たす必要があります。

例えば、下記のmatch ディレクティブは、ステータスコードが200であり、"Content-Type"ヘッダが text/html に完全一致し、"Welcome to nginx!" の文字列を含むボディを持つ応答を探します:

match welcome {
    status 200;
    header Content-Type = text/html;
    body ~ "Welcome to nginx!";
}

次の!を使っている例では、ステータスが 301, 302, 303と307 以外で、"Refresh" ヘッダフィールドを持たない 応答に条件が合致します。

match not_redirect {
    status ! 301-303 307;
    header ! Refresh;
}

複数のworkerプロセスの間でデータを共有

もしupstreamディレクティブがzoneディレクティブを含まない 場合、それぞれのwokerプロセスはサーバグループ設定の個々のコピーを保持し、関連するカウンターの個々のセットを保存します。カウンターにはグループ内のそれぞれのサーバへの現在の接続数が含まれており、サーバへリクエストを送信するのに失敗した数が含まれて居ます。結果的に、サーバグループの設定は変更変更不可です。

upstreamディレクティブがzoneディレクティブを含む場合、サーバグループの設定全てのwokerプロセスが共有しているメモリ領域で置き換えられます。workerプロセスがグループ設定のプロセスと同じコピーにアクセスするため、シナリオは

zoneディレクティブは、サーバグループのhealth checksruntime modificationで必須です。しかし、サーバグループの他の機能もこのディレクティブの利用の恩恵を受けることができます。

例えば、グループの設定が共有されない場合、それぞれのworkerプロセスは試行の失敗がサーバへのリクエストが成功するまでそれぞれのカウンターで保持します(max_fails パラメータを見てください)。この場合、それぞれのリクエストは一つだけのworkerプロセスに影響を与えます。リクエストを処理するようにと選択されたworkerプロセスがリクエストをサーバに転送することに失敗した場合、他のworkerプロセスはそれについて何も知りません。いくつかのworkerプロセスがサーバが健康では無いと見なす一方で、その他のプロセスはこのサーバにリクエストをまだ送るかも知れません。サーバが明確に利用できないと見なされるには、max_fails に失敗した試行のworkerプロセスの数をかけた数がfail_timeoutで設定された時間内に起こらなければなりません。一方で、zone ディレクティブは期待するような挙動を保障します。

least_connロードバランシングメソッドはzone ディレクティブ無しには、少なくとも負荷が少ないときに期待通りの動作をしないかも知れません。このロードバランスのメソッドは、アクティブな接続がもっとも少ないサーバにリクエストを渡します。再び、グループの設定が共有されていない場合、それぞれのworkerプロセスは接続の数のために個々のカウンターを使います。そして、もしあるworkerプロセスがリクエストをサーバに渡すと、他のworkerプロセスもリクエストを同じサーバに渡し得ます。しかしながら、この影響を減らすためにリクエスト数を増やすことができます。高負荷ではリクエストはworkerプロセスに一様に配布され、least_conn ロードバランスメソッドは期待したように動作します。

実行時の再設定

サーバグループの設定は特別なHTTPインタフェースを使って動的に変更することができます。設定コマンドを使って、グループ内の全てのサーバまたは特定のサーバを見たり、特定のサーバのパラメータを変更したり、サーバの追加または削除をすることができます。

動的に再設定するためには:

  • グループを定義するupstreamディレクティブの中でzoneディレクティブを指定します。zone ディレクティブは共有メモリの中のzoneを設定します。サーバグループの設定はこのzoneの中で保持され、全てのworkerプロセスは同じ設定を使うでしょう。
  • 分離されたlocationの中にupstream_confディレクティブを配置します。このlocationへのアクセスは制限されていなければなりません。

この種類の設定の例を下記に示します:

http {
    ...
    # Configuration of the server group
    upstream appservers {
        zone appservers 64k;

        server appserv1.example.com      weight=5;
        server appserv2.example.com:8080 fail_timeout=5s;

        server reserve1.example.com:8080 backup;
        server reserve2.example.com:8080 backup;
    }

    server {
        # Location that proxies requests to the group
        location / {
            proxy_pass http://appservers;
            health_check;
        }

        # Location for configuration requests
        location /upstream_conf {
            upstream_conf;
            allow 127.0.0.1;
            deny all;
        }
    }
}

ここで、二つ目のlocationへのアクセスは127.0.0.1 アドレスからのみ許可されています。他のIPアドレスからのアクセスは全て拒否されます。

nginxへ設定コマンドを渡すには、どのような方法でもいいのでHTTPリクエストを送信します。そのリクエストは、upstream_confを含んでいるlocationへいくための適当なURIを持っていなければなりません。リクエストはサーバグループの名前を設定されたupstream 引数を含む必要があります。例えば、グループ内の全ての(backupで印を付けられている)バックアップサーバを見るには、次のものを送信します

http://127.0.0.1/upstream_conf?upstream=appservers&backup=

グループに新しいサーバを追加するには、addserver 引数と一緒にリクエストを送信します:

http://127.0.0.1/upstream_conf?add=&upstream=appservers&server=appserv3.example.com:8080&weight=2&max_fails=3

サーバを削除するには、remove コマンドとサーバを識別するid 引数と一緒にリクエストを送信します:

http://127.0.0.1/upstream_conf?remove=&upstream=appservers&id=2

特定のサーバのパラメータを変更するには、 サーバを識別するid 引数とパラメータを一緒にリクエストを送信します:

http://127.0.0.1/upstream_conf?upstream=appservers&id=2&down=

もっと多くの例はreference を見てください。

TOP
inserted by FC2 system