すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Service Mesh:connectionPool フィールドを構成してサーキットブレーキングを実装する

最終更新日:Mar 29, 2025

サーキットブレーキングは、システム障害または過負荷の場合にシステムをさらなる損傷から保護するために使用されるトラフィック管理メカニズムです。従来の Java サービスでは、Resilience4j などのフレームワークを使用してサーキットブレーキングを実装できます。従来のアプローチと比較して、Istio では、各サービスのアプリケーションコードにサーキットブレーキングを統合することなく、ネットワークレベルでサーキットブレーキングを実装できます。 connectionPool フィールドを構成して、サーキットブレーキングを実装できます。これにより、システムの安定性と信頼性が向上し、目的のサービスが異常なリクエストの影響を受けるのを防ぎます。

前提条件

Container Service for Kubernetes(ACK)クラスタが Service Mesh(ASM)インスタンスに追加されています。詳細については、「ASM インスタンスにクラスタを追加する」をご参照ください。

connectionPool 設定

サーキットブレーキング機能を有効にする前に、デスティネーションルールを作成して、目的のデスティネーションサービスのサーキットブレーキングを構成する必要があります。デスティネーションルールのフィールドの詳細については、「Destination Rule 」をご参照ください。

connectionPool フィールドは、サーキットブレーキングに関連するパラメーターを定義します。次の表に、connectionPool フィールドのパラメーターを示します。

パラメーター

タイプ

必須

説明

デフォルト値

tcp.maxConnections

int32

いいえ

デスティネーションホストへの HTTP1 または TCP 接続の最大数。接続数の制限は、クライアント側とサーバー側の両方のサイドカープロキシに有効です。単一のクライアントポッドは、サーバーへの構成済み接続数を超える接続を開始できません。単一のサーバーは、構成済み接続数を超える接続を受け入れることができません。サーバー上のアプリケーションサービスが受け入れることができる接続数は、次の式を使用して計算されます。min(クライアントポッドの数、サーバーポッドの数)× maxConnections。

2³²-1

http.http1MaxPendingRequests

int32

いいえ

準備完了の接続プール接続を待機しているときにキューに入れられるリクエストの最大数。

1024

http.http2MaxRequests

int32

いいえ

バックエンドサービスへのアクティブリクエストの最大数。

1024

これらのパラメーターがどのように機能するかは、1 つのクライアントと 1 つのデスティネーションサービスインスタンスのみが存在する単純なシナリオでは明らかです。 Kubernetes 環境では、インスタンスはポッドと同等です。ただし、本番環境では、次のシナリオが発生する可能性が高くなります。

  • 1 つのクライアントインスタンスと複数のデスティネーションサービスインスタンス

  • 複数のクライアントインスタンスと単一のデスティネーションサービスインスタンス

  • 複数のクライアントインスタンスと複数のデスティネーションサービスインスタンス

さまざまなシナリオで、ビジネス要件に基づいてこれらのパラメーターの値を調整して、接続プールが高負荷で複雑な環境に適応し、優れたパフォーマンスと信頼性を提供できるようにする必要があります。次のセクションでは、前述のシナリオで接続プールを構成する例を示し、クライアントとサーバーでの構成の制約を理解するのに役立ちます。次に、本番環境に適用されるサーキットブレーキングポリシーを構成できます。

構成例

