gRPC là một framework RPC hiệu suất cao từ Google, hoạt động trên nền tảng HTTP/2 và đang trở thành tiêu chuẩn de facto cho việc tương tác giữa các dịch vụ. Nhưng ngay khi bạn cố gắng truyền tải lưu lượng gRPC qua proxy, sẽ ngay lập tức xuất hiện vấn đề: hầu hết các máy chủ proxy cổ điển không thể làm việc với HTTP/2 và các kết nối streaming lâu dài. Trong bài viết này, chúng ta sẽ xem xét cách cấu hình gRPC qua proxy một cách chính xác — từ việc chọn kiến trúc đến các cấu hình cụ thể cho Nginx, Envoy và HAProxy.
Tại sao gRPC hoạt động kém với proxy thông thường
Để hiểu vấn đề, cần phải tìm hiểu cách gRPC hoạt động bên trong. Giao thức sử dụng HTTP/2 làm lớp vận chuyển, và điều này hoàn toàn khác biệt so với REST thông thường trên HTTP/1.1. Hầu hết các proxy doanh nghiệp, tường lửa và bộ cân bằng tải được thiết kế trong thời đại HTTP/1.1 và đơn giản là không thể xử lý các luồng HTTP/2 đa hợp.
Dưới đây là những vấn đề cụ thể mà bạn sẽ gặp phải khi cố gắng truyền tải gRPC qua proxy HTTP cổ điển:
- Giảm cấp xuống HTTP/1.1. Nhiều proxy tự động hạ cấp phiên bản giao thức. gRPC yêu cầu HTTP/2 — nếu không, kết nối sẽ không được thiết lập và khách hàng sẽ nhận được lỗi
UNAVAILABLE. - Ngắt kết nối lâu dài. gRPC sử dụng tích cực streaming từ máy chủ và hai chiều. Các proxy với thời gian chờ quá nghiêm ngặt (đặc biệt là AWS ELB Classic, một số phiên bản Squid) sẽ ngắt kết nối không truyền dữ liệu lâu hơn 60 giây.
- Vấn đề với Content-Type. gRPC sử dụng tiêu đề
Content-Type: application/grpc. Proxy không biết loại này có thể từ chối yêu cầu hoặc bộ đệm nội dung không chính xác. - Trailers (đoạn cuối). gRPC sử dụng HTTP/2 trailers để truyền tải trạng thái hoàn thành cuộc gọi. Proxy HTTP/1.1 không hỗ trợ trailers — thông tin về trạng thái sẽ bị mất.
- Bộ đệm nội dung. Một số proxy bộ đệm toàn bộ nội dung phản hồi trước khi chuyển đến khách hàng. Đối với các cuộc gọi gRPC streaming, điều này có nghĩa là khách hàng sẽ không nhận được bất kỳ thông điệp nào cho đến khi luồng hoàn tất.
Kết luận chính:
Để gRPC hoạt động qua proxy, cần một proxy hỗ trợ HTTP/2 end-to-end hoặc chế độ tunneling đặc biệt. Proxy HTTP cổ điển mà không có cấu hình bổ sung sẽ không phù hợp.
Tunneling HTTP/2: cách nó hoạt động
Có hai cách tiếp cận khác nhau để proxy lưu lượng gRPC, và điều quan trọng là phải hiểu sự khác biệt giữa chúng để chọn giải pháp phù hợp cho kiến trúc của bạn.
Cách tiếp cận 1: HTTP/2 end-to-end (được khuyến nghị)
Proxy hiểu HTTP/2 và thiết lập kết nối HTTP/2 với cả khách hàng và backend. Nó có thể phân tích các luồng riêng lẻ, áp dụng cân bằng tải ở cấp độ yêu cầu, thêm tiêu đề và thực hiện kết thúc TLS. Đây là tùy chọn chức năng nhất — Envoy, Nginx (bắt đầu từ phiên bản 1.13.10) và các bộ cân bằng tải nhận thức gRPC trong các nhà cung cấp đám mây hoạt động như vậy.
Cách tiếp cận 2: Tunneling TCP (CONNECT)
Proxy không phân tích lưu lượng HTTP/2 mà chỉ tạo một tunneling TCP trong phương thức CONNECT. Khách hàng thiết lập kết nối TLS trực tiếp với backend qua tunneling. Proxy chỉ thấy luồng byte đã được mã hóa. Phương pháp này dễ thiết lập hơn, nhưng sẽ khiến bạn mất đi khả năng cân bằng tải ở cấp độ yêu cầu gRPC và thêm tiêu đề.
| Đặc điểm | HTTP/2 end-to-end | Tunneling TCP CONNECT |
|---|---|---|
| Cân bằng theo yêu cầu | ✅ Có | ❌ Không (chỉ theo TCP) |
| Kết thúc TLS trên proxy | ✅ Có | ❌ Không |
| Thêm tiêu đề | ✅ Có | ❌ Không |
| Độ phức tạp của cấu hình | Trung bình | Thấp |
| Hỗ trợ streaming | ✅ Hoàn toàn | ✅ Hoàn toàn |
| Khả năng quan sát (metrics) | ✅ Chi tiết | ❌ Chỉ TCP |
Cấu hình Nginx như một gRPC-proxy
Nginx hỗ trợ proxy gRPC bắt đầu từ phiên bản 1.13.10 (tháng 2 năm 2018). Để hoạt động, cần có module ngx_http_grpc_module, được bao gồm trong bản dựng tiêu chuẩn. Quan trọng: Nginx hỗ trợ HTTP/2 ở phía khách hàng (frontend), nhưng ở phía backend chỉ sử dụng HTTP/2 cho gRPC — upstream HTTP thông thường hoạt động trên HTTP/1.1.
Cấu hình cơ bản cho gRPC-proxy trên Nginx
server {
listen 443 ssl http2;
server_name grpc.example.com;
# Chứng chỉ TLS
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# Tham số TLS hiện đại
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# Chỉ thị grpc_pass thay vì proxy_pass
grpc_pass grpc://grpc_backend;
# Thời gian chờ cho các luồng lâu dài
grpc_read_timeout 3600s;
grpc_send_timeout 3600s;
grpc_connect_timeout 5s;
# Truyền IP thực của khách hàng
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 cho các kết nối HTTP/2
keepalive 32;
}
Lưu ý một số chi tiết quan trọng. Đầu tiên, sử dụng chỉ thị grpc_pass, không phải proxy_pass — đây là hai module khác nhau với hành vi khác nhau. Thứ hai, thời gian chờ grpc_read_timeout và grpc_send_timeout được đặt thành 3600 giây (1 giờ) — điều này rất quan trọng cho các luồng máy chủ có thể hoạt động lâu mà không truyền dữ liệu. Thứ ba, keepalive 32 trong upstream cho phép tái sử dụng các kết nối HTTP/2 với các backend.
Cấu hình cho gRPC không mã hóa (grpc://)
server {
listen 80 http2;
server_name grpc-internal.example.com;
location / {
grpc_pass grpc://127.0.0.1:50051;
# Xử lý lỗi gRPC
error_page 502 = /error502grpc;
}
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header content-length 0;
return 204;
}
}
Khối error502grpc là một chi tiết quan trọng: khi backend không khả dụng, nó trả về trạng thái gRPC chính xác UNAVAILABLE (14) thay vì mã HTTP 502, mà khách hàng gRPC sẽ không thể xử lý chính xác.
Envoy Proxy: lựa chọn tốt nhất cho gRPC trong microservices
Envoy được tạo ra bởi Lyft đặc biệt cho kiến trúc microservices, và hỗ trợ gRPC trong nó được thực hiện ở mức độ sâu nhất. Nó hiểu Protocol Buffers, có khả năng chuyển đổi gRPC thành REST, thu thập các metrics chi tiết cho mỗi phương thức RPC và là nền tảng cho các giải pháp service mesh — Istio, AWS App Mesh và nhiều hơn nữa. Nếu bạn đang xây dựng một kiến trúc microservices nghiêm túc, Envoy là tiêu chuẩn của ngành.
Cấu hình cơ bản cho Envoy cho 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
Những lợi ích chính của cấu hình này: định tuyến theo các dịch vụ gRPC (tiền tố đường dẫn tương ứng với tên đầy đủ của dịch vụ theo định dạng package.ServiceName), tự động retry khi có trạng thái UNAVAILABLE và thu thập metrics gRPC thông qua bộ lọc grpc_stats.
Chuyển đổi gRPC-Web trong Envoy
Một trong những tính năng nổi bật của Envoy là bộ chuyển đổi gRPC-Web tích hợp sẵn. Các trình duyệt không hỗ trợ gRPC trực tiếp (do các hạn chế của Fetch API đối với HTTP/2 trailers), vì vậy giao thức gRPC-Web được sử dụng. Envoy có thể tự động chuyển đổi các yêu cầu gRPC-Web từ trình duyệt thành gRPC thông thường cho backend:
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 và gRPC: cấu hình với cân bằng tải
HAProxy hỗ trợ gRPC bắt đầu từ phiên bản 1.9.2. Nó hoạt động ở cấp độ TCP hoặc HTTP/2, có khả năng cân bằng lưu lượng gRPC và thực hiện health checks. HAProxy là lựa chọn tốt nếu bạn đã sử dụng nó trong cơ sở hạ tầng và muốn thêm hỗ trợ gRPC mà không cần giới thiệu một thành phần mới.
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
# Kiểm tra sức khỏe qua Giao thức Kiểm tra Sức khỏe gRPC
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
Lưu ý một số cài đặt quan trọng. alpn h2,http/1.1 trong chỉ thị bind chỉ ra rằng HAProxy chấp nhận cả kết nối HTTP/2 và HTTP/1.1 qua TLS ALPN negotiation. timeout client 3600s và timeout server 3600s là các tham số quan trọng cho các luồng gRPC lâu dài. Thuật toán leastconn được ưu tiên hơn roundrobin cho gRPC, vì các kết nối streaming có thể kéo dài và không phân bổ đều tải cho các backend.
Kết thúc TLS và mã hóa đầu cuối cho gRPC
gRPC mặc định yêu cầu sử dụng TLS — đây là một phần của thông số kỹ thuật. Trong thực tế, trong kiến trúc microservices, câu hỏi đặt ra là: nơi nào thực hiện kết thúc TLS và làm thế nào để tổ chức mã hóa giữa các thành phần? Có ba mẫu chính.
Mẫu 1: Kết thúc TLS trên proxy (Edge TLS)
Proxy nhận lưu lượng được mã hóa từ khách hàng, giải mã nó và chuyển đến các backend qua kênh không mã hóa (hoặc với TLS riêng). Đây là cách tiếp cận phổ biến nhất trong các mạng doanh nghiệp. Các backend có thể sử dụng grpc.Insecure() để đơn giản hóa cấu hình.
Mẫu 2: Mã hóa đầu cuối (mTLS)
Mã hóa TLS tương hỗ (mTLS) là tiêu chuẩn cho service mesh. Mỗi dịch vụ có chứng chỉ riêng và trong mỗi kết nối, cả hai bên đều kiểm tra chứng chỉ của nhau. Điều này đảm bảo xác thực các dịch vụ và mã hóa lưu lượng bên trong cụm. Đây là cách mà Istio hoạt động với proxy Envoy sidecar.
# Go: gRPC-server với 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)
}
// Tạo server với mTLS
creds := createMTLSCredentials()
server := grpc.NewServer(grpc.Creds(creds))
Mẫu 3: TLS Passthrough
Proxy hoạt động ở cấp độ TCP và không giải mã lưu lượng — chỉ đơn giản là chuyển tiếp các byte đã được mã hóa đến backend. Đây là tùy chọn đơn giản nhất từ góc độ proxy, nhưng nó sẽ mất khả năng phân tích lưu lượng gRPC, thêm tiêu đề hoặc thực hiện cân bằng tải ở cấp độ yêu cầu.
Cân bằng tải cho các luồng gRPC: đặc điểm và giải pháp
Cân bằng tải cho gRPC là một nhiệm vụ không đơn giản, và đây là lý do. Trong HTTP/1.1, mỗi yêu cầu là một kết nối TCP riêng biệt (hoặc kết nối từ pool), và bộ cân bằng tải dễ dàng phân phối các yêu cầu cho các backend. Trong HTTP/2, một kết nối TCP đa hợp nhiều luồng — nếu bộ cân bằng tải hoạt động ở cấp độ TCP, tất cả các luồng của một kết nối sẽ được gửi đến một backend duy nhất.
Đối với gRPC, điều này có nghĩa là: nếu khách hàng đã thiết lập một kết nối HTTP/2 và gửi qua đó 100 yêu cầu RPC, khi cân bằng tải TCP, tất cả 100 yêu cầu sẽ được xử lý bởi một instance backend. Các backend khác sẽ không hoạt động. Giải pháp là cân bằng tải ở cấp độ luồng HTTP/2 (cân bằng tải L7).
Thuật toán cân bằng tải cho gRPC
| Thuật toán | Phù hợp cho gRPC | Nhận xét |
|---|---|---|
| Round Robin | ✅ Có | Tốt cho các RPC đơn với thời gian xử lý tương tự nhau |
| Least Connection | ✅ Lựa chọn tốt nhất | Xem xét các luồng đang hoạt động, phân phối tải đồng đều |
| Random | ⚠️ Có điều kiện | Hoạt động tốt khi có nhiều yêu cầu, không đồng đều khi ít |
| IP Hash | ❌ Kém | Gắn kết khách hàng với một backend, không có ý nghĩa trong L7 |
| Pick First (gRPC tích hợp sẵn) | ❌ Không cho sản xuất | Tất cả các yêu cầu đều đến máy chủ đầu tiên có sẵn |
Cân bằng tải phía khách hàng trong gRPC
gRPC hỗ trợ cân bằng tải phía khách hàng — khách hàng tự quyết định gửi yêu cầu đến máy chủ nào. Điều này giúp vượt qua vấn đề TCP multiplexing. Để phát hiện dịch vụ, sử dụng DNS với nhiều bản ghi A hoặc các resolver đặc biệt (Consul, etcd). Ví dụ cấu hình cân bằng tải phía khách hàng trong Go:
import (
"google.golang.org/grpc"
"google.golang.org/grpc/balancer/roundrobin"
)
// Khách hàng với cân bằng tải round-robin qua DNS
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"round_robin":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
// Khách hàng với least-connection (có sẵn trong gRPC >= 1.58)
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"least_request":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
Proxy bên ngoài cho gRPC: khi nào và tại sao cần thiết trong microservices
Ngoài các thành phần proxy nội bộ (Nginx, Envoy, HAProxy), trong kiến trúc microservices đôi khi cần sử dụng các máy chủ proxy bên ngoài — ví dụ, để định tuyến lưu lượng qua các khu vực cụ thể, vượt qua các hạn chế mạng hoặc cách ly các kết nối ra ngoài. Hãy xem xét các kịch bản chính.
Kịch bản 1: Microservices phân bố địa lý
Nếu các microservices của bạn nằm ở các khu vực khác nhau (ví dụ, một phần ở Châu Âu, một phần ở Hoa Kỳ), và bạn cần kiểm soát địa chỉ IP nào được sử dụng để thiết lập các kết nối gRPC giữa các khu vực, các proxy bên ngoài có thể giúp tổ chức định tuyến dự đoán. Các proxy trung tâm dữ liệu là lựa chọn phù hợp — chúng cung cấp địa chỉ IP ổn định và tốc độ kết nối cao, điều này rất quan trọng cho gRPC với độ nhạy cảm với độ trễ.
Kịch bản 2: Cách ly lưu lượng ra ngoài
Trong một số môi trường doanh nghiệp, toàn bộ lưu lượng ra ngoài phải đi qua proxy doanh nghiệp. Đối với các khách hàng gRPC cần truy cập các dịch vụ gRPC bên ngoài (ví dụ, Google Cloud APIs sử dụng gRPC), điều này tạo ra khó khăn. Giải pháp là thiết lập tunneling CONNECT qua proxy doanh nghiệp.
Ví dụ về cấu hình khách hàng gRPC để hoạt động qua proxy HTTP CONNECT trong Go:
import (
"net"
"net/http"
"golang.org/x/net/proxy"
"google.golang.org/grpc"
)
// Sử dụng proxy SOCKS5 cho 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),
)
Kịch bản 3: Kiểm tra và phát triển
Khi phát triển microservices, thường cần kiểm tra hành vi của các dịch vụ từ các môi trường mạng khác nhau — kiểm tra cách dịch vụ phản hồi khi có độ trễ cao, hoặc kiểm tra logic phụ thuộc vào địa lý. Đối với những nhiệm vụ như vậy, proxy dân cư rất tiện lợi, cho phép mô phỏng các yêu cầu từ các khu vực cụ thể với địa chỉ IP thực tế của người dùng tại nhà.
Các lỗi thường gặp khi cấu hình gRPC qua proxy và cách khắc phục
Hãy xem xét những vấn đề phổ biến nhất mà các nhà phát triển gặp phải khi cấu hình gRPC qua proxy, cùng với các cách giải quyết cụ thể.
Lỗi 1: "transport: received the unexpected content-type"
Triệu chứng:
Khách hàng nhận được lỗi transport: received the unexpected content-type "text/html; charset=utf-8"
Nguyên nhân: Proxy đã trả về một trang HTML với lỗi (ví dụ, 502 Bad Gateway) thay vì phản hồi gRPC. Khách hàng gRPC không thể xử lý HTML và đưa ra lỗi này.
Giải pháp: Đảm bảo rằng backend có sẵn. Thêm xử lý lỗi gRPC ở cấp độ proxy (như đã chỉ ra trong ví dụ Nginx ở trên với khối error502grpc).
Lỗi 2: Kết nối bị ngắt sau 60-120 giây
Triệu chứng:
Các kết nối gRPC streaming bị đóng đột ngột với lỗi UNAVAILABLE: transport is closing sau khoảng thời gian tương tự nhau.
Nguyên nhân: Proxy đóng các kết nối idle theo thời gian chờ. Các giá trị cổ điển: AWS ELB — 60 giây, Nginx mặc định — 60 giây.
Giải pháp 1: Tăng thời gian chờ trên proxy (như đã chỉ ra trong các ví dụ ở trên).
Giải pháp 2: Cấu hình keepalive ở phía khách hàng gRPC:
import "google.golang.org/grpc/keepalive"
kaParams := keepalive.ClientParameters{
Time: 30 * time.Second, // Ping mỗi 30 giây
Timeout: 10 * time.Second, // Chờ phản hồi 10 giây
PermitWithoutStream: true, // Ping ngay cả khi không có RPC hoạt động
}
conn, err := grpc.Dial(
"grpc-service:50051",
grpc.WithKeepaliveParams(kaParams),
grpc.WithTransportCredentials(creds),
)
Lỗi 3: HTTP/2 không đồng bộ (ALPN failure)
Triệu chứng:
Lỗi transport: failed to dial: context deadline exceeded hoặc no application protocol
Nguyên nhân: Proxy hoặc thiết bị trung gian không hỗ trợ ALPN (Application-Layer Protocol Negotiation) hoặc không có h2 trong danh sách các giao thức được hỗ trợ.
Giải pháp: Đảm bảo rằng trong cấu hình TLS của proxy, giao thức h2 được chỉ định rõ ràng: alpn h2,http/1.1 (HAProxy) hoặc listen 443 ssl http2 (Nginx).
Lỗi 4: Streaming bị treo — dữ liệu không đến
Triệu chứng:
Streaming từ máy chủ hoạt động trên backend (thấy trong log), nhưng khách hàng không nhận được thông điệp cho đến khi luồng hoàn tất.
Nguyên nhân: Proxy bộ đệm phản hồi và chỉ gửi đến khách hàng sau khi hoàn tất. Đây là vấn đề điển hình cho các proxy được cấu hình với proxy_buffering on.
Giải pháp cho Nginx:
location / {
grpc_pass grpc://backend;
# Tắt bộ đệm cho các luồng gRPC
grpc_buffer_size 0;
# Hoặc cho proxy_pass thông thường:
proxy_buffering off;
proxy_cache off;
}
Danh sách kiểm tra chẩn đoán gRPC qua proxy
✅ Danh sách kiểm tra: chẩn đoán gRPC-proxy
- Proxy hỗ trợ HTTP/2 (kiểm tra qua
curl --http2 -v) - ALPN h2 được bật trong cấu hình TLS của proxy
- Thời gian chờ của khách hàng và máy chủ được thiết lập ít nhất 300 giây
- Bộ đệm phản hồi bị tắt cho các endpoint gRPC
- Cấu hình keepalive gRPC ở phía khách hàng (Thời gian: 30s, Thời gian chờ: 10s)
- Lỗi backend được trả về dưới dạng trạng thái gRPC, không phải mã HTTP
- Kiểm tra sức khỏe sử dụng Giao thức Kiểm tra Sức khỏe gRPC
- Cân bằng tải hoạt động ở L7 (luồng HTTP/2), không phải L4 (TCP)
Kết luận
Cấu hình gRPC qua proxy yêu cầu hiểu những khác biệt chính giữa HTTP/2 và HTTP/1.1: đa hợp luồng, kết nối lâu dài, HTTP/2 trailers và đồng bộ ALPN. Các proxy HTTP cổ điển mà không có cấu hình đặc biệt sẽ không hoạt động với gRPC — cần một proxy L7 hỗ trợ HTTP/2 (Nginx 1.13.10+, Envoy, HAProxy 1.9.2+) hoặc tunneling TCP CONNECT.
Đối với môi trường sản xuất, Envoy được khuyến nghị — nó được tạo ra đặc biệt cho kiến trúc microservices, có hỗ trợ gRPC bản địa, có khả năng thu thập các metrics chi tiết cho mỗi phương thức RPC và là nền tảng cho hầu hết các giải pháp service mesh. Nginx là lựa chọn tốt nếu bạn đã sử dụng nó như một API Gateway và muốn thêm hỗ trợ gRPC mà không cần giới thiệu một thành phần mới. HAProxy sẽ phù hợp nếu hiệu suất là yếu tố quan trọng và bạn đã quen thuộc với cấu hình của nó.
Bất kể proxy nào được chọn, ba quy tắc vẫn không thay đổi: tăng thời gian chờ cho các luồng lâu dài, tắt bộ đệm phản hồi và cấu hình keepalive ở phía khách hàng. Ba cài đặt này giải quyết 80% các vấn đề với gRPC qua proxy.
Nếu trong kiến trúc của bạn, các dịch vụ gRPC cần tương tác qua các mạng bên ngoài hoặc bạn cần định tuyến lưu lượng qua các khu vực cụ thể, hãy xem xét proxy trung tâm dữ liệu — chúng cung cấp địa chỉ IP ổn định, độ trễ thấp và băng thông cao, điều này đặc biệt quan trọng cho gRPC với giao thức nhị phân và độ nhạy cảm với độ trễ.
```