Envoy. 1. Introduktion

Velkommen! Denne kort artikel besvarer spørgsmålene: "hvad er envoy?", "hvad er det til?" og "hvordan kommer man i gang?".

Hvad er det

Envoy er en L4-L7 load balancer skrevet i C++, designet til høj ydeevne og tilgængelighed. På den ene side kan det ses som en slags analog til nginx og haproxy, der kan måle sig med dem hvad angår ydeevne. På den anden side er det mere rettet mod mikrotjenestearkitektur og har funktionalitet der ikke er ringere end load balancere skrevet i java og go, som zuul eller traefik.

Sammenligningstabel for haproxy/nginx/envoy; den hævder ikke at være absolut sand, men giver et overordnet billede.

nginx
haproxy
envoy
traefik

stjerner på github
11.2k/mirror
1.1k/mirror
12.4k
27.6k

skrevet i
C
C
C++
go

API
nej
kun socket/push
dataplane/pull
pull

aktiv sundhedstjek
nej
ja
ja
ja

Open tracing
ekstern plugin
nej
ja
ja

JWT
ekstern plugin
nej
ja
nej

.sql
Lua/C
Lua/C
Lua/C++
nej

Hvorfor

Det er et ungt projekt, der mangler mange ting, og nogle er i tidlig alfa. Men envoy, blandt andet takket være dets ungdom, udvikler det sig hurtigt og har allerede mange interessante funktioner: dynamisk konfiguration, mange færdige filtre, og et enkelt interface til at skrive sine egne filtre.
Dette medfører anvendelsesområder, men for at begynde, her er 2 antipatterns:

  • At servere statisk indhold.

Punktet er, at der i øjeblikket ikke er envoy understøttelse af caching. Folkene hos google forsøger at rette dette. Ideen var at implementere i en enkelt løsning alt det komplekse (zoo af headers) i overensstemmelse med RFC, og for specifikke implementeringer at lave et interface. Men indtil videre er det ikke engang alfa, arkitekturen er under diskussion, envoy det er åbent (mens jeg skrev artiklen blev PR mergeret, men dette punkt er stadig aktuelt). PR Indtil da anbefales det at bruge nginx til statisk indhold.

Statisk konfiguration.

  • Den kan bruges, men

den blev ikke skabt til dette. Mulighederne i den statiske konfiguration vil ikke blive afsløret. Der er mange aspekter: envoy Når du redigerer konfigurationen i yaml, vil du lave fejl, bande udviklerne for overflødighed, og tænke at konfigurationer fra nginx/haproxy, selvom de er mindre strukturerede, er mere præcise. Det er essensen. Konfigurationen for Nginx og Haproxy blev designet til manuel redigering, mens

for Envoy blev lavet til generering fra kode. Hele konfigurationen er beskrevet i envoy , hvilket gør det langt sværere at lave fejl ved at generere den fra proto-filer. protobufCanary-scenarier, b/g-udrulning og meget andet implementeres kun korrekt i dynamisk konfiguration. Jeg siger ikke, at det ikke kan gøres i statisk, vi gør alle disse ting. Men for at gøre det, skal man omgive sig med løsninger, i enhver load balancer, i

inklusive. envoy Opgaver, hvor Envoy er uundgåelig:

Задачи в которых Envoy незаменим:

  • Lastbalancering af trafik i komplekse og dynamiske systemer. Dette inkluderer service mesh, men det er ikke kun det.
  • Behovet for funktionalitet i distribueret tracing, kompleks autorisation eller andet, som findes i envoy out-of-the-box eller nemt implementeres, mens nginx/haproxy kræver lua og tvivlsomme plugins.

Begge dele skal sikre høj ydeevne, hvis det er nødvendigt.

Hvordan fungerer det

Envoy distribueres kun som docker-billede i binære filer. Billedet har allerede et eksempel på statisk konfiguration. Men det er kun interessant for at forstå strukturen.

envoy.yaml statisk konfiguration

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
    # Kommentar på den følgende linje for at teste på v6-netværk
    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

Dynamisk konfiguration

