EnvoyをSidecar Proxyのマイクロサービスモードとして使用-2.タイムアウトと再試行


このブログは、Envoy ProxyとIstio.ioを深く研究し、マイクロサービスシリーズの文章を接続し、管理するためにより優雅な方法を実現する方法の一部です.
次のセクションのアイデアです(パブリケーション時にリンクを更新します):
  • 遮断器(第1部)
  • 再試行/タイムアウト(第2部)
  • 分散トレース(第3部)
  • Prometheusの指標収集(第4部)
  • rate limiter(第5部)
  • 第1部-envoy proxyを使用してタイムアウトと再試行を実現
    第1部では、Envoy Proxyの遮断機能の実装について説明します.第2部では、タイムアウトや再試行などの他の弾性機能を有効にする方法について詳しく説明します.簡単なプレゼンテーションを意図しているので、モードと使い方を個別に説明できます.このプレゼンテーションのソースコードをダウンロードし、説明に従ってください.
    このプレゼンテーションは、クライアントとサービスで構成されています.クライアントはJava httpアプリケーションで、「上流」サービスのhttp呼び出しをシミュレートします(ここではEnvoys用語を使用し、repo全体を貫くことに注意してください).クライアントはdocker.io/ceposta/http-envoy-client:latestのDockerミラーにパッケージ化されています.http-client Javaアプリケーションの他に、Envoy Proxyの一例があります.この配置モデルでは、Envoyはサービスのsidercar(この例ではhttpクライアント)として配置されています.http-clientがアウトバウンドコール(上流サービス)を行う場合の場合、すべての呼び出しはEnvoy Proxy sidercarを通過します.
    これらの例の「上流」サービスはhttpbin.orgです.httpbin.orgでは、HTTPサービスの動作を簡単にシミュレートできます.素晴らしいので、それを見ていない場合は、それを確認してください.
    再試行とタイムアウトのプレゼンテーションには独自のenvoy.jsonプロファイルがあります.プロファイルの各セクションの参照ドキュメントを参照して、完全な構成を理解することをお勧めします.datawire.ioの優秀なスタッフもEnvoyとその構成についてよく紹介しています.あなたもチェックする必要があります.
    再試行demoの実行
    再試行デモでは、次のように、Envoyでルーティングを構成します.
      "routes": [
        {
          "timeout_ms": 0,
          "prefix": "/",
          "auto_host_rewrite": true,
          "cluster": "httpbin_service",
          "retry_policy": {
            "retry_on": "5xx",
            "num_retries": 3
          }
    
        }

    ここではHTTP状態が5 xxの場合に最大3回再試行する.
    以前のプレゼンテーションを実行した場合は、そのプレゼンテーションの新しい初期化ステータスが開始されることを確認します.各プレゼンテーションに異なるEnvoy構成を提供し、毎回新しい初期化ステータスから開始することを確認します.
    まず既存のdemoを停止します.
    ./docker-stop.sh

    再試行demoの実行を開始します.
    ./docker-run.sh -d retries

    次に、クライアントを実行するために1回のコールを使用します.このコールは、HTTP 500エラーを返すべきHTTPエンドポイントをトリガーします.curl.shスクリプトを使用して、プレゼンテーションコンテナでcurlを呼び出すように設定します.
    ./curl.sh -vvvv localhost:15001/status/500

    同様の出力が表示されます.
    * Hostname was NOT found in DNS cache
    *   Trying ::1...
    * connect to ::1 port 15001 failed: Connection refused
    *   Trying 127.0.0.1...
    * Connected to localhost (127.0.0.1) port 15001 (#0)
    > GET /status/500 HTTP/1.1
    > User-Agent: curl/7.35.0
    > Host: localhost:15001
    > Accept: */*
    > 
    < HTTP/1.1 500 Internal Server Error
    * Server envoy is not blacklisted
    < server: envoy
    < date: Thu, 25 May 2017 05:55:37 GMT
    < content-type: text/html; charset=utf-8
    < access-control-allow-origin: *
    < access-control-allow-credentials: true
    < x-powered-by: Flask
    < x-processed-time: 0.000718116760254
    < content-length: 0
    < via: 1.1 vegur
    < x-envoy-upstream-service-time: 684
    < 
    * Connection #0 to host localhost left intact

    では、envoyが私たちのためにどのような仕事をしたかをチェックします.
    ./get-envoy-stats.sh | grep retry
    cluster.httpbin_service.retry.upstream_rq_500: 3
    cluster.httpbin_service.retry.upstream_rq_5xx: 3
    cluster.httpbin_service.upstream_rq_retry: 3
    cluster.httpbin_service.upstream_rq_retry_overflow: 0
    cluster.httpbin_service.upstream_rq_retry_success: 0

    ここでHTTP 500エラーでenvoyが3回再試行したのを見ました.
    別の観点から見ると、再試行はサービスアーキテクチャに悪影響を及ぼす可能性があります.障害の伝播や、もがいている内部サービスにDDoSタイプの攻撃をもたらす可能性があります.
    再試行の場合は、次の点に注意してください.
  • envoyは、ジッタによって自動指数再試行されます.詳細は、ドキュメント
  • を参照してください.
    再試行タイムアウトを設定できます(再試行ごとにタイムアウト)が、ルーティング・タイムアウトの合計を設定できます(ルーティング・テーブルの構成です.詳細な構成については、タイムアウト・プレゼンテーションを参照してください).保持/適用されます.制御不能な再試行/指数関数的なショートカットを回避するために、多数の接続がある場合に再試行の割当額を制限するために、常に遮断器再試行構成を設定する必要があります.Envoyドキュメントの遮断器セクションの有効な再試行を参照してください.
    実行タイムアウトdemo
    タイムアウトプレゼンテーションでは、次のようにEnvoyでルーティングを構成します.
       "routes": [
        {
          "timeout_ms": 0,
          "prefix": "/",
          "auto_host_rewrite": true,
          "cluster": "httpbin_service",
          "timeout_ms": 3000
        }

    この構成では、httpbin_serviceクラスタにルーティングされた任意の呼び出しによって、グローバル(すなわち、すべての再試行を含む)3 sタイムアウトが設定されます.
    オーバータイムを処理するたびに、エッジからのリクエストの全体的なグローバルタイムアウトを知る必要があります.ネットワーク呼び出しマップに深く入り込むと、タイムアウトが徐々に減少しないことに気づきます.つまり、呼び出しマップを参照すると、呼び出しマップのより深いレベルのサービス呼び出しのサービスタイムアウトは、以前のサービスの呼び出しよりも小さくなるはずです.
    Envoyはタイムアウト情報の伝播を支援し、gRPCのようなプロトコルはカットオフ時間情報を伝播することができる.本シリーズを継続するにつれて、Istio Meshを使用してEnvoyエージェントを制御する方法を見て、制御平面はタイムアウト異常を発見するために障害注入を支援することができる.
    以前のプレゼンテーションを実行した場合は、そのプレゼンテーションの新しい初期化ステータスが開始されることを確認します.各プレゼンテーションに異なるEnvoy構成を提供し、毎回新しい初期化ステータスから開始することを確認します.
    まず既存のdemoを停止します.
    ./docker-stop.sh

    今からタイムアウトdemo:
    ./docker-run.sh -d timeouts

    次に、クライアントを実行するためのコールを使用します.このコールは、応答を約5秒遅らせるHTTPエンドポイントをトリガーします.この遅延はenvoyタイムアウトをトリガーするのに十分です.プレゼンテーションコンテナでcurlを呼び出すように設定されたcurl.shスクリプトを使用します.
    ./curl.sh -vvvv localhost:15001/delay/5
    

    同様の出力が表示されます.
    * Hostname was NOT found in DNS cache
    *   Trying ::1...
    * connect to ::1 port 15001 failed: Connection refused
    *   Trying 127.0.0.1...
    * Connected to localhost (127.0.0.1) port 15001 (#0)
    > GET /delay/5 HTTP/1.1
    > User-Agent: curl/7.35.0
    > Host: localhost:15001
    > Accept: */*
    > 
    < HTTP/1.1 504 Gateway Timeout
    < content-length: 24
    < content-type: text/plain
    < date: Thu, 25 May 2017 06:13:53 GMT
    * Server envoy is not blacklisted
    < server: envoy
    < 
    * Connection #0 to host localhost left intact
    upstream request timeout

    私たちの要求がタイムアウトしているのを見ました.
    次のenvoyのステータスを確認します.
    ./get-envoy-stats.sh | grep timeout

    ここでは、Envoyによってタイムアウトされたリクエスト(送信されたリクエスト!)が1つ見られます.
    cluster.httpbin_service.upstream_cx_connect_timeout: 0
    cluster.httpbin_service.upstream_rq_per_try_timeout: 0
    cluster.httpbin_service.upstream_rq_timeout: 1
    http.admin.downstream_cx_idle_timeout: 0
    http.egress_http.downstream_cx_idle_timeout: 0
    

    リクエストを送信すると、今回の遅延が小さい場合は、コールが表示されます.
    ./curl.sh -vvvv localhost:15001/delay/2
    * Hostname was NOT found in DNS cache
    *   Trying ::1...
    * connect to ::1 port 15001 failed: Connection refused
    *   Trying 127.0.0.1...
    * Connected to localhost (127.0.0.1) port 15001 (#0)
    > GET /delay/2 HTTP/1.1
    > User-Agent: curl/7.35.0
    > Host: localhost:15001
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    * Server envoy is not blacklisted
    < server: envoy
    < date: Thu, 25 May 2017 06:15:41 GMT
    < content-type: application/json
    < access-control-allow-origin: *
    < access-control-allow-credentials: true
    < x-powered-by: Flask
    < x-processed-time: 2.00246119499
    < content-length: 309
    < via: 1.1 vegur
    < x-envoy-upstream-service-time: 2145
    < 
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Connection": "close", 
        "Host": "httpbin.org", 
        "User-Agent": "curl/7.35.0", 
        "X-Envoy-Expected-Rq-Timeout-Ms": "3000"
      }, 
      "origin": "68.3.84.124", 
      "url": "http://httpbin.org/delay/2"
    }
    * Connection #0 to host localhost left intact
    

    また、Envoyはタイムアウトheadersを伝播し、上流サービスが所望の内容を理解できるようにすることに注意してください.