Hallo! Dit is een kort artikel dat antwoord geeft op de vragen: "Wat is envoy?", "Waarvoor dient het?" en "Waar te beginnen?".
Wat is het
Envoy is een L4-L7 load balancer geschreven in C++, gericht op hoge prestaties en beschikbaarheid. Enerzijds is het in zekere zin een alternatief voor nginx en haproxy, qua prestaties vergelijkbaar met hen. Anderzijds is het meer gericht op microservices-architectuur en heeft het functies die niet onderdoen voor load balancers in java en go, zoals zuul of traefik.
Vergelijkingstabel haproxy/nginx/envoy, deze pretendeert niet de absolute waarheid te zijn, maar geeft een algemeen beeld.
met alles wat daarin al aanwezig is, en de inhoud van de map
haproxy
envoy
traefik
sterren op github
11.2k/mirror
1.1k/mirror
12.4k
27.6k
geschreven in
C
C
C++
go
API
nee
socket only/push
dataplane/pull
pull
actieve healthcheck
nee
ja
ja
ja
Open tracing
externe plugin
nee
ja
ja
JWT
externe plugin
nee
ja
nee
Uitbreiding
Lua/C
Lua/C
Lua/C++
nee
Waarom
Dit is een jong project, er is veel dat ontbreekt, sommige dingen zijn in vroege alpha. Maar envoy, mede dankzij de jongheid, ontwikkelt het zich snel en heeft het al veel interessante mogelijkheden: dynamische configuratie, veel kant-en-klare filters, een eenvoudige interface voor het schrijven van je eigen filters.
Hieruit volgen toepassingsgebieden, maar voor nu 2 antipatterns:
- Statistische afhandeling.
Het punt is dat er op dit moment in de envoy geen ondersteuning voor caching is. De jongens van google proberen dit . Het idee is om een keer in op envoy alle nuances (dierenpark van headers) in overeenstemming met RFC te implementeren, en voor specifieke implementaties een interface te maken. Maar momenteel is dit zelfs niet alpha, de architectuur is nog in discussie, open (terwijl ik dit artikel schreef, werd de PR samengevoegd, maar dit punt is nog steeds actueel).
Gebruik voor statische bestanden voorlopig nginx.
- Statische configuratie.
Je kunt het gebruiken, maar envoy is niet daarvoor gemaakt. Mogelijkheden in statische configuratie zullen niet tot hun recht komen. Er zijn veel aspecten:
Als je de configuratie in yaml bewerkt, zul je fouten maken, ontwikkelaars afsnauwen omwille van de bombast en denken dat de configuraties van nginx/haproxy, zij het minder gestructureerd, maar beknopter zijn. Dat is waar het om draait. De configuratie van Nginx en Haproxy is gemaakt voor handmatige bewerking, terwijl de envoy bedoeld is voor generatie vanuit code. Alle configuratie is beschreven in , het is veel moeilijker om fouten te maken door ze uit proto-bestanden te genereren.
Canary, b/g deployments en veel meer, worden alleen goed gerealiseerd in dynamische configuratie. Ik zeg niet dat dit niet kan in statische configuratie, we doen het allemaal. Maar daarvoor moet je omwegen gebruiken, in elke load balancer, in envoy eveneens.
Taken waarin Envoy onmisbaar is:
- Verkeersbalancering in complexe en dynamische systemen. Dit omvat service mesh, maar het is niet alleen daarmee beperkt.
- De noodzaak van functionaliteit voor gedistribueerde tracing, complexe autorisatie of iets anders dat beschikbaar is in envoy de standaardversie of gemakkelijk kan worden geïmplementeerd, terwijl het bij nginx/haproxy nodig is om lua en twijfelachtige plug-ins te gebruiken.
Beide moeten, indien nodig, een hoge prestaties garanderen.
Hoe het werkt
Envoy wordt uitsluitend als docker-image in binaire vorm verspreid. In de afbeelding is er al een voorbeeld van statische configuratie aanwezig. Maar we zijn alleen geïnteresseerd in het om de structuur te begrijpen.
envoy.yaml statische configuratie
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
# Zet de volgende regel uit om te testen op v6-netwerken
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.comDynamische configuratie
Welke problemen proberen we op te lossen? Je kunt de configuratie van de balancer niet zomaar herladen onder belasting, dit zal "kleine" problemen veroorzaken:
- Validatie van configuratie.
De configuratie kan groot zijn, of zelfs heel groot, als we alles in één keer herladen, stijgt de kans dat er ergens een fout is.
- Langdurige verbindingen.
Bij de initialisatie van een nieuwe listener moet je rekening houden met de verbindingen die actief zijn op de oude. Als wijzigingen frequent plaatsvinden en er langdurige verbindingen zijn, moet er een compromis worden gevonden. Hallo, kubernetes ingress op nginx.
- Actieve health checks.
Als we actieve health checks hebben, moeten we ze allemaal opnieuw controleren op de nieuwe configuratie voordat we verkeer sturen. Als er veel upstreams zijn, kost dit tijd. Hallo, haproxy.
Hoe wordt dit opgelost in envoy, door de configuratie dynamisch te laden volgens het poolmodel, kan deze in afzonderlijke delen worden verdeeld en hoeft het deel dat niet is veranderd niet opnieuw te worden geïnitialiseerd. Bijvoorbeeld een listener, die kostbaar is om opnieuw te initialiseren, verandert slechts zelden.
Configuratie envoy (uit het bovenstaande bestand) heeft de volgende entiteiten:
- listener — een listener die aan een bepaald ip/poort hangt
- virtual host — een virtuele host op basis van de domeinnaam
- route — balansregel
- cluster — een groep upstreams met balansparameters
- om verschillende typen datastromen binnen één apparaat te scheiden. — het adres van de upstream-instantie
Elke van deze entiteiten, plus enkele andere, kan dynamisch worden ingevuld; hiervoor wordt in de configuratie het adres van de service opgegeven waaruit de configuratie zal worden verkregen. De service kan REST of gRPC zijn, waarbij gRPC de voorkeur heeft.
De services worden respectievelijk genoemd: LDS, VHDS, RDS, CDS en EDS. Statische en dynamische configuraties kunnen worden gecombineerd, met de beperking dat een dynamische resource niet in een statische kan worden opgegeven.
Voor de meeste taken is het voldoende om de laatste drie services te implementeren, deze worden ADS (Aggregated Discovery Service) genoemd, voor en Go heeft een kant-en-klare gRPC dataplane-implementatie waarin het voldoende is om alleen de objecten uit uw bron in te vullen.
De configuratie krijgt de volgende vorm:
envoy.yaml dynamische configuratie
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: 6565Bij het uitvoeren verschijnt het volgende: envoy met deze configuratie, zal het verbinding maken met het control-plane en proberen de configuratie RDS, CDS en EDS aan te vragen. Hoe het interactieproces verloopt, wordt beschreven .
Kortom, envoy stuurt een verzoek met de vermelding van het type van het gevraagde resource, de versie en de knooppuntparameters. In ruil daarvoor ontvangt het de resource en de versie; als de versie op het control-plane niet is gewijzigd, antwoordt het niet.
Er zijn 4 interactieopties:
- Een gRPC-stream voor alle types resources, het volledige status van de resource wordt verzonden.
- Gescheiden streams, volledige status.
- Één stream, incrementele status.
- Gescheiden streams, incrementele status.
Incremental xDS vermindert het verkeer tussen de control-plane en envoy, wat relevant is voor grote configuraties. Maar het compliceert de interactie, in de aanvraag wordt een lijst met bronnen voor afmelding en aanmelding verzonden.
In ons voorbeeld wordt ADS gebruikt — één stream voor RDS, CDS, EDS en niet-incrementele modus. Om de incrementele modus in te schakelen, moet worden opgegeven api_type: DELTA_GRPC
Aangezien de aanvraag knooppuntparameters bevat, kunnen we verschillende bronnen voor verschillende instanties naar de control-plane verzenden envoy, wat handig is voor het bouwen van een service mesh.
Warmup
Op envoy bij de start of bij het ontvangen van een nieuwe configuratie van de control-plane, wordt het warmupproces van de middelen gestart. Dit is verdeeld in listener warmup en cluster warmup. De eerste wordt gestart bij wijzigingen in RDS/LDS, de tweede bij CDS/EDS. Dit betekent dat als alleen upstream wordt gewijzigd, de listener niet opnieuw wordt aangemaakt.
Tijdens het opwarmen worden afhankelijkheidsbronnen van de control-plane binnen een time-out verwacht. Als de time-out is verstreken, zal de initialisatie niet succesvol zijn, en zal de nieuwe listener niet beginnen met luisteren op de poort.
De initialisatievolgorde: EDS, CDS, actieve health check, RDS, LDS. Bij ingeschakelde actieve health checks wordt het verkeer naar de upstream pas doorgegeven na één succesvolle health check.
Als de listener opnieuw werd aangemaakt, gaat de oude naar de staat DRAIN en wordt deze verwijderd nadat alle verbindingen zijn gesloten of de time-out is verstreken. --drain-time-s, standaard 10 minuten.
Wordt vervolgd.
Bron: habr.com
