NGINXとNGINX Plusによる負荷分散:第2回

NGINX | 2014年3月17日

「Load Balancing with NGINX and NGINX Plus, Part 1」では、複数のWebサーバーにトラフィックを分散するシンプルなHTTPプロキシを設定しました。この記事では、以下の追加機能について説明します。このうち一部は、NGINX Plusで利用できます。キープアライブによるパフォーマンス最適化、ヘルスチェック、セッション維持、リダイレクト、およびコンテンツ書き換えです。

NGINXおよびNGINX Plusの負荷分散機能の詳細については、「NGINX Plus Admin Guide」をご覧ください。

編集者注 – NGINX Plus Release 5以降では、TCPベースのアプリケーションも負荷分散できます。Release 6では、ヘルスチェック、動的再構成、SSL終端などが追加され、TCP負荷分散機能が大幅に拡張されました。NGINX Plus Release 7以降では、TCPロードバランサーはHTTPロードバランサーと同等の機能をすべて備えています。UDP負荷分散のサポートはRelease 9で導入されました。

TCPおよびUDPのロードバランシングは、streamコンテキストで構成します。httpコンテキストではありません。HTTPとTCP/UDPには本質的な違いがあるため、使用できるディレクティブとパラメーターは一部異なります。詳細については、HTTPおよびTCP/UDP Upstreamモジュールのドキュメントを参照してください。

簡単なおさらい

振り返りとして、以下は前回の記事で作成した構成です。

server {    listen 80;

    location / {
        proxy_pass http://backend;

        # Rewrite the 'Host' header to the value in the client request,
        # or primary server name
        proxy_set_header Host $host;

        # Alternatively, put the value in the config:
        # proxy_set_header Host www.example.com;
    } 
}

upstream backend {
    zone backend 64k;  # Use NGINX Plus' shared memory
    least_conn;

    server webserver1 weight=1;
    server webserver2 weight=4;
}

この記事では、ロードバランシングの効果を高めるための、NGINXとNGINX Plusの簡単な設定方法をいくつかご紹介します。

HTTPキープアライブ

NGINXまたはNGINX Plusとアップストリームサーバー間でHTTPキープアライブを有効にすると、レイテンシーが低減してパフォーマンスが向上し、NGINXでエフェメラルポートが枯渇する可能性も低減します。

HTTPプロトコルは、基盤となるTCP接続を使用してHTTPリクエストを送信し、HTTPレスポンスを受信します。 HTTPキープアライブ接続を使用すると、これらのTCP接続を再利用できるため、リクエストごとに接続を確立して切断するオーバーヘッドを回避できます。

NGINXはフルプロキシとして、クライアントからの接続(フロントエンドのキープアライブ接続)とサーバーへの接続(アップストリームのキープアライブ接続)を個別に管理します。

NGINXは、アップストリームサーバーへのアイドル状態のkeepalive接続をまとめた「キャッシュ」を維持します。アップストリームにリクエストを転送する必要がある場合、新しいTCP接続を作成する代わりに、キャッシュ内の確立済みkeepalive接続を使用します。これにより、NGINXとアップストリームサーバー間のトランザクションのレイテンシーが短縮され、エフェメラルポートの使用頻度も低下するため、NGINXは大量のトラフィックを受け入れて負荷分散できます。トラフィックが急増するとキャッシュが空になることがあり、その場合、NGINXはアップストリームサーバーへの新しいHTTP接続を確立します。

他の負荷分散ツールでは、この手法は「多重化」、「コネクションプーリング」、「コネクション再利用」、または「OneConnect」と呼ばれることがあります。

設定にproxy_http_version、proxy_set_header、およびkeepaliveディレクティブを含めることで、キープアライブ接続キャッシュを構成します。

server {    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
     }
}

upstream backend {
    server webserver1;
    server webserver2;

    # maintain up to 20 idle connections to the group of upstream servers
    keepalive 20;
}

ヘルスチェック