このトピックでは、2 つの Python スクリプトが作成されます。1 つはデスティネーションサービス(サーバー)用、もう 1 つは呼び出しサービス(クライアント)用です。

  • サーバースクリプトは Flask アプリケーションを作成し、ルートルートに単一のエンドポイントを定義します。ルートルートにアクセスすると、サーバーは 5 秒間スリープしてから、JSON 形式で "Hello World!" 文字列を返します。

    サーバースクリプトを表示

    #!  /usr/bin/env python3
    # Flask をインポート
    from flask import Flask
    # time をインポート
    import time
    
    # Flask アプリケーションを作成
    app = Flask(__name__)
    
    # ルートルートにエンドポイントを定義
    @app.route('/hello')
    def get():
        # 5 秒間スリープ
        time.sleep(5)
        # "hello world!" を返す
        return 'hello world!'
    
    # メイン関数
    if __name__ == '__main__':
        # アプリケーションを実行
        app.run(debug=True, host='0.0.0.0', port='9080', threaded = True)
  • クライアントスクリプトは、一度に 10 個のリクエストを並行して送信することでサーバーエンドポイントを呼び出し、次のバッチの 10 個のリクエストを送信する前にしばらくスリープします。スクリプトはこれを無限ループで実行します。複数のクライアントポッドが実行されているときにすべてのクライアントポッドが同時に 10 個のリクエストのバッチを送信するようにするには、この例では、毎分 0 秒、20 秒、40 秒(システム時刻に従って)に 10 個のリクエストのバッチが送信されます。

    クライアントスクリプトを表示

    #!  /usr/bin/env python3
    # 必要なライブラリをインポート
    import requests
    import time
    import sys
    from datetime import datetime
    import _thread
    
    # 時刻表示関数
    def timedisplay(t):
      return t.strftime("%H:%M:%S")
    
    # GET リクエストを送信する関数
    def get(url):
      try:
        # 開始時刻を記録
        stime = datetime.now()
        start = time.time()
        # GET リクエストを送信
        response = requests.get(url)
        # 終了時刻を記録
        etime = datetime.now()
        end = time.time()
        # 経過時間を計算
        elapsed = end-start
        # 結果を標準エラー出力に書き込む
        sys.stderr.write("ステータス: " + str(response.status_code) + ", 開始: " + timedisplay(stime) + ", 終了: " + timedisplay(etime) + ", 経過時間: " + str(elapsed)+"\n")
        sys.stdout.flush()
      except Exception as myexception:
        # 例外が発生した場合、標準エラー出力に書き込む
        sys.stderr.write("例外: " + str(myexception)+"\n")
        sys.stdout.flush()
    
    # 30 秒間スリープ
    time.sleep(30)
    
    # 無限ループ
    while True:
      # 現在の秒数を取得
      sc = int(datetime.now().strftime('%S'))
      # リクエストを送信する時間範囲
      time_range = [0, 20, 40]
    
      # 現在の秒数が時間範囲に含まれていない場合、1 秒間スリープ
      if sc not in time_range:
        time.sleep(1)
        continue
    
      # 情報を標準エラー出力に書き込む
      sys.stderr.write("\n----------情報----------\n")
      sys.stdout.flush()
    
      # 10 個のリクエストを並行して送信
      for i in range(10):
        _thread.start_new_thread(get, ("http://circuit-breaker-sample-server:9080/hello", ))
    
      # 2 秒間スリープ
      time.sleep(2)

サンプルアプリケーションをデプロイする

  1. 次の内容を含む YAML ファイルを作成し、kubectl apply -f ${YAML ファイルの名前}.yaml コマンドを実行して、サンプルアプリケーションをデプロイします。

    YAML コードを表示

    ##################################################################################################
    #  circuit-breaker-sample-server サービス
    ##################################################################################################
    apiVersion: v1
    kind: Service
    metadata:
      name: circuit-breaker-sample-server
      labels:
        app: circuit-breaker-sample-server
        service: circuit-breaker-sample-server
    spec:
      ports:
      - port: 9080
        name: http
      selector:
        app: circuit-breaker-sample-server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: circuit-breaker-sample-server
      labels:
        app: circuit-breaker-sample-server
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: circuit-breaker-sample-server
          version: v1
      template:
        metadata:
          labels:
            app: circuit-breaker-sample-server
            version: v1
        spec:
          containers:
          - name: circuit-breaker-sample-server
            image: registry.cn-hangzhou.aliyuncs.com/acs/istio-samples:circuit-breaker-sample-server.v1
            imagePullPolicy: Always
            ports:
            - containerPort: 9080
    ---
    ##################################################################################################
    #  circuit-breaker-sample-client サービス
    ##################################################################################################
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: circuit-breaker-sample-client
      labels:
        app: circuit-breaker-sample-client
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: circuit-breaker-sample-client
          version: v1
      template:
        metadata:
          labels:
            app: circuit-breaker-sample-client
            version: v1
        spec:
          containers:
          - name: circuit-breaker-sample-client
            image: registry.cn-hangzhou.aliyuncs.com/acs/istio-samples:circuit-breaker-sample-client.v1
            imagePullPolicy: Always
    
  2. 次のコマンドを実行して、クライアントとサーバーのポッドを表示します。

    kubectl get po |grep circuit  

    予期される出力:

    circuit-breaker-sample-client-d4f64d66d-fwrh4   2/2     Running   0             1m22s
    circuit-breaker-sample-server-6d6ddb4b-gcthv    2/2     Running   0             1m22s

