Sändebud. 1. Introduktion

Hälsningar! Det här är en kort artikel som svarar på frågorna: "vad är sändebud?", "varför behövs det?" och "var ska man börja?".

Vad är det här

Envoy är en L4-L7-balanserare skriven i C++, fokuserad på hög prestanda och tillgänglighet. Å ena sidan är detta på något sätt en analog av nginx och haproxy, jämförbar i prestanda med dem. Å andra sidan är den mer orienterad mot mikrotjänstarkitektur och har funktionalitet inte sämre än java och go balanserare, såsom zuul eller traefik.

Jämförelsetabell för haproxy/nginx/envoy, den gör inte anspråk på att vara den absoluta sanningen, men ger en allmän bild.

nginx
haproxy
skickat
traefik

stjärnor på github
11.2k/spegel
1.1k/spegel
12.4k
27.6k

skrivet i
C
C
C + +
go

API
ingen
endast uttag/tryck
dataplan/drag
dra

aktiv hälsokontroll
ingen
ja
ja
ja

Öppna spårning
extern plugin
ingen
ja
ja

J.W.T.
extern plugin
ingen
ja
ingen

förlängning
Lua/C
Lua/C
Lua/C++
ingen

För vad

Det här är ett ungt projekt, det är mycket som saknas, några i tidig alfa. Men skickat, även på grund av sin ungdom, utvecklas snabbt och har redan många intressanta funktioner: dynamisk konfiguration, många färdiga filter, ett enkelt gränssnitt för att skriva dina egna filter.
Användningsområden följer av detta, men först finns det 2 antimönster:

  • Statisk rekyl.

Faktum är att för tillfället i skickat inget cachingstöd. Google-killarna försöker detta att fixa. Idén kommer att genomföras en gång i tiden skickat alla subtiliteter (zoo headers) av RFC-efterlevnad, och för specifika implementeringar skapa ett gränssnitt. Men för tillfället är det inte ens alfa, arkitekturen är under diskussion, PR öppen (medan jag skrev PR-artikeln frös PR, men denna punkt är fortfarande relevant).

För nu, använd nginx för statik.

  • Statisk konfiguration.

Du kan använda det, men skickat Det var inte det den skapades för. Funktioner i en statisk konfiguration kommer inte att exponeras. Det finns många ögonblick:

När du redigerar konfigurationen i yaml kommer du att missta dig, skälla ut utvecklarna för detaljerad information och tro att nginx/haproxy-konfigurationerna, även om de är mindre strukturerade, är mer koncisa. Det är poängen. Konfigurationen av Nginx och Haproxy skapades för redigering för hand, och skickat för generering från kod. Hela konfigurationen beskrivs i protobuf, att generera den från protofiler är mycket svårare att göra ett misstag.

Canary, b/g-distributionsscenarier och mycket mer implementeras normalt endast i en dynamisk konfiguration. Jag säger inte att detta inte kan göras statiskt, vi gör det alla. Men för detta måste du sätta på kryckor, i någon av balanserna, in skickat Inklusive.

Uppgifter som envoy är oumbärlig för:

  • Trafikbalansering i komplexa och dynamiska system. Detta inkluderar servicenätet, men det är inte nödvändigtvis det enda.
  • Behovet av distribuerad spårningsfunktionalitet, komplex auktorisering eller annan funktionalitet som är tillgänglig i skickat out of the box eller praktiskt implementerad, men i nginx/haproxy måste du vara omgiven av lua och tvivelaktiga plugins.

Båda ger vid behov hög prestanda.

Hur fungerar den här

Envoy distribueras endast i binärer som en docker-bild. Bilden innehåller redan ett exempel på en statisk konfiguration. Men vi är bara intresserade av det för att förstå 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
    # 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

Dynamisk konfiguration

Vilket problem letar vi efter en lösning på? Du kan inte bara ladda om lastbalanserarens konfiguration under belastning; "små" problem kommer att uppstå:

  • Konfigurationsvalidering.

Konfigurationen kan vara stor, den kan vara väldigt stor, om vi överbelastas allt på en gång ökar chanserna för ett fel någonstans.

  • Långlivade förbindelser.

