QoE

NGINXを使用したカナリアの展開

2015年8月5日

Webサービスの最初のバージョンをデプロイしたばかりで、ユーザーはそれを気に入っており、使用をやめることはできません。次に、次のようなアップグレードされたバージョンのサービスをデプロイすることを検討しています。

  • サービスを構成するいくつかのプロセスの停止と再起動が含まれる場合でも、新しいバージョンをデプロイおよび構成している間は、サービスが中断されないようにする必要があります。
  • 両方のバージョンをしばらく並行して実行し、各バージョンをトラフィックの制御された部分で実行して、サービスの新しいバージョンが期待どおりに動作することを検証できます。これはとして知られています カナリア展開、 また 青緑色の展開、およびA/Bテストのインスタンスでもあります。
  • トラフィック制御メカニズムは、サービスを中断することなく構成可能である必要があります。たとえば、新しいバージョンが誤動作しているように見える場合、トラフィックをすばやく送信して古いバージョンに戻すことができます。
  • トラフィック制御メカニズムでは、パーセンテージベースの制御(たとえば、パブリックトラフィックの1%を新しいバージョンに転送する必要があります)と、IPアドレスやUser-agentなどのHTTPヘッダーに基づくクライアント依存の制御の両方を許可する必要があります。およびリファラー(たとえば、従業員または既知のテスターは、新しいバージョンに誘導する必要があります)、またはそれらの組み合わせ。
  • トラフィック制御メカニズムは、「スティッキネス」を保証する必要があります。クライアントからのすべてのHTTP要求は、特定のトラフィック制御構成に対して、同じバージョンで処理される必要があります。
  • 別々のバージョンはすべて同じデータベースを使用しています。下位互換性と下位互換性を備えたWebアプリを設計する必要があるため、これは難しい注文です。これは見た目ほど難しくはなく、段階的な展開とロールバックを実現するために不可欠です。これを実現する方法については、今後の投稿で説明します。

カナリアの展開は非常に便利な手法であり、それを実装するために使用できるメカニズムは複数あります。この投稿では、使用している場合の方法について説明します NGINX フロントWebサーバーとして、特に DjangouWSGIベース Webサービス。ただし、他の種類のWebサービスにも同様の構成を使用できます。将来の投稿では、同じを使用して同じことを達成するためのもう少し複雑な方法について説明します HAProxy.
Touchstone Webサービスの開発中に、これらの手法を学びました。 Conviva Inc.  Convivaは、ビデオ品質の分析と最適化のリーダーであり、Touchstoneは、Convivaの顧客がビデオプレーヤーへのConvivaライブラリの統合をテストおよび微調整するために使用する独自のWebサービスです。 Convivaには多くのタイムゾーンに顧客がいて、Touchstone Webサービスを使用する自動化された継続的テストツールが多数あるため、アップグレードを展開するためにサービスを中断する便利な時間はありません。

次に、実現したいトラフィック制御構成の例を説明します(下の図を参照)。

  • Webサービスの3つの個別のインスタンスをデプロイします。各インスタンスには、独自の静的アセットファイルのセットがあり、独自のuWSGIサーバーが異なるバージョンのDjangoアプリケーションを実行している可能性があります。これらのバージョンを「アルファ」(アーリーアダプターのテストが最も少ないバージョン)、「ベータ」(一般提供の準備ができていると考えられている)、および「ga」(強化された一般提供バージョン)と呼びます。 Djangoアプリケーションのこれらすべてのインスタンスは同じデータベースを使用し、永続化されたデータのすべての下位互換性サポートと下位互換性サポートがアプリケーション自体に組み込まれていることに注意してください。
  • パブリックIPアドレスに基づいて、「従業員」グループと「テスター」グループからのクライアントを識別します。 「従業員」から100%のトラフィックを送信し、「テスター」グループから「アルファ」インスタンスに30%のトラフィックを送信します。 「ベータ」インスタンスは、残りの「テスター」トラフィックとパブリックトラフィックの1%を取得します。最後に、パブリックトラフィックの99%は「ga」インスタンスに移動する必要があります。

A Chart Of Nginx, A Web Server Configuration Language