デスティネーションルールに制限が定義されていない場合、サーバーはクライアントからの 10 個の同時リクエストを処理できます。したがって、サーバーから返されるレスポンスコードは常に 200 です。次のコードブロックは、クライアントのログを示しています。

----------情報----------
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.016539812088013
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.012614488601685
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.015984535217285
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.015599012374878
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.012874364852905
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.018714904785156
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.010422468185425
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.012431621551514
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.011001348495483
ステータス: 200, 開始: 02:39:20, 終了: 02:39:25, 経過時間: 5.01432466506958

connectionPool フィールドを構成する

サービスメッシュテクノロジーを使用してデスティネーションサービスのサーキットブレーキングを有効にするには、デスティネーションサービスに対応するデスティネーションルールを定義するだけで済みます。

次の内容を使用して、サンプルデスティネーションサービスのデスティネーションルールを作成します。詳細については、「デスティネーションルールを管理する」をご参照ください。このデスティネーションルールは、デスティネーションサービスへの TCP 接続の数を 5 に制限します。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: circuit-breaker-sample-server
spec:
  host: circuit-breaker-sample-server
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 5

シナリオ 1:1 つのクライアントポッドとデスティネーションサービスの 1 つのポッド

  1. クライアントポッドを起動し、ログを監視します。

    より直感的な統計結果を得るために、クライアントを再起動することをお勧めします。次のログが表示されます。

    ----------情報----------
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:45, 経過時間: 5.0167787075042725
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:45, 経過時間: 5.011920690536499
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:45, 経過時間: 5.017078161239624
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:45, 経過時間: 5.018405437469482
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:45, 経過時間: 5.018689393997192
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:50, 経過時間: 10.018936395645142
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:50, 経過時間: 10.016417503356934
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:50, 経過時間: 10.019930601119995
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:50, 経過時間: 10.022735834121704
    ステータス: 200, 開始: 02:49:40, 終了: 02:49:55, 経過時間: 15.02303147315979

    上記のログは、すべてのリクエストが成功したことを示しています。ただし、各バッチの 5 つのリクエストのみが約 5 秒で応答されます。他のリクエストは 10 秒以上で応答されます。これは、tcp.maxConnections のみを使用すると、過剰なリクエストがキューに入れられることを意味します。接続が解放されるのを待機しています。デフォルトでは、キューに入れられるリクエストの数は 2³² - 1 です。

  2. 次の内容を使用してデスティネーションルールを更新し、保留中のリクエストを 1 つだけ許可します。詳細については、「デスティネーションルールを管理する」をご参照ください。

    サーキットブレーキング(フェイルファースト)を実現するには、http.http1MaxPendingRequests も設定して、キューに入れられるリクエストの数を制限する必要があります。 http1MaxPendingRequests パラメーターのデフォルト値は 1024 です。値を 0 に設定すると、デフォルト値に戻ります。したがって、値を少なくとも 1 に設定する必要があります。

    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
      name: circuit-breaker-sample-server
    spec:
      host: circuit-breaker-sample-server
      trafficPolicy:
        connectionPool:
          tcp:
            maxConnections: 5
          http:
            http1MaxPendingRequests: 1
  3. クライアントポッドを再起動して正しい統計情報を取得し、ログを監視します。

    サンプルログ:

    ----------情報----------
    ステータス: 503, 開始: 02:56:40, 終了: 02:56:40, 経過時間: 0.005339622497558594
    ステータス: 503, 開始: 02:56:40, 終了: 02:56:40, 経過時間: 0.007254838943481445
    ステータス: 503, 開始: 02:56:40, 終了: 02:56:40, 経過時間: 0.0044133663177490234
    ステータス: 503, 開始: 02:56:40, 終了: 02:56:40, 経過時間: 0.008964776992797852
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:45, 経過時間: 5.018309116363525
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:45, 経過時間: 5.017424821853638
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:45, 経過時間: 5.019804954528809
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:45, 経過時間: 5.01643180847168
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:45, 経過時間: 5.025975227355957
    ステータス: 200, 開始: 02:56:40, 終了: 02:56:50, 経過時間: 10.01716136932373

    ログは、4つのリクエストがすぐにスロットルされ、5つのリクエストがデスティネーションサービスに送信され、1つのリクエストがキューに入れられたことを示しています。

  4. 次のコマンドを実行して、クライアントの Istio プロキシがデスティネーションサービスのポッドと確立するアクティブな接続の数を表示します。

    kubectl exec $(kubectl get pod --selector app=circuit-breaker-sample-client --output jsonpath='{.items[0].metadata.name}') -c istio-proxy -- curl -X POST http://localhost:15000/clusters | grep circuit-breaker-sample-server | grep cx_active

    予期される出力:

    outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local::172.20.192.124:9080::cx_active::5

    出力は、クライアントの Istio プロキシとデスティネーションサービスのポッドの間に 5 つのアクティブな接続が確立されていることを示しています。

シナリオ 2:1 つのクライアントポッドとデスティネーションサービスの複数のポッド

このセクションでは、接続制限がポッドレベルで適用されるか、サービスレベルで適用されるかを確認します。 1 つのクライアントポッドとデスティネーションサービスの 3 つのポッドがあるとします。

  • 接続制限がポッドレベルで適用される場合、デスティネーションサービスの各ポッドの最大接続数は 5 です。

    この場合、許可される最大接続数は 15(3 ポッド×ポッドあたり 5 接続)であるため、スロットリングやキューイングは発生しません。一度に送信されるリクエストは 10 個だけなので、すべてのリクエストは成功し、約 5 秒で応答されます。

  • 接続制限がサービスレベルで適用される場合、デスティネーションサービスで実行されているポッドの数に関係なく、合計で最大 5 つの接続が許可されます。

    この場合、4つのリクエストがすぐにスロットルされ、5つのリクエストがデスティネーションサービスに送信され、1つのリクエストがキューに入れられます。

  1. 次のコマンドを実行して、デスティネーションサービスデプロイメントを 3 つのレプリカにスケーリングします。

    kubectl scale deployment/circuit-breaker-sample-server  --replicas=3
  2. クライアントポッドを再起動し、ログを監視します。

    サンプルログ:

    ----------情報----------
    ステータス: 503, 開始: 03:06:20, 終了: 03:06:20, 経過時間: 0.011791706085205078
    ステータス: 503, 開始: 03:06:20, 終了: 03:06:20, 経過時間: 0.0032286643981933594
    ステータス: 503, 開始: 03:06:20, 終了: 03:06:20, 経過時間: 0.012153387069702148
    ステータス: 503, 開始: 03:06:20, 終了: 03:06:20, 経過時間: 0.011871814727783203
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:25, 経過時間: 5.012892484664917
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:25, 経過時間: 5.013102769851685
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:25, 経過時間: 5.016939163208008
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:25, 経過時間: 5.014261484146118
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:25, 経過時間: 5.01246190071106
    ステータス: 200, 開始: 03:06:20, 終了: 03:06:30, 経過時間: 10.021712064743042

    ログは、前のコードブロックに示されているのと同様のスロットリングとキューイングを示しています。これは、デスティネーションサービスのインスタンス数を増やしても、クライアントの接続制限が増加しないことを意味します。これは、接続制限がサービスレベルで適用されていることを示しています。

  3. 次のコマンドを実行して、クライアントの Istio プロキシがデスティネーションサービスのポッドと確立するアクティブな接続の数を表示します。

    kubectl exec $(kubectl get pod --selector app=circuit-breaker-sample-client --output jsonpath='{.items[0].metadata.name}') -c istio-proxy -- curl -X POST http://localhost:15000/clusters | grep circuit-breaker-sample-server | grep cx_active

    予期される出力:

    outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local::172.20.192.124:9080::cx_active::2
    outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local::172.20.192.158:9080::cx_active::2
    outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local::172.20.192.26:9080::cx_active::2

    出力は、クライアントの Istio プロキシがデスティネーションサービスの各ポッドと 2 つのアクティブな接続を確立していることを示しています。合計で 5 つではなく 6 つの接続が確立されています。Envoy と Istio の両方のドキュメントで述べられているように、プロキシは接続数に関してある程度の余裕を許容します。