Hvilket problem prøver vi at løse? Man kan ikke bare genstarte konfigurationen af balanceringssystemet under belastning, der vil opstå "små" problemer:

  • Validering af konfiguration.

Konfigurationen kan være stor, meget stor, og hvis vi genstarter hele konfigurationen på én gang, øges chancerne for fejl.

  • Langvarige forbindelser.

Ved initialisering af en ny lytter skal man sørge for de forbindelser, der kører på den gamle, og hvis ændringerne sker ofte og der er langvarige forbindelser, må man finde et kompromis. Hej, kubernetes ingress på nginx.

  • Aktive health checks.

Hvis vi har aktive health checks, skal vi genkontrollere dem alle på den nye konfiguration, før vi sender trafik. Hvis der er mange upstreams, tager det tid. Hej, haproxy.

Hvordan det løses i envoy, ved dynamisk at indlæse konfigurationen, ved hjælp af pool-modellen, kan den opdeles i separate dele og den del, der ikke er ændret, behøver ikke at blive geninitialiseret. For eksempel er en lytter, som er dyr at geninitialisere, og den ændres sjældent.

Konfiguration envoy (fra den ovenstående fil) har følgende enheder:

  • listener — en lytter, der hænger på en bestemt ip/port
  • virtual host — en virtuel vært efter domænenavn
  • rute — balancing rule
  • cluster — en gruppe upstreams med balancing-parametre
  • endpoint — adressen til upstream-instansen

Hver af disse enheder plus nogle andre kan udfyldes dynamisk; i konfigurationen angives adressen til tjenesten, hvorfra konfigurationen vil blive hentet. Tjenesten kan være REST eller gRPC, det er at foretrække at bruge gRPC.

Tjenesterne kaldes henholdsvis: LDS, VHDS, RDS, CDS og EDS. Man kan kombinere statisk og dynamisk konfiguration, med begrænsningen at den dynamiske ressource ikke kan angives i den statiske.

Til de fleste opgaver er det tilstrækkeligt at implementere de sidste tre tjenester, de kaldes ADS (Aggregated Discovery Service), for java og go har en klar implementation af gRPC dataplane, hvor det kun er nødvendigt at udfylde objekterne fra sin egen kilde.

Konfigurationen får følgende udseende:

envoy.yaml dynamisk konfiguration

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

Ved opstart envoy med denne konfiguration vil den oprette forbindelse til control-plane og forsøge at anmode om konfigurationen af RDS, CDS og EDS. Hvordan interaktionen finder sted er beskrevet her.

Kort sagt, envoy den sender en anmodning, med angivelse af den type ressource, versionen og nodens parametre. Som svar modtager den ressourcen og versionen; hvis versionen på control-plane ikke er ændret, svarer den ikke.
Der er 4 interaktionsmuligheder:

  • En gRPC strøm for alle typer ressourcer, der sender den komplette tilstand af ressourcen.
  • Separate streams, full state.
  • Single stream, incremental state.
  • Separate streams, incremental state.

Incremental xDS reduces traffic between the control plane and envoy, which is relevant for large configurations. However, it complicates interactions, as the request transmits a list of resources for subscription and unsubscription.

In our example, ADS is used — a single stream for RDS, CDS, EDS, and in non-incremental mode. To enable incremental mode, you need to specify api_type: DELTA_GRPC

Since the request includes node parameters, we can send different resources to different instances on the control plane envoy, making it convenient for building a service mesh.

Warmup

På envoy at startup or when receiving a new configuration from the control plane, the resource warmup process starts. It is split into listener warmup and cluster warmup. The first is initiated during changes in RDS/LDS, and the second during CDS/EDS. This means that if only upstreams change, the listener is not recreated.

During the warmup process, dependent resources are expected from the control plane within a timeout. If the timeout expires, the initialization will not be successful, and the new listener will not start listening on the port.
Initialization order: EDS, CDS, active health check, RDS, LDS. With active health checks enabled, traffic will only go to the upstream after one successful health check.

If the listener was recreated, the old one transitions to the DRAIN state and will be removed after all connections are closed or the timeout expires --drain-time-s, by default 10 minutes.

Fortsættes.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster