gRPC ist ein leistungsstarkes RPC-Framework von Google, das über HTTP/2 funktioniert und zum De-facto-Standard für die Inter-Service-Kommunikation wird. Doch sobald Sie versuchen, gRPC-Verkehr über einen Proxy zu leiten, treten sofort Probleme auf: Die meisten klassischen Proxy-Server können nicht mit HTTP/2 und langlebigen Streaming-Verbindungen umgehen. In diesem Artikel werden wir untersuchen, wie man gRPC korrekt über einen Proxy konfiguriert – von der Auswahl der Architektur bis hin zu spezifischen Konfigurationen von Nginx, Envoy und HAProxy.
Warum gRPC schlecht mit normalen Proxys funktioniert
Um das Problem zu verstehen, müssen wir uns ansehen, wie gRPC unter der Haube funktioniert. Das Protokoll verwendet HTTP/2 als Transportschicht, was es grundlegend von herkömmlichem REST über HTTP/1.1 unterscheidet. Die meisten Unternehmensproxies, Firewalls und Lastverteiler wurden in der Ära von HTTP/1.1 entwickelt und können einfach keine multiplexierten HTTP/2-Streams verarbeiten.
Hier sind die spezifischen Probleme, auf die Sie stoßen werden, wenn Sie versuchen, gRPC über einen klassischen HTTP-Proxy zu leiten:
- Downgrade auf HTTP/1.1. Viele Proxys senken automatisch die Protokollversion. gRPC erfordert HTTP/2 – ohne es kann die Verbindung einfach nicht hergestellt werden, und der Client erhält einen Fehler
UNAVAILABLE. - Abbruch langlebiger Verbindungen. gRPC nutzt aktiv serverseitiges und bidirektionales Streaming. Proxys mit aggressiven Timeouts (insbesondere AWS ELB Classic, einige Versionen von Squid) brechen Verbindungen ab, die länger als 60 Sekunden keine Daten übertragen.
- Probleme mit Content-Type. gRPC verwendet den Header
Content-Type: application/grpc. Proxys, die diesen Typ nicht kennen, können die Anfrage ablehnen oder den Body nicht korrekt puffern. - Trailers. gRPC verwendet HTTP/2-Trailers zur Übertragung des Abschlussstatus des Aufrufs. HTTP/1.1-Proxys unterstützen keine Trailer – die Statusinformationen gehen verloren.
- Pufferung des Bodys. Einige Proxys puffern den gesamten Body der Antwort, bevor sie ihn an den Client weitergeben. Für Streaming-gRPC-Aufrufe bedeutet dies, dass der Client keine Nachrichten erhält, bis der Stream abgeschlossen ist.
Wichtige Erkenntnis:
Für den Betrieb von gRPC über einen Proxy ist ein Proxy erforderlich, der HTTP/2 End-to-End oder einen speziellen Tunneling-Modus unterstützt. Ein klassischer HTTP-Proxy ohne angepasste Konfiguration ist nicht geeignet.
HTTP/2-Tunneling: Wie es funktioniert
Es gibt zwei grundlegend unterschiedliche Ansätze zum Proxieren von gRPC-Verkehr, und es ist wichtig, den Unterschied zwischen ihnen zu verstehen, um die richtige Lösung für Ihre Architektur auszuwählen.
Ansatz 1: HTTP/2 End-to-End (empfohlen)
Der Proxy versteht HTTP/2 und stellt eine HTTP/2-Verbindung sowohl zum Client als auch zum Backend her. Er kann einzelne Streams analysieren, Lastverteilung auf Anfrageebene anwenden, Header hinzufügen und TLS-Terminierung durchführen. Dies ist die funktionalste Option – so arbeiten Envoy, Nginx (ab Version 1.13.10) und gRPC-bewusste Lastverteiler in Cloud-Anbietern.
Ansatz 2: TCP-Tunneling (CONNECT)
Der Proxy analysiert den HTTP/2-Verkehr nicht, sondern erstellt einfach einen transparenten TCP-Tunnel über die CONNECT-Methode. Der Client stellt die TLS-Verbindung direkt mit dem Backend über den Tunnel her. Der Proxy sieht nur den verschlüsselten Byte-Stream. Diese Methode ist einfacher einzurichten, entzieht Ihnen jedoch die Möglichkeit, Lastverteilung auf gRPC-Anfrageebene durchzuführen und Header hinzuzufügen.
| Merkmal | HTTP/2 End-to-End | TCP CONNECT Tunnel |
|---|---|---|
| Lastverteilung nach Anfragen | ✅ Ja | ❌ Nein (nur über TCP) |
| TLS-Terminierung am Proxy | ✅ Ja | ❌ Nein |
| Header hinzufügen | ✅ Ja | ❌ Nein |
| Schwierigkeitsgrad der Einrichtung | Mittel | Niedrig |
| Unterstützung für Streaming | ✅ Vollständig | ✅ Vollständig |
| Observability (Metriken) | ✅ Detailliert | ❌ Nur TCP |
Nginx als gRPC-Proxy konfigurieren
Nginx unterstützt das Proxieren von gRPC seit Version 1.13.10 (Februar 2018). Für den Betrieb ist das Modul ngx_http_grpc_module erforderlich, das in die Standard-Builds integriert ist. Wichtig: Nginx unterstützt HTTP/2 auf der Client-Seite (Frontend), verwendet jedoch auf der Backend-Seite HTTP/2 nur für gRPC – reguläre HTTP-Upstream-Verbindungen arbeiten über HTTP/1.1.
Basis-Konfiguration für gRPC-Proxy in Nginx
server {
listen 443 ssl http2;
server_name grpc.example.com;
# TLS-Zertifikate
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# Moderne TLS-Parameter
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# grpc_pass-Direktive anstelle von proxy_pass
grpc_pass grpc://grpc_backend;
# Timeouts für langlebige Streams
grpc_read_timeout 3600s;
grpc_send_timeout 3600s;
grpc_connect_timeout 5s;
# Weitergabe der echten IP des Clients
grpc_set_header X-Real-IP $remote_addr;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream grpc_backend {
server backend-1:50051;
server backend-2:50051;
server backend-3:50051;
# Keepalive für HTTP/2-Verbindungen
keepalive 32;
}
Achten Sie auf einige kritische Details. Erstens wird die Direktive grpc_pass verwendet, nicht proxy_pass – das sind verschiedene Module mit unterschiedlichem Verhalten. Zweitens sind die Timeouts grpc_read_timeout und grpc_send_timeout auf 3600 Sekunden (1 Stunde) eingestellt – das ist wichtig für serverseitige Streams, die lange ohne Datenübertragung arbeiten können. Drittens ermöglicht keepalive 32 im Upstream, HTTP/2-Verbindungen mit Backends wiederzuverwenden.
Konfiguration für unverschlüsseltes gRPC (grpc://)
server {
listen 80 http2;
server_name grpc-internal.example.com;
location / {
grpc_pass grpc://127.0.0.1:50051;
# Behandlung von gRPC-Fehlern
error_page 502 = /error502grpc;
}
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header content-length 0;
return 204;
}
}
Der Block error502grpc ist ein wichtiges Detail: Wenn das Backend nicht verfügbar ist, gibt es den korrekten gRPC-Status UNAVAILABLE (14) zurück, anstelle von HTTP 502, den der gRPC-Client nicht korrekt verarbeiten kann.
Envoy Proxy: Die beste Wahl für gRPC in Microservices
Envoy wurde von Lyft speziell für Microservice-Architekturen entwickelt, und die Unterstützung von gRPC ist auf der tiefsten Ebene implementiert. Es versteht Protocol Buffers, kann gRPC in REST transkodieren, sammelt detaillierte Metriken für jede RPC-Methode und ist die Grundlage für Service-Mesh-Lösungen – Istio, AWS App Mesh und andere. Wenn Sie eine ernsthafte Microservice-Architektur aufbauen, ist Envoy der Industriestandard.
Basis-Konfiguration von Envoy für gRPC
static_resources:
listeners:
- name: grpc_listener
address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: grpc_proxy
codec_type: HTTP2
route_config:
name: grpc_routes
virtual_hosts:
- name: grpc_services
domains: ["*"]
routes:
- match:
prefix: "/com.example.UserService"
route:
cluster: user_service
timeout: 30s
retry_policy:
retry_on: "reset,connect-failure,retriable-status-codes"
num_retries: 3
retriable_status_codes: [14]
- match:
prefix: "/com.example.OrderService"
route:
cluster: order_service
timeout: 60s
http_filters:
- name: envoy.filters.http.grpc_stats
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
emit_filter_state: true
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: user_service
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: user_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: user-service
port_value: 50051
Die wichtigsten Vorteile dieser Konfiguration: Routing nach gRPC-Diensten (der Pfad-Präfix entspricht dem vollständigen Namen des Dienstes im Format package.ServiceName), automatische Wiederholungen bei Status UNAVAILABLE und das Sammeln von gRPC-Metriken über den Filter grpc_stats.
gRPC-Web Transkodierung in Envoy
Eine der Killer-Funktionen von Envoy ist der integrierte gRPC-Web-Transcoder. Browser unterstützen gRPC nicht direkt (aufgrund von Einschränkungen des Fetch-API bei HTTP/2-Trailers), daher wird das gRPC-Web-Protokoll verwendet. Envoy kann automatisch gRPC-Web-Anfragen vom Browser in normales gRPC für das Backend umwandeln:
http_filters:
- name: envoy.filters.http.grpc_web
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
HAProxy und gRPC: Konfiguration mit Lastverteilung
HAProxy unterstützt gRPC seit Version 1.9.2. Es arbeitet auf TCP- oder HTTP/2-Ebene, kann gRPC-Verkehr ausbalancieren und Health Checks durchführen. HAProxy ist eine gute Wahl, wenn Sie es bereits in Ihrer Infrastruktur verwenden und gRPC-Unterstützung hinzufügen möchten, ohne ein neues Element einzuführen.
global
maxconn 50000
log stdout format raw local0
defaults
log global
timeout connect 5s
timeout client 3600s
timeout server 3600s
frontend grpc_frontend
bind *:443 ssl crt /etc/haproxy/certs/server.pem alpn h2,http/1.1
mode http
option http-use-htx
default_backend grpc_servers
backend grpc_servers
mode http
balance leastconn
option http-use-htx
# Health Check über das gRPC Health Checking Protocol
option httpchk GET /grpc.health.v1.Health/Check
http-check expect status 200
server grpc1 10.0.0.1:50051 check ssl verify none
server grpc2 10.0.0.2:50051 check ssl verify none
server grpc3 10.0.0.3:50051 check ssl verify none
Achten Sie auf einige wichtige Einstellungen. alpn h2,http/1.1 in der Bind-Direktive gibt an, dass HAProxy sowohl HTTP/2- als auch HTTP/1.1-Verbindungen über TLS ALPN-Verhandlung akzeptiert. timeout client 3600s und timeout server 3600s sind kritische Parameter für langlebige gRPC-Streams. Der Algorithmus leastconn ist für gRPC vorzuziehen, da Streaming-Verbindungen langlebig sein können und die Backends ungleichmäßig belasten.
TLS-Terminierung und End-to-End-Verschlüsselung für gRPC
gRPC setzt standardmäßig die Verwendung von TLS voraus – das ist Teil der Spezifikation. In der Praxis stellt sich in einer Microservice-Architektur die Frage: Wo sollte die TLS-Terminierung erfolgen und wie kann die Verschlüsselung zwischen den Komponenten organisiert werden? Es gibt drei Hauptmuster.
Muster 1: TLS-Terminierung am Proxy (Edge TLS)
Der Proxy akzeptiert verschlüsselten Verkehr von Clients, entschlüsselt ihn und leitet ihn über eine unverschlüsselte Verbindung (oder mit separatem TLS) an die Backends weiter. Dies ist der gebräuchlichste Ansatz in Unternehmensnetzwerken. Backends können grpc.Insecure() verwenden, um die Konfiguration zu vereinfachen.
Muster 2: End-to-End-Verschlüsselung (mTLS)
Mutual TLS (mTLS) ist der Standard für Service Mesh. Jeder Dienst hat ein eigenes Zertifikat, und bei jeder Verbindung überprüfen beide Seiten die Zertifikate des jeweils anderen. Dies gewährleistet die Authentifizierung von Diensten und die Verschlüsselung des Verkehrs innerhalb des Clusters. So funktioniert Istio mit dem Envoy Sidecar-Proxy.
# Go: gRPC-Server mit mTLS
import (
"crypto/tls"
"crypto/x509"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func createMTLSCredentials() credentials.TransportCredentials {
cert, _ := tls.LoadX509KeyPair("server.crt", "server.key")
caCert, _ := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caCertPool,
}
return credentials.NewTLS(tlsConfig)
}
// Erstellen eines Servers mit mTLS
creds := createMTLSCredentials()
server := grpc.NewServer(grpc.Creds(creds))
Muster 3: TLS Passthrough
Der Proxy arbeitet auf TCP-Ebene und entschlüsselt den Verkehr nicht – er leitet einfach die verschlüsselten Bytes an das Backend weiter. Dies ist die einfachste Option aus Sicht des Proxys, entzieht jedoch die Möglichkeit, gRPC-Verkehr zu analysieren, Header hinzuzufügen oder Lastverteilung auf Anfrageebene durchzuführen.
Lastverteilung für gRPC-Streams: Besonderheiten und Lösungen
Die Lastverteilung für gRPC ist keine triviale Aufgabe, und das aus gutem Grund. In HTTP/1.1 ist jede Anfrage eine separate TCP-Verbindung (oder eine Verbindung aus einem Pool), und der Lastverteiler verteilt die Anfragen problemlos auf die Backends. In HTTP/2 multiplexiert eine TCP-Verbindung viele Streams – wenn der Lastverteiler auf TCP-Ebene arbeitet, gelangen alle Streams einer Verbindung zu einem Backend.
Für gRPC bedeutet dies: Wenn der Client eine HTTP/2-Verbindung hergestellt hat und darüber 100 RPC-Anfragen sendet, wird bei TCP-Lastverteilung alle 100 Anfragen von einer Instanz des Backends verarbeitet. Die anderen Backends bleiben untätig. Die Lösung ist die Lastverteilung auf HTTP/2-Stream-Ebene (L7-Lastverteilung).
Lastverteilungsalgorithmen für gRPC
| Algorithmus | Geeignet für gRPC | Kommentar |
|---|---|---|
| Round Robin | ✅ Ja | Gut für unäre RPC mit ungefähr gleicher Bearbeitungszeit |
| Least Connection | ✅ Beste Wahl | Berücksichtigt aktive Streams, verteilt die Last gleichmäßig |
| Random | ⚠️ Bedingt | Funktioniert bei einer großen Anzahl von Anfragen, ungleichmäßig bei wenigen |
| IP Hash | ❌ Schlecht | Bindet den Client an ein Backend, macht keinen Sinn bei L7 |
| Pick First (gRPC eingebaut) | ❌ Nicht für Produktion | Alle Anfragen gehen an den ersten verfügbaren Server |
Client-seitige Lastverteilung in gRPC
gRPC unterstützt client-seitige Lastverteilung – der Client entscheidet selbst, an welchen Server er die Anfrage senden möchte. Dies ermöglicht es, das Problem der TCP-Multiplexierung zu umgehen. Für die Service Discovery wird DNS mit mehreren A-Einträgen oder speziellen Resolvern (Consul, etcd) verwendet. Beispiel für die Konfiguration der client-seitigen Lastverteilung in Go:
import (
"google.golang.org/grpc"
"google.golang.org/grpc/balancer/roundrobin"
)
// Client mit Round-Robin-Lastverteilung über DNS
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"round_robin":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
// Client mit Least-Connection (verfügbar in gRPC >= 1.58)
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"least_request":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
Externe Proxys für gRPC: Wann und warum sie in Microservices benötigt werden
Neben internen Proxy-Komponenten (Nginx, Envoy, HAProxy) kann in einer Microservice-Architektur manchmal die Notwendigkeit bestehen, externe Proxy-Server zu verwenden – beispielsweise zur Routen von Verkehr durch bestimmte Regionen, zum Umgehen von Netzwerkbeschränkungen oder zur Isolierung von ausgehenden Verbindungen. Lassen Sie uns die wichtigsten Szenarien betrachten.
Szenario 1: Georepartierte Microservices
Wenn Ihre Microservices in verschiedenen Regionen angesiedelt sind (zum Beispiel einige in Europa, einige in den USA), und Sie kontrollieren müssen, über welche IP-Adresse die gRPC-Verbindungen zwischen den Regionen hergestellt werden, können externe Proxys helfen, eine vorhersehbare Routenführung zu organisieren. Für solche Aufgaben eignen sich Datacenter-Proxys – sie bieten stabile IP-Adressen und hohe Verbindungsraten, was für gRPC mit seiner Empfindlichkeit gegenüber Verzögerungen entscheidend ist.
Szenario 2: Isolierung des ausgehenden Verkehrs
In einigen Unternehmensumgebungen muss der gesamte ausgehende Verkehr über einen Unternehmensproxy geleitet werden. Für gRPC-Clients, die auf externe gRPC-Dienste zugreifen müssen (zum Beispiel Google Cloud APIs, die gRPC verwenden), kann dies zu Schwierigkeiten führen. Die Lösung besteht darin, einen CONNECT-Tunnel über den Unternehmensproxy einzurichten.
Beispiel für die Konfiguration eines gRPC-Clients zur Arbeit über einen HTTP CONNECT-Proxy in Go:
import (
"net"
"net/http"
"golang.org/x/net/proxy"
"google.golang.org/grpc"
)
// Verwendung eines SOCKS5-Proxys für gRPC
proxyDialer, _ := proxy.SOCKS5(
"tcp",
"proxy.example.com:1080",
&proxy.Auth{User: "user", Password: "pass"},
proxy.Direct,
)
conn, err := grpc.Dial(
"grpc-service.example.com:443",
grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
return proxyDialer.Dial("tcp", addr)
}),
grpc.WithTransportCredentials(creds),
)
Szenario 3: Testen und Entwicklung
Bei der Entwicklung von Microservices muss oft das Verhalten von Diensten aus verschiedenen Netzwerkumgebungen getestet werden – zu überprüfen, wie der Dienst bei hoher Latenz reagiert, oder die geoabhängige Logik zu testen. Für solche Aufgaben sind residential Proxys praktisch, die es ermöglichen, Anfragen aus bestimmten Regionen mit realen IPs von Heimnutzern zu simulieren.
Typische Fehler bei der Konfiguration von gRPC über Proxy und deren Behebung
Lassen Sie uns die häufigsten Probleme untersuchen, mit denen Entwickler bei der Konfiguration von gRPC über Proxys konfrontiert sind, und spezifische Lösungen dafür.
Fehler 1: "transport: received the unexpected content-type"
Symptom:
Der Client erhält einen Fehler transport: received the unexpected content-type "text/html; charset=utf-8"
Ursache: Der Proxy hat eine HTML-Fehlerseite (z.B. 502 Bad Gateway) anstelle der gRPC-Antwort zurückgegeben. Der gRPC-Client kann HTML nicht verarbeiten und gibt diesen Fehler aus.
Lösung: Stellen Sie sicher, dass das Backend verfügbar ist. Fügen Sie eine Behandlung von gRPC-Fehlern auf Proxy-Ebene hinzu (wie im obigen Nginx-Beispiel mit dem Block error502grpc).
Fehler 2: Verbindung bricht nach 60-120 Sekunden ab
Symptom:
Streaming-gRPC-Verbindungen schließen sich unerwartet mit dem Fehler UNAVAILABLE: transport is closing nach ungefähr gleichem Zeitintervall.
Ursache: Der Proxy schließt Leerlaufverbindungen aufgrund von Timeouts. Klassische Werte: AWS ELB – 60 Sekunden, Nginx standardmäßig – 60 Sekunden.
Lösung 1: Erhöhen Sie die Timeouts am Proxy (wie in den obigen Beispielen gezeigt).
Lösung 2: Konfigurieren Sie Keepalive auf der gRPC-Client-Seite:
import "google.golang.org/grpc/keepalive"
kaParams := keepalive.ClientParameters{
Time: 30 * time.Second, // Ping alle 30 Sekunden
Timeout: 10 * time.Second, // Auf Antwort 10 Sekunden warten
PermitWithoutStream: true, // Pingen auch ohne aktive RPCs
}
conn, err := grpc.Dial(
"grpc-service:50051",
grpc.WithKeepaliveParams(kaParams),
grpc.WithTransportCredentials(creds),
)
Fehler 3: HTTP/2 kann nicht ausgehandelt werden (ALPN-Fehler)
Symptom:
Fehler transport: failed to dial: context deadline exceeded oder no application protocol
Ursache: Der Proxy oder die Zwischenhardware unterstützt ALPN (Application-Layer Protocol Negotiation) nicht oder h2 ist nicht in der Liste der unterstützten Protokolle enthalten.
Lösung: Stellen Sie sicher, dass in der TLS-Konfiguration des Proxys das Protokoll h2 explizit angegeben ist: alpn h2,http/1.1 (HAProxy) oder listen 443 ssl http2 (Nginx).
Fehler 4: Streaming hängt – keine Daten kommen an
Symptom:
Der serverseitige Stream funktioniert im Backend (sichtbar in den Logs), aber der Client erhält keine Nachrichten bis zum Abschluss des Streams.
Ursache: Der Proxy puffert die Antwort und sendet sie erst nach Abschluss an den Client. Typisches Problem für Proxys, die mit proxy_buffering on konfiguriert sind.
Lösung für Nginx:
location / {
grpc_pass grpc://backend;
# Pufferung für gRPC-Streams deaktivieren
grpc_buffer_size 0;
# Oder für reguläres proxy_pass:
proxy_buffering off;
proxy_cache off;
}
Diagnoseliste für gRPC über Proxy
✅ Checkliste: Diagnose von gRPC-Proxys
- Der Proxy unterstützt HTTP/2 (überprüfen Sie mit
curl --http2 -v) - ALPN h2 ist in der TLS-Konfiguration des Proxys aktiviert
- Timeouts für Client und Server sind auf mindestens 300 Sekunden eingestellt
- Antwortpufferung ist für gRPC-Endpunkte deaktiviert
- gRPC-keepalive ist auf dem Client konfiguriert (Time: 30s, Timeout: 10s)
- Backend-Fehler werden als gRPC-Status und nicht als HTTP-Codes zurückgegeben
- Health Check verwendet das gRPC Health Checking Protocol
- Lastverteilung funktioniert auf L7 (HTTP/2-Streams) und nicht auf L4 (TCP)
Fazit
Die Konfiguration von gRPC über Proxy erfordert ein Verständnis der wesentlichen Unterschiede zwischen HTTP/2 und HTTP/1.1: Multiplexing von Streams, langlebige Verbindungen, HTTP/2-Trailers und ALPN-Aushandlung. Klassische HTTP-Proxys funktionieren ohne spezielle Anpassungen mit gRPC nicht – entweder ist ein L7-Proxy mit Unterstützung für HTTP/2 (Nginx 1.13.10+, Envoy, HAProxy 1.9.2+) erforderlich oder TCP CONNECT-Tunneling.
Für Produktionsumgebungen wird Envoy empfohlen – es wurde speziell für Microservice-Architekturen entwickelt, hat native Unterstützung für gRPC, kann detaillierte Metriken für jede RPC-Methode sammeln und ist die Grundlage der meisten Service-Mesh-Lösungen. Nginx ist eine gute Wahl, wenn Sie es bereits als API-Gateway verwenden und gRPC-Unterstützung hinzufügen möchten, ohne ein neues Element einzuführen. HAProxy eignet sich, wenn Leistung entscheidend ist und Sie bereits mit seiner Konfiguration vertraut sind.
Unabhängig von dem gewählten Proxy bleiben drei Regeln unverändert: Erhöhen Sie die Timeouts für langlebige Streams, deaktivieren Sie die Antwortpufferung und konfigurieren Sie Keepalive auf dem Client. Diese drei Einstellungen lösen 80% der Probleme mit gRPC über Proxys.
Wenn in Ihrer Architektur gRPC-Dienste über externe Netzwerke kommunizieren müssen oder Sie den Verkehr durch bestimmte Regionen routen müssen, sollten Sie auf Datacenter-Proxys achten – sie bieten stabile IP-Adressen, niedrige Latenz und hohe Bandbreite, was besonders wichtig für gRPC mit seinem binären Protokoll und seiner Empfindlichkeit gegenüber Latenz ist.
```