ヘルスチェックを有効にすると、負荷分散サービスの信頼性が向上し、エンドユーザーにエラーメッセージが表示される可能性が低減されるほか、一般的なメンテナンス作業も容易になります。

NGINX Plusの「ヘルスチェック」機能を使用すると、アップストリームサーバーの障害を検出できます。NGINX Plusは「合成トランザクション」を使用して各サーバーをプローブし、その応答をhealth_checkディレクティブに設定したパラメーター(matchパラメーターを指定した場合は、関連付けられたmatch設定ブロックも含む)と照合します。

server {    listen 80;

    location / {
        proxy_pass http://backend;

        health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

        # The health checks inherit other proxy settings
        proxy_set_header Host www.foo.com;
    }
}

match statusok {
    # Used for /test.php health check
    status 200;
    header Content-Type = text/html;
    body ~ "Server[0-9]+ is alive";
}

ヘルスチェックは、親のlocationブロックから一部のパラメーターを継承します。設定でランタイム変数を使用している場合、これが問題を引き起こす可能性があります。たとえば、次の設定は、クライアントリクエストからHostヘッダーの値を抽出するため、実際のHTTPトラフィックでは機能します。しかし、ヘルスチェックで使用する合成トランザクションにはHostヘッダーが設定されておらず、合成トランザクションでHostヘッダーが使用されないため、おそらく機能しません。

location / {    proxy_pass http://backend;

    # This health check might not work...
    health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

    # Extract the 'Host' header from the request
    proxy_set_header Host $host;
}

有効な解決策の1つは、ヘルスチェックトランザクションで使用するすべてのパラメーターを静的に定義するダミーの「location」ブロックを作成することです。

location /internal-health-check1 {    internal; # Prevent external requests from matching this location block

    proxy_pass http://backend;

    health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

    # Explicitly set request parameters; don't use run-time variables
    proxy_set_header Host www.example.com;
}

詳細については、NGINX Plus管理者ガイドをご覧ください。

セッション維持

セッション永続化により、クラスターにデプロイできないアプリケーションでも、信頼性の高い負荷分散とスケーリングが可能になります。セッション状態を保存して複製するアプリケーションは、より効率的に動作し、エンドユーザーのパフォーマンスも向上します。

一部のアプリケーションでは、ユーザーが仮想ショッピングカートに商品を追加したり、アップロードした画像を編集したりする際などに、アップストリームサーバーに状態情報を保存することがあります。このような場合、そのユーザーからの後続のリクエストをすべて同じサーバーに転送することが望ましい場合があります。

セッション永続化ではリクエストのルーティング先が指定されるのに対し、ロードバランシングではNGINXが最適なアップストリームサーバーを自由に選択できます。NGINX Plusのセッション永続化機能を使用すると、この2つのプロセスを併用できます。

条件:リクエストがセッション永続化ルールに一致する場合
処理:対象のアップストリームサーバーを使用する
それ以外:負荷分散アルゴリズムを適用してアップストリームサーバーを選択する

ターゲットサーバーが利用できず、セッション永続化による決定に失敗した場合、NGINX Plusは負荷分散によって接続先を決定します。

最もシンプルなセッション永続化方式は「sticky cookie」方式です。NGINX Plusは最初のレスポンスに、固定先のアップストリームサーバーを識別するCookieを挿入します。

sticky cookie srv_id expires=1h domain=.example.com path=/;

代替手段である「sticky route」方式では、NGINXはJSESSIONID Cookieなどのリクエストパラメーターに基づいてアップストリームサーバーを選択します。

upstream backend {
   server backend1.example.com route=a;
   server backend2.example.com route=b;

    # select first non-empty variable; it should contain either 'a' or 'b'
    sticky route $route_cookie $route_uri;
}

詳細については、NGINX Plus管理者ガイドをご覧ください。

HTTPリダイレクトの書き換え

一部のリダイレクトが機能しない場合、特にプロキシから実際のアップストリームサーバーにリダイレクトされる場合は、HTTPリダイレクトを書き換えます。

