Trimis. 1. Introducere

Salutari! Acesta este un articol scurt care răspunde la întrebările: „ce este trimis?”, „de ce este nevoie?” și „de unde să încep?”.

Ce este asta?

Envoy este un echilibrator L4-L7 scris în C++, axat pe performanță ridicată și disponibilitate. Pe de o parte, acesta este într-un fel un analog al nginx și haproxy, comparabil ca performanță cu acestea. Pe de altă parte, este mai orientat către arhitectura de microservicii și are o funcționalitate nu mai proastă decât java și balansoarele go, cum ar fi zuul sau traefik.

Tabel de comparație al haproxy/nginx/envoy, nu pretinde a fi adevărul absolut, dar oferă o imagine generală.

Nginx
haproxy
trimis
traefik

stele pe github
11.2k/oglindă
1.1k/oglindă
12.4k
27.6k

scris in
C
C
C ++
go

API
nu
numai priză/împingere
dataplane/pull
trage

controlul de sănătate activ
nu
da
da
da

Deschideți urmărirea
plugin extern
nu
da
da

J.W.T.
plugin extern
nu
da
nu

extensie
Lua/C
Lua/C
Lua/C++
nu

Pentru ce

Acesta este un proiect tânăr, lipsesc multe lucruri, unele în alfa timpurie. Dar trimis, tot datorită tinereții sale, se dezvoltă rapid și are deja multe caracteristici interesante: configurație dinamică, multe filtre gata făcute, o interfață simplă pentru a scrie propriile filtre.
De aici rezultă domenii de aplicare, dar mai întâi există 2 antimodeluri:

  • Recul static.

Cert este că în acest moment în trimis fără suport pentru cache. Băieții de la Google încearcă asta pentru a repara. Ideea va fi implementată odată trimis toate subtilitățile (antetele zoo) ale conformității RFC, iar pentru implementări specifice creați o interfață. Dar deocamdată nu este nici măcar alfa, arhitectura este în discuție, PR deschis (în timp ce scriam articolul de PR, PR a înghețat, dar acest punct este încă relevant).

Pentru moment, utilizați nginx pentru statice.

  • Configurație statică.

Îl poți folosi, dar trimis Nu pentru asta a fost creat. Caracteristicile într-o configurație statică nu vor fi expuse. Sunt multe momente:

Când editați configurația în yaml, vă veți înșela, certați dezvoltatorii pentru verbozitate și credeți că configurațiile nginx/haproxy, deși mai puțin structurate, sunt mai concise. Acesta este ideea. Configurația Nginx și Haproxy a fost creată pentru editare manual și trimis pentru generare din cod. Întreaga configurație este descrisă în protobuf, generarea acestuia din fișiere proto este mult mai dificil de făcut o greșeală.

Scenariile de implementare Canary, b/g și multe altele sunt în mod normal implementate doar într-o configurație dinamică. Nu spun că acest lucru nu se poate face static, o facem cu toții. Dar pentru asta trebuie să puneți cârje, în oricare dintre balansoare, în trimis inclusiv.

Sarcini pentru care Envoy este indispensabil:

  • Echilibrarea traficului în sisteme complexe și dinamice. Aceasta include rețeaua de serviciu, dar nu este neapărat singura.
  • Nevoia de funcționalitate de urmărire distribuită, autorizare complexă sau alte funcționalități care sunt disponibile în trimis ieșit din cutie sau implementat convenabil, dar în nginx/haproxy trebuie să fii înconjurat de plugin-uri lua și dubioase.

Ambele, dacă este necesar, oferă performanțe ridicate.

Cum funcționează

Envoy este distribuit în binare doar ca imagine docker. Imaginea conține deja un exemplu de configurație statică. Dar ne interesează doar pentru înțelegerea structurii.

configurație statică 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

Configurație dinamică

La ce problemă căutăm o soluție? Nu puteți să reîncărcați configurația echilibrului de încărcare sub încărcare; vor apărea probleme „mici”:

  • Validarea configurației.

Configurația poate fi mare, poate fi foarte mare, dacă o supraîncărcăm pe toate odată, șansele unei erori undeva cresc.

  • Legături de lungă durată.

Când inițializați un nou ascultător, trebuie să aveți grijă de conexiunile care rulează pe cel vechi; dacă schimbările apar frecvent și există conexiuni de lungă durată, va trebui să căutați un compromis. Bună ziua, intrarea kubernetes pe nginx.

  • Controale active de sănătate.

Dacă avem verificări de sănătate active, trebuie să le verificăm pe toate în noua configurație înainte de a trimite trafic. Dacă există o mulțime de amonte, acest lucru necesită timp. Bună, haproxy.

Cum se rezolvă asta în trimisÎncărcând configurația în mod dinamic, în funcție de modelul piscinei, o puteți împărți în părți separate și nu reinițializați partea care nu s-a schimbat. De exemplu, un ascultător, care este scump de reinițializat și se schimbă rar.

configurație trimis (din dosarul de mai sus) are următoarele entități:

  • ascultător — ascultător agățat de un anumit ip/port
  • gazdă virtuală - gazdă virtuală după nume de domeniu
  • traseu - regula de echilibrare
  • grup — un grup de amonte cu parametri de echilibrare
  • punct final — adresa instanței din amonte

Fiecare dintre aceste entități plus unele altele pot fi completate dinamic; pentru aceasta, configurația specifică adresa serviciului de unde va fi primită configurația. Serviciul poate fi REST sau gRPC, este de preferat gRPC.

Serviciile sunt denumite respectiv: LDS, VHDS, RDS, CDS și EDS. Puteți combina configurația statică și dinamică, cu limitarea că o resursă dinamică nu poate fi specificată într-una statică.

Pentru majoritatea sarcinilor, este suficient să implementați ultimele trei servicii, acestea se numesc ADS (Aggregated Discovery Service), pentru Java și mergeți acolo este o implementare gata făcută a planului de date gRPC în care trebuie doar să completați obiectele din sursa dvs.

Configurația ia următoarea formă:

configurație dinamică 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

La pornire trimis cu această configurație, se va conecta la planul de control și va încerca să solicite configurația RDS, CDS și EDS. Este descris modul în care are loc procesul de interacțiune aici.

Pe scurt, trimis trimite o cerere indicând tipul de resursă solicitată, versiunea și parametrii nodului. Ca răspuns, primește o resursă și o versiune; dacă versiunea de pe planul de control nu s-a schimbat, nu răspunde.
Există 4 opțiuni de interacțiune:

  • Un flux gRPC pentru toate tipurile de resurse, se trimite starea completă a resursei.
  • Fluxuri separate, stare completă.
  • Un singur flux, stare incrementală.
  • Fluxuri separate, stare incrementală.

xDS incremental vă permite să reduceți traficul între planul de control și trimis, acest lucru este relevant pentru configurații mari. Dar complică interacțiunea; cererea conține o listă de resurse pentru dezabonare și abonare.

Exemplul nostru folosește ADS - un flux pentru RDS, CDS, EDS și modul non-incremental. Pentru a activa modul incremental, trebuie să specificați api_type: DELTA_GRPC

Deoarece cererea conține parametrii nodului, putem trimite diferite resurse către planul de control pentru diferite instanțe trimis, acest lucru este convenabil pentru construirea unei rețele de serviciu.

Încălzire

Pe trimis la pornire sau la primirea unei noi configurații din planul de control, procesul de încălzire a resurselor este lansat. Este împărțit în încălzire ascultător și încălzire cluster. Primul este lansat când există modificări în RDS/LDS, al doilea când CDS/EDS. Aceasta înseamnă că, dacă se schimbă doar în amonte, ascultătorul nu este recreat.

În timpul procesului de încălzire, sunt așteptate resurse dependente de la planul de control în timpul expirării. Dacă are loc expirarea, inițializarea nu va avea succes și noul ascultător nu va începe să asculte pe port.
Ordin de inițializare: EDS, CDS, verificare de sănătate activă, RDS, LDS. Cu verificările active de sănătate activate, traficul va merge în amonte numai după o verificare de sănătate reușită.

Dacă ascultătorul a fost recreat, cel vechi intră în starea DRAIN și va fi șters după ce toate conexiunile sunt închise sau expiră timpul de expirare --drain-time-s, implicit 10 minute.

Pentru a fi continuat.

Sursa: www.habr.com

Adauga un comentariu