När du initierar en ny lyssnare måste du ta hand om anslutningarna som körs på den gamla, om ändringar sker ofta och det finns långlivade anslutningar måste du leta efter en kompromiss. Hej, kubernetes ingress på nginx.

  • Aktiva hälsokontroller.

Om vi ​​har aktiva hälsokontroller måste vi dubbelkolla dem alla i den nya konfigurationen innan vi skickar trafik. Är det mycket uppströms tar detta tid. Hej haproxy.

Hur löses detta i skickatGenom att ladda konfigurationen dynamiskt, enligt poolmodellen, kan du dela upp den i separata delar och inte återinitiera den del som inte har ändrats. Till exempel en lyssnare, som är dyr att återinitiera och sällan ändras.

konfiguration skickat (från filen ovan) har följande enheter:

  • lyssnare — lyssnare som hänger på en specifik ip/port
  • virtuell värd - virtuell värd efter domännamn
  • rutt - balanseringsregel
  • kluster — en grupp uppströms med balanseringsparametrar
  • slutpunkt — Uppströmsinstansadress

Var och en av dessa enheter plus några andra kan fyllas i dynamiskt; för detta anger konfigurationen adressen till tjänsten varifrån konfigurationen kommer att tas emot. Tjänsten kan vara REST eller gRPC, gRPC är att föredra.

Tjänsterna heter respektive: LDS, VHDS, RDS, CDS och EDS. Du kan kombinera statisk och dynamisk konfiguration, med begränsningen att en dynamisk resurs inte kan anges i en statisk.

För de flesta uppgifter räcker det att implementera de tre sista tjänsterna, de kallas ADS (Aggregated Discovery Service), för Java och gå dit finns en färdig implementering av gRPC-dataplanet där du bara behöver fylla i objekten från din källa.

Konfigurationen har följande form:

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

Vid start skickat med denna konfiguration kommer den att ansluta till kontrollplanet och försöka begära RDS-, CDS- och EDS-konfigurationen. Hur interaktionsprocessen går till beskrivs här.

Kortfattat, skickat skickar en begäran som indikerar typen av resurs som efterfrågas, versionen och parametrarna för noden. Som svar får den en resurs och en version, om versionen på kontrollplanet inte har ändrats svarar den inte.
Det finns 4 interaktionsalternativ:

  • En gRPC-ström för alla typer av resurser, hela statusen för resursen skickas.
  • Separata bäckar, fullt skick.
  • En ström, inkrementellt tillstånd.
  • Separata strömmar, inkrementellt tillstånd.

Inkrementell xDS låter dig minska trafiken mellan kontrollplanet och skickat, detta är relevant för stora konfigurationer. Men det komplicerar interaktionen, begäran innehåller en lista med resurser för att av- och prenumerera.

Vårt exempel använder ADS - en ström för RDS, CDS, EDS och icke-inkrementellt läge. För att aktivera inkrementellt läge måste du ange api_type: DELTA_GRPC

Eftersom begäran innehåller nodparametrar kan vi skicka olika resurser till kontrollplanet för olika instanser skickat, detta är praktiskt för att bygga ett servicenät.

Uppvärmning

skickat vid uppstart eller när en ny konfiguration tas emot från kontrollplanet, startas resursuppvärmningsprocessen. Den är uppdelad i lyssnaruppvärmning och klusteruppvärmning. Den första lanseras när det finns ändringar i RDS/LDS, den andra när CDS/EDS. Det betyder att om bara uppströms ändras så återskapas inte lyssnaren.

Under uppvärmningsprocessen förväntas beroende resurser från kontrollplanet under timeout. Om timeout inträffar kommer initieringen inte att lyckas och den nya lyssnaren kommer inte att börja lyssna på porten.
Initieringsordning: EDS, CDS, aktiv hälsokontroll, RDS, LDS. Med aktiva hälsokontroller aktiverade kommer trafiken att gå uppströms först efter en lyckad hälsokontroll.

Om lyssnaren återskapades går den gamla till DRAIN-tillståndet och kommer att raderas efter att alla anslutningar stängts eller timeouten löper ut --drain-time-s, standard 10 minuter.

Att fortsätta

Källa: will.com

Lägg en kommentar