NGINX は高性能のWebサーバーとリバースプロキシサーバーであり、柔軟性があります。 構成言語 着信要求の処理方法を制御します。 Webサービスの優れた展開設計では、静的アセットとHTTPSターミネーションに、実際のアプリケーション(このコンテキストでは「アップストリーム」アプリケーションと呼ばれる)へのリバースプロキシ設定を使用して、実際のWebサーバーを使用する必要があることは既にご存知でしょう。 NGINXはWebサーバーとして非常に優れた選択肢であり、ここで示すように、静的ファイルを提供してHTTPS接続を終了するよりも、デプロイメントに対してかなり多くのことができることがわかります。
NGINX構成言語の次の機能を利用します。

  • NGINX構成では、着信HTTPリクエストの内容に基づいてリクエストごとに設定される変数を使用できます。次に、変数を使用して他の変数を計算し、最終的には、プロキシされるアップストリームアプリケーションや、静的ファイルが提供されるディレクトリなど、各リクエストの処理方法を制御できます。
  • 構成ディレクティブ ジオ リクエストの送信元のIPアドレスに基づいて変数の値を設定します。
    #「$ip_range」変数は「employees」または「testers」のいずれかに設定されます。
    クライアントのIPアドレスに基づく#または「パブリック」
    geo $ip_range {
    69.12.128.0/17人の従業員;当事務所の#IPアドレス
    128.32.0.0/16テスター;テスターの#IPアドレス
    デフォルトのパブリック。 #他のみんな
    }

     

  • ディレクティブ split_clients カスタマイズされた粘着性で分割されたランダム化されたパーセンテージに基づいて変数の値を設定します。以下の例では、変数$remote_addr(クライアントIPアドレス)の値が文字列「AAA」と連結され、結果が32ビットの数値にハッシュされます。定義された変数の値は、32ビット範囲のどこにハッシュ値が含まれるかに基づいて設定されます。
    #「$split」変数が異なるパーセンテージ範囲に設定されている
    remote_addr(クライアントIPアドレス)による#スティッキ
    split_clients "$ {remote_addr} AAA" $split {
    1%フラクション1; #「fraction1」に割り当てられたリモートアドレスの1%
    30%フラクション2; 「fraction2」に割り当てられたリモートアドレスの#30%
    * 他の; #は「その他」に休む
    }

    このスキームは、同じIPアドレスを持つ2つのリクエストが、「$split」変数の同じ値になることを保証します。このスキームは、split_clientディレクティブの「$remote_addr」の代わりに、または「$remote_addr」に加えて、他の変数を使用して適合させることができます。
    「${remote_addr}AAA」という表記は、文字列補間を実行し、「AAA」と連結された$remote_addr変数の値に基づいて文字列を計算することに注意してください。

  • The 地図 ディレクティブを使用して、他の変数に基づいて条件付きで変数の値を計算できます。以下の例では、「$instance」変数は、正規表現の一致を使用して、上記で計算された$ip_range変数と$split変数の連結に基づいて設定されます。
    #「$instance」変数は、$ip_rangeおよび$splitに基づいて設定されます。
    マップ"${ip_range} _$ {split}" $instance {
    "〜^employees_。*"alpha; #「従業員」から「アルファ」まですべて
    "〜^testers_fraction2$"アルファ; #「テスター」から「アルファ」への30%
    "〜^testers_。*"ベータ版; #残りは「テスター」から「ベータ」まで
    "〜^public_fraction1$"ベータ版;公衆の#1%から「ベータ」へ
    デフォルトのga; #他のすべてを「ga」に
    }

     

    「〜」プレフィックスは、「map」に正規表現の一致を使用するように指示し、「map」のさまざまな句は、一致するまで順番に評価されます。

次に示すように、$instance変数の値を使用して、要求をプロキシするWebアプリケーションのインスタンスを決定するだけです。

# uUSGIアップストリームハンドラー、インスタンスごとに個別のUNIXソケット
アップストリームapp_alpha_django{
サーバーunix:///opt/app_alpha/uwsgi.sock;
}
アップストリームapp_beta_django{
サーバーunix:///opt/app_beta/uwsgi.sock;
}
アップストリームapp_ga_django{
サーバーunix:///opt/app_ga/uwsgi.sock;
}
サーバー{
80を聞く;
場所/静的{
#各インスタンスには独自の静的ファイルがあります
ルート/opt/ app_$ {instance} / static;
}

#すべてのuwsgi要求に共通のパラメーターを定義します
位置 / {
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
…より標準的なuwsgiパラメータ…
#各インスタンスには独自のアップストリームサーバーがあります
uwsgi_pass app_$ {instance} _django;
}
}

 

それでおしまい!よくほとんど。また、スクリプトを使用して、さまざまなインスタンス、IP範囲、およびパーセンテージの仕様に基づいて上記の構成を生成します。たとえば、スクリプトは、すべてのトラフィックを単一のインスタンスに強制する構成をすばやく生成できます。最後に、スクリプトはNGINX構成をテストし、次にNGINXに新しい構成をロードするように指示します(NGINXが要求をドロップせずに実行できること)。

#リロードする前に、構成をテストするようにnginxに指示してください。
sudo / usr / sbin / nginx -t
sudo kill -HUP `cat /var/run/nginx.pid`

この投稿がNGINXを最大限に活用するのに役立ち、おそらくあなたが マニュアル さらに多くのグッズのために。