Grüße! Dies ist ein kurzer Artikel, der die Fragen beantwortet: „Was ist ein Gesandter?“, „Warum wird er benötigt?“ und „Wo soll ich anfangen?“.
Was ist das
Envoy ist ein in C++ geschriebener L4-L7-Balancer, der auf hohe Leistung und Verfügbarkeit ausgerichtet ist. Einerseits ist dies in gewisser Weise ein Analogon zu Nginx und Haproxy, dessen Leistung mit ihnen vergleichbar ist. Andererseits ist es eher auf die Microservice-Architektur ausgerichtet und verfügt über eine nicht schlechtere Funktionalität als Java- und Go-Balancer wie Zuul oder Traefik.
Vergleichstabelle von haproxy/nginx/envoy, sie erhebt keinen Anspruch auf absolute Wahrheit, sondern vermittelt ein allgemeines Bild.
haproxy
Gesandte
Verkehr
Sterne auf Github
11.2k/Spiegel
1.1k/Spiegel
12.4K
27.6K
geschrieben in
C
C
C + +
go
API
Nein
Nur Steckdose/Push
Datenebene/Pull
ziehen
aktiver Gesundheitscheck
Nein
ja
ja
ja
Offene Nachverfolgung
externes Plugin
Nein
ja
ja
JWT
externes Plugin
Nein
ja
Nein
Expansion
Lua/C
Lua/C
Lua/C++
Nein
Warum
Dies ist ein junges Projekt, es fehlen viele Dinge, einige befinden sich in der frühen Alpha. Aber Gesandteentwickelt sich, auch aufgrund seiner Jugend, rasant und verfügt bereits über viele interessante Features: dynamische Konfiguration, viele vorgefertigte Filter, eine einfache Schnittstelle zum Schreiben eigener Filter.
Daraus ergeben sich Anwendungsbereiche, allerdings gibt es zunächst 2 Antimuster:
- Statischer Rückstoß.
Tatsache ist, dass im Moment in Gesandte keine Caching-Unterstützung. Die Google-Leute versuchen das
Verwenden Sie vorerst Nginx für die Statik.
- Statische Konfiguration.
Sie können es verwenden, aber Gesandte Dafür wurde es nicht geschaffen. Features in einer statischen Konfiguration werden nicht verfügbar gemacht. Es gibt viele Momente:
Wenn Sie die Konfiguration in Yaml bearbeiten, werden Sie sich irren, die Entwickler für ihre Ausführlichkeit schelten und denken, dass die Nginx/Haproxy-Konfigurationen zwar weniger strukturiert, aber prägnanter sind. Das ist der Punkt. Die Konfiguration von Nginx und Haproxy wurde zur manuellen Bearbeitung erstellt und Gesandte zur Generierung aus Code. Die gesamte Konfiguration ist in beschrieben
Canary-, B/G-Bereitstellungsszenarien und vieles mehr werden normalerweise nur in einer dynamischen Konfiguration implementiert. Ich sage nicht, dass dies nicht statisch möglich ist, wir alle tun es. Dafür müssen Sie jedoch Krücken in einem der Balancer anziehen Gesandte einschließlich.
Aufgaben, für die Envoy unverzichtbar ist:
- Verkehrsausgleich in komplexen und dynamischen Systemen. Dazu gehört auch das Service Mesh, es ist aber nicht unbedingt das einzige.
- Der Bedarf an verteilter Ablaufverfolgungsfunktion, komplexer Autorisierung oder anderen verfügbaren Funktionen Gesandte sofort einsatzbereit oder bequem implementiert, aber in Nginx/Haproxy muss man von Lua und dubiosen Plugins umgeben sein.
Beide liefern bei Bedarf eine hohe Leistung.
Wie funktioniert das
Envoy wird in Binärdateien nur als Docker-Image verteilt. Das Bild enthält bereits ein Beispiel einer statischen Konfiguration. Aber wir sind nur daran interessiert, die Struktur zu verstehen.
Statische Konfiguration von 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
Dynamische Konfiguration
Für welches Problem suchen wir eine Lösung? Unter Last kann man die Load-Balancer-Konfiguration nicht einfach neu laden, es entstehen „kleine“ Probleme:
- Konfigurationsvalidierung.
Die Konfiguration kann groß sein, sie kann sehr groß sein. Wenn wir sie auf einmal überlasten, steigt die Wahrscheinlichkeit, dass irgendwo ein Fehler auftritt.
- Langlebige Verbindungen.
Wenn Sie einen neuen Listener initialisieren, müssen Sie sich um die Verbindungen kümmern, die auf dem alten laufen. Bei häufigen Änderungen und langlebigen Verbindungen müssen Sie nach einem Kompromiss suchen. Hallo, Kubernetes-Ingress auf Nginx.
- Aktive Gesundheitschecks.
Wenn wir aktive Gesundheitsprüfungen haben, müssen wir sie alle in der neuen Konfiguration noch einmal überprüfen, bevor wir Datenverkehr senden. Wenn es viele Upstreams gibt, braucht das Zeit. Hallo haproxy.
Wie wird das gelöst? GesandteIndem Sie die Konfiguration entsprechend dem Poolmodell dynamisch laden, können Sie sie in separate Teile aufteilen und müssen den Teil, der sich nicht geändert hat, nicht erneut initialisieren. Zum Beispiel ein Listener, dessen Neuinitialisierung teuer ist und der sich selten ändert.
Konfiguration Gesandte (aus der Datei oben) hat die folgenden Entitäten:
- Hörer – Listener hängt an einer bestimmten IP/einem bestimmten Port
- virtueller Host - Virtueller Host nach Domänenname
- Route - Ausgleichsregel
- Gruppe — eine Gruppe von Upstreams mit Ausgleichsparametern
- Endpunkt — Upstream-Instanzadresse
Jede dieser Entitäten und einige andere können dynamisch ausgefüllt werden; dazu gibt die Konfiguration die Adresse des Dienstes an, von dem die Konfiguration empfangen wird. Der Dienst kann REST oder gRPC sein, gRPC ist vorzuziehen.
Die Dienste heißen jeweils: LDS, VHDS, RDS, CDS und EDS. Sie können statische und dynamische Konfiguration kombinieren, mit der Einschränkung, dass eine dynamische Ressource nicht in einer statischen angegeben werden kann.
Für die meisten Aufgaben reicht es aus, die letzten drei Dienste zu implementieren, sie werden z. B. ADS (Aggregated Discovery Service) genannt
Die Konfiguration hat folgende Form:
Dynamische Konfiguration von 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
Beim Ausführen Gesandte Mit dieser Konfiguration wird eine Verbindung zur Steuerungsebene hergestellt und versucht, die RDS-, CDS- und EDS-Konfiguration anzufordern. Es wird beschrieben, wie der Interaktionsprozess abläuft
Zusamenfassend, Gesandte sendet eine Anfrage mit Angabe des angeforderten Ressourcentyps, der Version und der Parameter des Knotens. Als Antwort erhält es eine Ressource und eine Version; wenn sich die Version auf der Steuerungsebene nicht geändert hat, antwortet es nicht.
Es gibt 4 Interaktionsmöglichkeiten:
- Ein gRPC-Stream für alle Arten von Ressourcen, der vollständige Status der Ressource wird gesendet.
- Separate Streams, vollständiger Zustand.
- Ein Stream, inkrementeller Zustand.
- Separate Streams, inkrementeller Status.
Mit inkrementellem xDS können Sie den Datenverkehr zwischen der Steuerungsebene und reduzieren GesandteDies ist für große Konfigurationen relevant. Dies erschwert jedoch die Interaktion: Die Anfrage enthält eine Liste von Ressourcen zum Abmelden und Abonnieren.
Unser Beispiel verwendet ADS – einen Stream für RDS, CDS, EDS und den nicht-inkrementellen Modus. Um den inkrementellen Modus zu aktivieren, müssen Sie Folgendes angeben api_type: DELTA_GRPC
Da die Anfrage Knotenparameter enthält, können wir für verschiedene Instanzen unterschiedliche Ressourcen an die Steuerungsebene senden GesandteDies ist praktisch für den Aufbau eines Service-Mesh.
Sich warm laufen
Auf Gesandte Beim Start oder beim Empfang einer neuen Konfiguration von der Steuerungsebene wird der Ressourcenaufwärmprozess gestartet. Es ist in Listener-Aufwärmphase und Cluster-Aufwärmphase unterteilt. Der erste wird bei Änderungen in RDS/LDS gestartet, der zweite bei CDS/EDS. Das bedeutet, dass der Listener nicht neu erstellt wird, wenn sich nur Upstreams ändern.
Während des Aufwärmvorgangs werden während des Timeouts abhängige Ressourcen von der Steuerungsebene erwartet. Wenn die Zeitüberschreitung auftritt, ist die Initialisierung nicht erfolgreich und der neue Listener beginnt nicht mit der Überwachung des Ports.
Initialisierungsreihenfolge: EDS, CDS, aktive Gesundheitsprüfung, RDS, LDS. Wenn aktive Gesundheitsprüfungen aktiviert sind, wird der Datenverkehr erst nach einer erfolgreichen Gesundheitsprüfung flussaufwärts geleitet.
Wenn der Listener neu erstellt wurde, wechselt der alte in den DRAIN-Status und wird gelöscht, nachdem alle Verbindungen geschlossen wurden oder das Timeout abgelaufen ist --drain-time-s
, Standard 10 Minuten.
To be continued.
Source: habr.com