使者。 1. はじめに

こんにちは! これは、「envoy とは何ですか?」「なぜ必要ですか?」という質問に答える短い記事です。 そして「どこから始めればいいのか?」

これは何ですか

Envoy は、C++ で書かれた L4 ~ L7 バランサーであり、高いパフォーマンスと可用性を重視しています。 一方で、これはある意味 nginx や haproxy に似ており、パフォーマンスにおいてはそれらに匹敵します。 一方で、マイクロサービス アーキテクチャをより指向しており、Java や zuul や traefik などの Go バランサーと同等の機能を備えています。

haproxy/nginx/envoy の比較表。絶対的な真実であるとは主張しませんが、全体像を示します。

nginx
ハプロキシ
特使
トレフィク

github のスター
11.2k/ミラー
1.1k/ミラー
12.4k
27.6k

で書かれている
C
C
C + +
go

API
ノー
ソケットのみ/プッシュ
データプレーン/プル
プル

アクティブなヘルスチェック
ノー
はい
はい
はい

オープントレース
外部プラグイン
ノー
はい
はい

JWT
外部プラグイン
ノー
はい
ノー

拡張
ルア/C
ルア/C
ルア/C++
ノー

何のために

これは若いプロジェクトであり、不足しているものがたくさんあり、初期のアルファ版のものも含まれています。 しかし 特使は、その若さもあって急速に開発されており、動的構成、多くの既製フィルター、独自のフィルターを作成するためのシンプルなインターフェイスなど、すでに多くの興味深い機能を備えています。
これに応用分野が続きますが、最初に 2 つのアンチパターンがあります。

  • 静的な反動。

事実は、現時点では 特使 キャッシュのサポートはありません。 Googleの人たちはこれを試しています 修正する。 アイデアは XNUMX 回実行されます 特使 RFC 準拠のすべての微妙な点 (zoo ヘッダー) に対応し、特定の実装のためにインターフェイスを作成します。 しかし、現時点ではアルファ版ですらなく、アーキテクチャは議論中です。 PR open (PR 記事を書いているときに PR がフリーズしましたが、この点は依然として重要です)。

現時点では、静的データには nginx を使用します。

  • 静的構成。

使ってもいいですが、 特使 それはそのために作られたものではありません。 静的構成の機能は公開されません。 多くの瞬間があります:

yaml で設定を編集するとき、開発者が冗長であると叱責し、nginx/haproxy 設定は構造化されていないものの、より簡潔であると考えるのは間違いです。 それがポイントです。 Nginx と Haproxy の構成は手動で編集するために作成されており、 特使 コードから生成する場合。 全体の構成は次のとおりです。 プロトブフ、proto ファイルから生成する方が間違いが起こりにくいです。

Canary、b/g 展開シナリオなどは、通常、動的構成でのみ実装されます。 これを静的に行うことができないと言っているのではなく、誰もがそれを行っています。 ただし、このためには、バランサーのいずれかで松葉杖を着用する必要があります。 特使 含む

Envoy が不可欠なタスク:

  • 複雑で動的なシステムにおけるトラフィックのバランシング。 これにはサービス メッシュが含まれますが、必ずしもそれだけではありません。
  • 分散トレース機能、複雑な認証、またはで利用可能なその他の機能の必要性。 特使 すぐに使用できる、または便利に実装されていますが、nginx/haproxy では、lua と疑わしいプラグインに囲まれる必要があります。

必要に応じて、両方とも高いパフォーマンスを提供します。

これはどう動かすのですか

Envoy は、バイナリで Docker イメージとしてのみ配布されます。 イメージには、静的構成の例がすでに含まれています。 しかし、私たちは構造を理解するためにのみそれに興味を持っています。

envoy.yaml 静的構成

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite: www.google.com
                  cluster: service_google
          http_filters:
          - name: envoy.router
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
        sni: www.google.com

動的構成

私たちはどのような問題の解決策を探しているのでしょうか? 負荷がかかった状態でロード バランサー構成を単にリロードすることはできません。「小さな」問題が発生します。

  • 構成の検証。

構成は大きくなる場合もあり、非常に大きくなる場合もあります。すべてを一度にオーバーロードすると、どこかでエラーが発生する可能性が高くなります。

  • 長く続く接続。

新しいリスナーを初期化するときは、古いリスナーで実行されている接続に注意する必要があります。変更が頻繁に発生し、接続の存続期間が長い場合は、妥協点を探す必要があります。 こんにちは、nginx での kubernetes ingress です。

  • アクティブなヘルスチェック。

アクティブなヘルスチェックがある場合は、トラフィックを送信する前に、新しい構成ですべてのヘルスチェックを再確認する必要があります。 アップストリームが多い場合、これには時間がかかります。 こんにちは、ハプロキシです。

これはどのように解決されますか 特使プール モデルに従って構成を動的にロードすることで、構成を個別の部分に分割し、変更されていない部分を再初期化する必要がなくなります。 たとえば、リスナーは再初期化にコストがかかり、ほとんど変更されません。

設定 特使 (上記のファイルより) には次のエンティティがあります。

  • リスナー — リスナーが特定の IP/ポートにハングアップしている
  • 仮想ホスト - ドメイン名による仮想ホスト
  • route - バランスルール
  • — バランスパラメータを備えたアップストリームのグループ
  • 終点 — 上流インスタンスのアドレス

これらの各エンティティとその他のエンティティは動的に入力できます。そのために、構成では、構成の受信元となるサービスのアドレスを指定します。 サービスには REST または gRPC を使用できますが、gRPC をお勧めします。

サービスにはそれぞれ、LDS、VHDS、RDS、CDS、および EDS という名前が付けられます。 静的構成と動的構成を組み合わせることができますが、静的リソースでは動的リソースを指定できないという制限があります。

ほとんどのタスクでは、最後の XNUMX つのサービスを実装するだけで十分です。これらは ADS (Aggregated Discovery Service) と呼ばれます。 ジャワ そして、gRPC データプレーンの既製の実装が用意されており、ソースからオブジェクトを入力するだけで済みます。

構成は次の形式になります。

envoy.yaml の動的構成

dynamic_resources:
  ads_config:
    api_type: GRPC
    grpc_services:
      envoy_grpc:
        cluster_name: xds_clr
  cds_config:
    ads: {}
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          rds:
            route_config_name: local_route
            config_source:
              ads: {}
          http_filters:
          - name: envoy.router
  clusters:
  - name: xds_clr
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: xds_clr
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: xds
                port_value: 6565

実行時 特使 この設定を使用すると、コントロール プレーンに接続し、RDS、CDS、および EDS の設定を要求しようとします。 インタラクションプロセスがどのように発生するかについて説明します ここで.

要するに、 特使 リクエストされているリソースのタイプ、ノードのバージョンおよびパラメータを示すリクエストを送信します。 応答として、リソースとバージョンを受け取りますが、コントロール プレーン上のバージョンが変更されていない場合は応答しません。
4 つの対話オプションがあります。

  • すべてのタイプのリソースに対して XNUMX つの gRPC ストリームで、リソースの完全なステータスが送信されます。
  • 別々のストリーム、完全な状態。
  • XNUMX つのストリーム、インクリメンタル状態。
  • 個別のストリーム、増分状態。

インクリメンタル xDS を使用すると、コントロール プレーンとコントロール プレーン間のトラフィックを削減できます。 特使、これは大規模な構成に関連します。 ただし、リクエストには購読解除と購読のためのリソースのリストが含まれているため、やり取りが複雑になります。

この例では、ADS (RDS、CDS、EDS、および非インクリメンタル モードに XNUMX つのストリーム) を使用します。 インクリメンタル モードを有効にするには、次のように指定する必要があります api_type: DELTA_GRPC

リクエストにはノードパラメータが含まれているため、異なるインスタンスの異なるリソースをコントロールプレーンに送信できます。 特使、これはサービス メッシュを構築するのに便利です。

準備し始める

На 特使 起動時、またはコントロール プレーンから新しい設定を受信したときに、リソースのウォームアップ プロセスが開始されます。 リスナーのウォームアップとクラスターのウォームアップに分かれています。 XNUMX つ目は RDS/LDS に変更があったときに起動され、XNUMX つ目は CDS/EDS に変更があったときに起動されます。 これは、アップストリームのみが変更された場合、リスナーは再作成されないことを意味します。

ウォームアップ プロセス中、タイムアウト中にコントロール プレーンからの依存リソースが期待されます。 タイムアウトが発生すると、初期化は成功せず、新しいリスナーはポートでのリッスンを開始しません。
初期化順序: EDS、CDS、アクティブ ヘルス チェック、RDS、LDS。 アクティブなヘルス チェックが有効になっている場合、トラフィックは XNUMX 回のヘルス チェックが成功した場合にのみアップストリームに送信されます。

リスナーが再作成された場合、古いリスナーは DRAIN 状態になり、すべての接続が閉じられるかタイムアウトが経過すると削除されます。 --drain-time-s、デフォルトは 10 分です。

継続するために。

出所: habr.com

コメントを追加します