シナリオ 3:複数のクライアントポッドとデスティネーションサービスの 1 つのポッド

  1. 次のコマンドを実行して、デスティネーションサービスとクライアントのレプリカ数を調整します。

    kubectl scale deployment/circuit-breaker-sample-server --replicas=1 
    kubectl scale deployment/circuit-breaker-sample-client --replicas=3
  2. クライアントポッドを再起動し、ログを監視します。

    クライアントのログを表示

    クライアント 1
    
    ----------情報----------
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.008828878402709961
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.010806798934936523
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.012855291366577148
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.004465818405151367
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.007823944091796875
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.06221342086791992
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.06922149658203125
    ステータス: 503, 開始: 03:10:40, 終了: 03:10:40, 経過時間: 0.06859922409057617
    ステータス: 200, 開始: 03:10:40, 終了: 03:10:45, 経過時間: 5.015282392501831
    ステータス: 200, 開始: 03:10:40, 終了: 03:10:50, 経過時間: 9.378434181213379
    
    クライアント 2
    
    ----------情報----------
    ステータス: 503, 開始: 03:11:00, 終了: 03:11:00, 経過時間: 0.007795810699462891
    ステータス: 503, 開始: 03:11:00, 終了: 03:11:00, 経過時間: 0.00595545768737793
    ステータス: 503, 開始: 03:11:00, 終了: 03:11:00, 経過時間: 0.013380765914916992
    ステータス: 503, 開始: 03:11:00, 終了: 03:11:00, 経過時間: 0.004278898239135742
    ステータス: 503, 開始: 03:11:00, 終了: 03:11:00, 経過時間: 0.010999202728271484
    ステータス: 200, 開始: 03:11:00, 終了: 03:11:05, 経過時間: 5.015426874160767
    ステータス: 200, 開始: 03:11:00, 終了: 03:11:05, 経過時間: 5.0184690952301025
    ステータス: 200, 開始: 03:11:00, 終了: 03:11:05, 経過時間: 5.019806146621704
    ステータス: 200, 開始: 03:11:00, 終了: 03:11:05, 経過時間: 5.0175628662109375
    ステータス: 200, 開始: 03:11:00, 終了: 03:11:05, 経過時間: 5.031521558761597
    
    クライアント 3
    
    ----------情報----------
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.012019157409667969
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.012546539306640625
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.013760805130004883
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.014089822769165039
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.014792442321777344
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.015463829040527344
    ステータス: 503, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.01661539077758789
    ステータス: 200, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.02904224395751953
    ステータス: 200, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.03912043571472168
    ステータス: 200, 開始: 03:13:20, 終了: 03:13:20, 経過時間: 0.06436014175415039

    ログは、各クライアントの 503 エラーの数が増加していることを示しています。システムは、3 つのすべてのクライアントポッドから最大 5 つの同時リクエストのみを許可します。

  3. クライアントプロキシのログを表示します。

    クライアントプロキシのログを表示

    {"authority":"circuit-breaker-sample-server:9080","bytes_received":"0","bytes_sent":"81","downstream_local_address":"192.168.142.207:9080","downstream_remote_address":"172.20.192.31:44610","duration":"0","istio_policy_status":"-","method":"GET","path":"/hello","protocol":"HTTP/1.1","request_id":"d9d87600-cd01-421f-8a6f-dc0ee0ac8ccd","requested_server_name":"-","response_code":"503","response_flags":"UO","route_name":"default","start_time":"2023-02-28T03:14:00.095Z","trace_id":"-","upstream_cluster":"outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"python-requests/2.21.0","x_forwarded_for":"-"}
    
    {"authority":"circuit-breaker-sample-server:9080","bytes_received":"0","bytes_sent":"81","downstream_local_address":"192.168.142.207:9080","downstream_remote_address":"172.20.192.31:43294","duration":"58","istio_policy_status":"-","method":"GET","path":"/hello","protocol":"HTTP/1.1","request_id":"931d080a-3413-4e35-91f4-0c906e7ee565","requested_server_name":"-","response_code":"503","response_flags":"URX","route_name":"default","start_time":"2023-02-28T03:12:20.995Z","trace_id":"-","upstream_cluster":"outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local","upstream_host":"172.20.192.84:9080","upstream_local_address":"172.20.192.31:58742","upstream_service_time":"57","upstream_transport_failure_reason":"-","user_agent":"python-requests/2.21.0","x_forwarded_for":"-"}
    

    スロットルされたリクエストには、2 つの異なるタイプのログが表示されます。このようなリクエストに対しては、エラーコード 503 が返されます。ログは、RESPONSE_FLAGS フィールドに UOURX の 2 つの値があることを示しています。

    • UO:アップストリームオーバーフロー(サーキットブレーキング)を示します。

    • URX:アップストリーム HTTP リクエストの再試行条件が満たされていないか、TCP 接続試行の最大数に達したため、リクエストが拒否されたことを示します。

    DURATIONUPSTREAM_HOSTUPSTREAM_CLUSTER などのログ内の他のフィールドの値に従って、次の結論をさらに導き出すことができます。

    UO フラグが付いたリクエストはクライアントプロキシによってローカルでスロットルされ、URX フラグが付いたリクエストはデスティネーションサービスプロキシによって拒否されます。

  4. 前の手順の結論の正しさを確認し、デスティネーションサービスプロキシのログを確認します。

    デスティネーションサービスプロキシのログを表示

    {"authority":"circuit-breaker-sample-server:9080","bytes_received":"0","bytes_sent":"81","downstream_local_address":"172.20.192.84:9080","downstream_remote_address":"172.20.192.31:59510","duration":"0","istio_policy_status":"-","method":"GET","path":"/hello","protocol":"HTTP/1.1","request_id":"7684cbb0-8f1c-44bf-b591-40c3deff6b0b","requested_server_name":"outbound_.9080_._.circuit-breaker-sample-server.default.svc.cluster.local","response_code":"503","response_flags":"UO","route_name":"default","start_time":"2023-02-28T03:14:00.095Z","trace_id":"-","upstream_cluster":"inbound|9080||","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"python-requests/2.21.0","x_forwarded_for":"-"}
    {"authority":"circuit-breaker-sample-server:9080","bytes_received":"0","bytes_sent":"81","downstream_local_address":"172.20.192.84:9080","downstream_remote_address":"172.20.192.31:58218","duration":"0","istio_policy_status":"-","method":"GET","path":"/hello","protocol":"HTTP/1.1","request_id":"2aa351fa-349d-4283-a5ea-dc74ecbdff8c","requested_server_name":"outbound_.9080_._.circuit-breaker-sample-server.default.svc.cluster.local","response_code":"503","response_flags":"UO","route_name":"default","start_time":"2023-02-28T03:12:20.996Z","trace_id":"-","upstream_cluster":"inbound|9080||","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"python-requests/2.21.0","x_forwarded_for":"-"}

    予想どおり、レスポンスコード 503 がデスティネーションサービスプロキシのログに表示されます。これが、クライアントプロキシのログに "response_code":"503""response_flags":"URX" が含まれている理由です。

要約すると、クライアントプロキシは、各ポッドで最大 5 つの接続が許可されるという制限に従ってリクエストを送信し、UO レスポンスフラグを使用して過剰なリクエストをスロットルまたはキューに入れます。 3 つのすべてのクライアントプロキシは、バッチの開始時に最大 15 個の並列リクエストを送信できます。ただし、デスティネーションサービスプロキシも接続数を 5 に制限しているため、正常に送信できるリクエストは 5 つだけです。デスティネーションサービスプロキシは 5 つのリクエストのみを受け入れ、残りをスロットルします。スロットルされたリクエストは、クライアントプロキシのログで URX レスポンスフラグによってマークされます。

次の図は、前述のシナリオで複数のクライアントポッドから単一のデスティネーションサービスポッドにリクエストがどのように送信されるかを示しています。

シナリオ 4:クライアントとデスティネーションサービスの両方で複数のポッド

デスティネーションサービスのレプリカ数を増やすと、各デスティネーションサービスプロキシが 5 つの並列リクエストを許可するため、リクエストの全体的な成功率が上がります。このようにして、クライアントプロキシとデスティネーションサービスプロキシの両方でスロットリングを観察できます。

  1. 次のコマンドを実行して、デスティネーションサービスのレプリカ数を 2 に、クライアントのレプリカ数を 3 に増やします。

    kubectl scale deployment/circuit-breaker-sample-server --replicas=2
    kubectl scale deployment/circuit-breaker-sample-client --replicas=3

    バッチ内の 3 つのすべてのクライアントプロキシによって生成された 30 個のリクエストのうち、10 個のリクエストが成功していることがわかります。

  2. 次のコマンドを実行して、デスティネーションサービスのレプリカ数を 3 に増やします。

    kubectl scale deployment/circuit-breaker-sample-server --replicas=3

    15 個のリクエストが成功していることがわかります。

  3. 次のコマンドを実行して、デスティネーションサービスのレプリカ数を 4 に増やします。

    kubectl scale deployment/circuit-breaker-sample-server --replicas=3

    デスティネーションサービスのレプリカ数が 3 から 4 に増えた後も、成功したリクエストは 15 個だけです。クライアントプロキシの制限は、デスティネーションサービスのレプリカ数に関係なく、デスティネーションサービス全体に適用されます。したがって、デスティネーションサービスのレプリカ数に関係なく、各クライアントプロキシは最大 5 つの同時リクエストをデスティネーションサービスに送信できます。

関連操作

接続プールのサーキットブレーキングに関連するメトリックを表示する

接続プールのサーキットブレーキングは、デスティネーションホストへの TCP 接続の最大数を制限することで実装されます。サーキットブレーキングが発生すると、一連の関連メトリックが生成されます。これらのメトリックは、サーキットブレーキングが発生したかどうかを判断するのに役立ちます。次の表に、いくつかのメトリックを示します。

メトリック

タイプ

説明

envoy_cluster_circuit_breakers_default_cx_open

Gauge

接続プールに対してサーキットブレーキングがトリガーされたかどうかを示します。値 1 は、サーキットブレーキングがトリガーされたことを示します。値 0 は、サーキットブレーキングがトリガーされていないことを示します。

envoy_cluster_circuit_breakers_default_rq_pending_open

Gauge

準備完了の接続プール接続を待機しているときにキューに入れられるリクエストの数が指定された値を超えたかどうかを示します。リクエストの数が指定された値を超えている場合、値は 1 です。リクエストの数が指定された値を超えていない場合、値は 0 です。

サイドカープロキシの proxyStatsMatcher を構成して、サイドカープロキシがサーキットブレーキングに関連するメトリックを報告できるようにすることができます。その後、Prometheus を使用してメトリックを収集および表示できます。

  1. proxyStatsMatcher を構成して、サイドカープロキシがサーキットブレーキングに関連するメトリックを報告できるようにします。 proxyStatsMatcher を選択した後、[正規表現一致] を選択し、値を .*circuit_breaker.* に設定します。詳細については、「proxyStatsMatcher」をご参照ください。

  2. circuit-breaker-sample-server と circuit-breaker-sample-client のデプロイメントを再デプロイします。詳細については、「ワークロードを再デプロイする」をご参照ください。

  3. 前の手順に従って、接続プールのサーキットブレーキング構成を完了し、リクエストテストを実行します。

  4. 次のコマンドを実行して、circuit-breaker-sample-client サービスの接続プールのサーキットブレーキングに関連するメトリックを表示します。

    kubectl exec -it deploy/circuit-breaker-sample-client -c istio-proxy -- curl localhost:15090/stats/prometheus | grep circuit_breaker | grep circuit-breaker-sample-server

    予期される出力:

    kubectl exec -it deploy/circuit-breaker-sample-client -c istio-proxy -- curl localhost:15090/stats/prometheus | grep circuit_breaker | grep circuit-breaker-sample-server
    envoy_cluster_circuit_breakers_default_cx_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 1
    envoy_cluster_circuit_breakers_default_cx_pool_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_default_remaining_cx{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_default_remaining_cx_pools{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 18446744073709551613
    envoy_cluster_circuit_breakers_default_remaining_pending{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 1
    envoy_cluster_circuit_breakers_default_remaining_retries{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 4294967295
    envoy_cluster_circuit_breakers_default_remaining_rq{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 4294967295
    envoy_cluster_circuit_breakers_default_rq_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_default_rq_pending_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_default_rq_retry_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_high_cx_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_high_cx_pool_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_high_rq_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_high_rq_pending_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0
    envoy_cluster_circuit_breakers_high_rq_retry_open{cluster_name="outbound|9080||circuit-breaker-sample-server.default.svc.cluster.local"} 0

接続プールのサーキットブレーキングのメトリック収集とアラートを構成する

接続プールのサーキットブレーキングに関連するメトリックを構成した後、メトリックを Prometheus に収集するための設定を構成し、主要なメトリックに基づいてアラートルールを構成できます。このようにして、サーキットブレーキングが発生したときにアラートを生成できます。次のセクションでは、接続プールのサーキットブレーキングのメトリック収集とアラートを構成する方法を示します。この例では、Managed Service for Prometheus を使用します。

  1. Managed Service for Prometheus では、データプレーンのクラスタを Alibaba Cloud ASMコンポーネントを管理するセルフマネージド Prometheus インスタンスを使用して ASM インスタンスを監視する コンポーネントに接続するか、コンポーネントを最新バージョンにアップグレードできます。これにより、公開されたサーキットブレーキングに関連するメトリックを Managed Service for Prometheus で収集できます。コンポーネントを ARMS に統合する方法の詳細については、「」をご参照ください。( を参照して、セルフマネージド Prometheus インスタンスが ASM インスタンスのメトリックを収集するように構成している場合は、この手順を実行する必要はありません。)

  2. 接続プールのサーキットブレーキングのアラートルールを作成します。詳細については、「カスタム PromQL ステートメントを使用してアラートルールを作成する」をご参照ください。次の例は、アラートルールを構成するための主要なパラメーターを指定する方法を示しています。他のパラメーターの構成方法の詳細については、上記のドキュメントを参照してください。

パラメーター

説明

カスタム PromQL ステートメント

(sum by(cluster_name, pod_name,namespace) (envoy_cluster_circuit_breakers_default_cx_open)) != 0

この例では、envoy_cluster_circuit_breakers_default_cx_open メトリックをクエリして、現在のクラスタの接続プールでサーキットブレーキングが発生しているかどうかを判断します。アップストリームサービスのホスト名とメトリックを報告するポッドの名前に基づいて、サーキットブレーキングが発生した場所を特定できます。

アラートメッセージ

接続プールでサーキットブレーキングが発生しました。サイドカープロキシによって確立された TCP 接続の数が上限に達しました。名前空間:{{$labels.namespace}}、接続プールでサーキットブレーキングが発生したポッド:{{$labels.pod_name}}、アップストリームサービスに関する情報:{{ $labels.cluster_name }}

この例のアラート情報は、接続プールでサーキットブレーキングが発生したポッド、ポッドが接続するアップストリームサービス、およびポッドが属する名前空間を示しています。

接続プール構成の制約

次の表に、クライアントとデスティネーションサービスの connectionPool フィールドの構成の制約を示します。

ロール

説明

クライアント

各クライアントプロキシは制限を個別に実装します。リクエスト数の制限が 100 の場合、各クライアントプロキシはローカルスロットリングが適用される前に 100 の未処理リクエストを持つことができます。 N 個のクライアントがデスティネーションサービスを呼び出す場合、サポートされる未処理リクエストの最大数は 100 と N の積です。

クライアントプロキシの制限は、デスティネーションサービスの単一のレプリカではなく、デスティネーションサービス全体に適用されます。デスティネーションサービスが 200 のアクティブなポッドで実行されている場合でも、最大 100 のリクエストが許可されます。

デスティネーションサービス

制限は各デスティネーションサービスプロキシに適用されます。サービスが 50 のアクティブなポッドで実行されている場合、各ポッドは、スロットリングがトリガーされてレスポンスコード 503 が返される前に、クライアントプロキシから送信された最大 100 の未処理リクエストを持つことができます。