アップストリームサーバーにプロキシする場合、サーバーはローカルアドレスでアプリケーションを公開しますが、アプリケーションへのアクセスには別のアドレス、つまりプロキシのアドレスを使用します。通常、これらのアドレスはドメイン名に解決されるため、サーバーとプロキシのドメインが異なると問題が発生する可能性があります。

たとえば、テスト環境では、プロキシに直接(IPアドレスで)アクセスするか、localhostとしてアクセスすることがあります。ただし、アップストリームサーバーは実際のドメイン名(www.nginx.comなど)でリクエストを待ち受けている場合があります。アップストリームサーバーがリダイレクトメッセージ(3xxステータスとLocationヘッダー、またはRefreshヘッダーを使用)を発行すると、そのメッセージにサーバーの実際のドメインが含まれることがあります。

NGINXは、この問題でよく見られるケースを検出して修正しようとします。特定の書き換えを強制するために完全な制御が必要な場合は、次のようにproxy_redirectディレクティブを使用します。

proxy_redirect http://staging.mysite.com/ http://$host/;

HTTPレスポンスの書き換え

HTTPレスポンスの内容を書き換える必要がある場合があります。たとえば上記の例のように、レスポンスにプロキシ以外のサーバーを参照する絶対リンクが含まれている場合です。

適用する書き換えは、sub_filterディレクティブを使用して定義できます。

sub_filter /blog/ /blog-staging/;
sub_filter_once off;

非常によくある落とし穴の1つが、HTTP圧縮の使用です。クライアントが圧縮データを受け入れ可能であることを通知し、それを受けてサーバーがレスポンスを圧縮すると、NGINXはレスポンスを検査、変更できません。最も簡単な対策は、クライアントのリクエストに含まれるAccept-Encodingヘッダーを空文字列("")に設定して削除することです。

proxy_set_header Accept-Encoding "";

完全な例

この記事で説明したすべての手法を使用する負荷分散設定のテンプレートを以下に示します。NGINX Plusで利用できる高度な機能はオレンジ色で強調表示しています。

[編集者注 – 以下の設定は、当初使用されていた個別のモジュールに代えて、ライブアクティビティの監視とアップストリームグループの動的設定にNGINX Plus APIを使用するよう更新されています。]

server {
    listen 80;

    location / {
        proxy_pass http://backend;

        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Accept-Encoding "";
        proxy_redirect http://staging.example.com/ http://$host/;

        # Rewrite the Host header to the value in the client request
        proxy_set_header Host $host;

        # Replace any references inline to staging.example.com
        sub_filter http://staging.example.com/ /;
        sub_filter_once off;
    }

    location /internal-health-check1 {
        internal; # Prevent external requests from matching this location block
        proxy_pass http://backend;
        health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
        # Explicitly set request parameters; don't use runtime variables
        proxy_set_header Host www.example.com;
    }
 
upstream backend {
    zone backend 64k; # Use NGINX Plus' shared memory
    least_conn;
    keepalive 20;

    # Apply session persistence for this upstream group
    sticky cookie srv_id expires=1h domain=.example.com path=/servlet;

    server webserver1 weight=1; 
    server webserver2 weight=4; 
}

match statusok {
    # Used for /test.php health check
    status 200;
    header Content-Type = text/html;
    body ~ "Server[0-9]+ is alive";
}

server {
    listen 8080;
    root /usr/share/nginx/html;

    location = /api {
        api write=on; # Live activity monitoring and
                      # dynamic configuration of upstream groups

        allow 127.0.0.1; # permit access from localhost
        deny all;        # deny access from everywhere else
    }
}

NGINX Plusの優れた負荷分散機能を実際にお試しください。今すぐ30日間の無料トライアルを開始するか、ユースケースについてご相談ください。


共有

著者について

Owen Garrett
Owen Garrettプロダクトマネジメント担当シニアディレクター

Owen Garrettのその他のブログ記事

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります