gRPC는 Google에서 개발한 고성능 RPC 프레임워크로, HTTP/2 위에서 작동하며 서비스 간 상호작용의 사실상 표준이 되고 있습니다. 그러나 gRPC 트래픽을 프록시를 통해 전송하려고 하면 즉시 문제가 발생합니다. 대부분의 전통적인 프록시 서버는 HTTP/2 및 장기 스트리밍 연결을 처리할 수 없습니다. 이 기사에서는 아키텍처 선택에서 Nginx, Envoy 및 HAProxy의 구체적인 구성까지 gRPC를 프록시를 통해 올바르게 설정하는 방법을 살펴보겠습니다.
gRPC가 일반 프록시와 잘 작동하지 않는 이유
문제를 이해하기 위해서는 gRPC의 내부 구조를 이해해야 합니다. 이 프로토콜은 HTTP/2를 전송 계층으로 사용하며, 이는 HTTP/1.1 위의 일반적인 REST와 근본적으로 다릅니다. 대부분의 기업 프록시, 방화벽 및 로드 밸런서는 HTTP/1.1 시대에 설계되었기 때문에 HTTP/2의 다중화된 스트림을 처리할 수 없습니다.
다음은 전통적인 HTTP 프록시를 통해 gRPC를 전송하려고 할 때 직면할 수 있는 구체적인 문제들입니다:
- HTTP/1.1로 다운그레이드. 많은 프록시가 프로토콜 버전을 자동으로 낮춥니다. gRPC는 HTTP/2를 요구합니다 — 없으면 연결이 설정되지 않고 클라이언트는
UNAVAILABLE오류를 받습니다. - 장기 연결의 끊김. gRPC는 서버 측 및 양방향 스트리밍을 적극적으로 사용합니다. 공격적인 타임아웃을 가진 프록시(특히 AWS ELB Classic 및 일부 Squid 버전)는 60초 이상 데이터를 전송하지 않는 연결을 끊습니다.
- Content-Type 문제. gRPC는
Content-Type: application/grpc헤더를 사용합니다. 이 유형을 모르는 프록시는 요청을 거부하거나 본문을 잘못 버퍼링할 수 있습니다. - 트레일러. gRPC는 호출 완료 상태를 전달하기 위해 HTTP/2 트레일러를 사용합니다. HTTP/1.1 프록시는 트레일러를 지원하지 않으므로 상태 정보가 손실됩니다.
- 본문 버퍼링. 일부 프록시는 응답 본문 전체를 클라이언트에 전달하기 전에 버퍼링합니다. 스트리밍 gRPC 호출의 경우, 이는 클라이언트가 스트림이 완료될 때까지 아무 메시지도 받지 못하게 됩니다.
핵심 결론:
gRPC를 프록시를 통해 작동시키려면 HTTP/2 종단 간 지원이 있는 프록시 또는 특별한 터널링 모드가 필요합니다. 일반적인 HTTP 프록시는 구성 수정 없이 적합하지 않습니다.
HTTP/2 터널링: 작동 방식
gRPC 트래픽을 프록시하는 데는 두 가지 근본적으로 다른 접근 방식이 있으며, 올바른 아키텍처 솔루션을 선택하기 위해 이들 간의 차이를 이해하는 것이 중요합니다.
접근 방식 1: HTTP/2 종단 간 (추천)
프록시는 HTTP/2를 이해하고 클라이언트와 백엔드 모두에 대해 HTTP/2 연결을 설정합니다. 개별 스트림을 분석하고 요청 수준에서 로드 밸런싱을 적용하며 헤더를 추가하고 TLS 종료를 수행할 수 있습니다. 이는 가장 기능적인 옵션으로, Envoy, Nginx(1.13.10 이상) 및 클라우드 제공업체의 gRPC 인식 로드 밸런서가 이렇게 작동합니다.
접근 방식 2: TCP 터널링 (CONNECT)
프록시는 HTTP/2 트래픽을 분석하지 않고 단순히 CONNECT 메서드를 통해 투명한 TCP 터널을 생성합니다. 클라이언트는 터널을 통해 백엔드와 직접 TLS 연결을 설정합니다. 프록시는 암호화된 바이트 스트림만 볼 수 있습니다. 이 방법은 설정이 더 간단하지만 gRPC 요청 수준에서 로드 밸런싱 및 헤더 추가 기능을 잃게 됩니다.
| 특징 | HTTP/2 종단 간 | TCP CONNECT 터널 |
|---|---|---|
| 요청 기반 로드 밸런싱 | ✅ 예 | ❌ 아니요 (TCP만 가능) |
| 프록시에서의 TLS 종료 | ✅ 예 | ❌ 아니요 |
| 헤더 추가 | ✅ 예 | ❌ 아니요 |
| 설정의 복잡성 | 중간 | 낮음 |
| 스트리밍 지원 | ✅ 완전 지원 | ✅ 완전 지원 |
| 가시성 (메트릭) | ✅ 상세 | ❌ TCP만 가능 |
Nginx를 gRPC 프록시로 설정하기
Nginx는 1.13.10 버전(2018년 2월)부터 gRPC 프록시를 지원합니다. 작동하려면 ngx_http_grpc_module 모듈이 필요하며, 이는 표준 빌드에 포함되어 있습니다. 중요한 점: Nginx는 클라이언트 측에서 HTTP/2를 지원하지만, 백엔드 측에서는 gRPC에 대해서만 HTTP/2를 사용하며, 일반 HTTP 업스트림은 HTTP/1.1로 작동합니다.
Nginx에서 gRPC 프록시의 기본 구성
server {
listen 443 ssl http2;
server_name grpc.example.com;
# TLS 인증서
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# 현대적인 TLS 매개변수
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# proxy_pass 대신 grpc_pass 지시어 사용
grpc_pass grpc://grpc_backend;
# 장기 스트림을 위한 타임아웃
grpc_read_timeout 3600s;
grpc_send_timeout 3600s;
grpc_connect_timeout 5s;
# 실제 클라이언트 IP 전달
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;
# HTTP/2 연결을 위한 Keepalive
keepalive 32;
}
몇 가지 중요한 세부 사항에 유의하십시오. 첫째, grpc_pass 지시어가 사용되며, proxy_pass가 아닙니다 — 이들은 서로 다른 모듈로 서로 다른 동작을 합니다. 둘째, grpc_read_timeout 및 grpc_send_timeout는 3600초(1시간)로 설정되어 있습니다 — 이는 데이터를 전송하지 않고 오랫동안 작동할 수 있는 서버 스트림에 중요합니다. 셋째, keepalive 32는 백엔드와의 HTTP/2 연결을 재사용할 수 있게 합니다.
암호화되지 않은 gRPC 구성 (grpc://)
server {
listen 80 http2;
server_name grpc-internal.example.com;
location / {
grpc_pass grpc://127.0.0.1:50051;
# gRPC 오류 처리
error_page 502 = /error502grpc;
}
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header content-length 0;
return 204;
}
}
error502grpc 블록은 중요한 세부 사항입니다: 백엔드가 사용할 수 없을 경우 올바른 gRPC 상태 UNAVAILABLE (14)를 반환하며, 이는 gRPC 클라이언트가 올바르게 처리할 수 없는 HTTP 502 대신입니다.
Envoy Proxy: 마이크로서비스에서 gRPC에 대한 최고의 선택
Envoy는 Lyft에서 마이크로서비스 아키텍처를 위해 개발되었으며, gRPC 지원이 가장 깊은 수준에서 구현되어 있습니다. Protocol Buffers를 이해하고 gRPC를 REST로 변환할 수 있으며, 각 RPC 메서드에 대한 상세한 메트릭을 수집하고, service mesh 솔루션인 Istio, AWS App Mesh 등에서 기반이 됩니다. 심각한 마이크로서비스 아키텍처를 구축하고 있다면, Envoy는 업계 표준입니다.
gRPC를 위한 Envoy의 기본 구성
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
이 구성의 주요 장점은 gRPC 서비스에 대한 라우팅(경로 접두사가 package.ServiceName 형식의 서비스 전체 이름과 일치함), UNAVAILABLE 상태에서 자동 재시도 및 grpc_stats 필터를 통한 gRPC 메트릭 수집입니다.
Envoy에서 gRPC-Web 트랜스코딩
Envoy의 주요 기능 중 하나는 내장된 gRPC-Web 트랜스코더입니다. 브라우저는 gRPC를 직접 지원하지 않기 때문에(HTTP/2 트레일러에 대한 Fetch API의 제한으로 인해) gRPC-Web 프로토콜이 사용됩니다. Envoy는 브라우저의 gRPC-Web 요청을 백엔드의 일반 gRPC로 자동 변환할 수 있습니다:
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와 gRPC: 로드 밸런싱 구성
HAProxy는 1.9.2 버전부터 gRPC를 지원합니다. TCP 또는 HTTP/2 수준에서 작동하며, gRPC 트래픽을 로드 밸런싱하고 헬스 체크를 수행할 수 있습니다. HAProxy는 이미 인프라에서 사용하고 있고 gRPC 지원을 추가하고 싶다면 좋은 선택입니다.
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
# 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
몇 가지 중요한 설정에 유의하십시오. alpn h2,http/1.1는 HAProxy가 TLS ALPN 협상을 통해 HTTP/2 및 HTTP/1.1 연결을 모두 수용하도록 지정합니다. timeout client 3600s 및 timeout server 3600s는 장기 gRPC 스트림에 매우 중요한 매개변수입니다. leastconn 알고리즘은 gRPC에 더 적합하며, 스트리밍 연결이 장기적이고 백엔드를 불균형하게 부하를 줄 수 있기 때문입니다.
gRPC를 위한 TLS 종료 및 종단 간 암호화
gRPC는 기본적으로 TLS 사용을 전제로 합니다 — 이는 사양의 일부입니다. 실제로 마이크로서비스 아키텍처에서는 TLS 종료를 어디에서 수행하고 구성 요소 간 암호화를 어떻게 조직할 것인지에 대한 질문이 발생합니다. 세 가지 주요 패턴이 있습니다.
패턴 1: 프록시에서 TLS 종료 (Edge TLS)
프록시는 클라이언트로부터 암호화된 트래픽을 수신하고 이를 복호화하여 백엔드에 암호화되지 않은 채널(또는 별도의 TLS)로 전달합니다. 이는 기업 네트워크에서 가장 일반적인 접근 방식입니다. 백엔드는 구성 단순화를 위해 grpc.Insecure()를 사용할 수 있습니다.
패턴 2: 종단 간 암호화 (mTLS)
상호 TLS(mTLS)는 서비스 메쉬의 표준입니다. 각 서비스는 고유한 인증서를 가지고 있으며, 연결 시 양측이 서로의 인증서를 확인합니다. 이는 서비스의 인증과 클러스터 내 트래픽 암호화를 보장합니다. 바로 이것이 Istio가 Envoy 사이드카 프록시와 함께 작동하는 방식입니다.
# Go: mTLS를 사용하는 gRPC 서버
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)
}
// mTLS를 사용하는 서버 생성
creds := createMTLSCredentials()
server := grpc.NewServer(grpc.Creds(creds))
패턴 3: TLS 패스스루
프록시는 TCP 수준에서 작동하며 트래픽을 복호화하지 않고 암호화된 바이트를 백엔드로 단순히 전달합니다. 이는 프록시 관점에서 가장 간단한 옵션이지만 gRPC 트래픽을 분석하거나 헤더를 추가하거나 요청 수준에서 로드 밸런싱을 수행할 수 있는 기능을 잃게 됩니다.
gRPC 스트림을 위한 로드 밸런싱: 특징 및 솔루션
gRPC를 위한 로드 밸런싱은 간단한 작업이 아니며, 그 이유는 다음과 같습니다. HTTP/1.1에서는 각 요청이 개별 TCP 연결(또는 풀에서의 연결)이며, 로드 밸런서는 요청을 백엔드에 쉽게 분배할 수 있습니다. 그러나 HTTP/2에서는 하나의 TCP 연결이 여러 스트림을 다중화합니다 — 만약 로드 밸런서가 TCP 수준에서 작동하면, 동일한 연결의 모든 스트림이 하나의 백엔드로 전달됩니다.
gRPC의 경우, 클라이언트가 하나의 HTTP/2 연결을 설정하고 그를 통해 100개의 RPC 요청을 전송하면, TCP 로드 밸런싱이 이루어질 경우 모든 100개의 요청이 하나의 백엔드 인스턴스에 의해 처리됩니다. 나머지 백엔드는 유휴 상태가 됩니다. 해결책은 HTTP/2 스트림 수준에서 로드 밸런싱(L7 로드 밸런싱)입니다.
gRPC를 위한 로드 밸런싱 알고리즘
| 알고리즘 | gRPC에 적합 | 비고 |
|---|---|---|
| 라운드 로빈 | ✅ 예 | 비슷한 처리 시간을 가진 단일 RPC에 적합 |
| 최소 연결 | ✅ 최고의 선택 | 활성 스트림을 고려하여 부하를 고르게 분배 |
| 무작위 | ⚠️ 조건부 | 많은 요청이 있을 때 작동하지만 적을 때는 불균형 |
| IP 해시 | ❌ 나쁨 | 클라이언트를 하나의 백엔드에 고정시키며 L7에서는 의미가 없음 |
| 첫 번째 선택 (gRPC 내장) | ❌ 프로덕션에 적합하지 않음 | 모든 요청이 첫 번째 사용 가능한 서버로 전송됨 |
gRPC 클라이언트의 로드 밸런싱
gRPC는 클라이언트 로드 밸런싱을 지원합니다 — 클라이언트가 요청을 보낼 서버를 스스로 결정합니다. 이는 TCP 다중화 문제를 우회할 수 있게 합니다. 서비스 발견을 위해 여러 A 레코드가 있는 DNS 또는 특별한 리졸버(Consul, etcd)를 사용합니다. Go에서 클라이언트 로드 밸런싱을 설정하는 예:
import (
"google.golang.org/grpc"
"google.golang.org/grpc/balancer/roundrobin"
)
// DNS를 통한 라운드 로빈 로드 밸런싱 클라이언트
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"round_robin":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
// 최소 연결을 통한 클라이언트 (gRPC >= 1.58에서 사용 가능)
conn, err := grpc.Dial(
"dns:///grpc-service.internal:50051",
grpc.WithDefaultServiceConfig(
`{"loadBalancingConfig": [{"least_request":{}}]}`
),
grpc.WithTransportCredentials(creds),
)
gRPC를 위한 외부 프록시: 필요성과 이유
내부 프록시 구성 요소(Nginx, Envoy, HAProxy) 외에도 마이크로서비스 아키텍처에서는 특정 지역을 통한 트래픽 라우팅, 네트워크 제한 우회 또는 아웃바운드 연결 격리를 위해 외부 프록시 서버를 사용할 필요가 있을 수 있습니다. 주요 시나리오를 살펴보겠습니다.
시나리오 1: 지리적으로 분산된 마이크로서비스
마이크로서비스가 서로 다른 지역(예: 일부는 유럽, 일부는 미국)에 위치하고 있으며, gRPC 연결이 어떤 IP 주소를 통해 설정되는지를 제어해야 하는 경우, 외부 프록시가 예측 가능한 라우팅을 조직하는 데 도움이 될 수 있습니다. 이러한 작업에는 데이터 센터 프록시가 적합합니다 — 이들은 안정적인 IP 주소와 높은 연결 속도를 제공하며, 이는 지연에 민감한 gRPC에 매우 중요합니다.
시나리오 2: 아웃바운드 트래픽 격리
일부 기업 환경에서는 모든 아웃바운드 트래픽이 기업 프록시를 통해 전달되어야 합니다. 외부 gRPC 서비스(예: gRPC를 사용하는 Google Cloud API)에 접근해야 하는 gRPC 클라이언트에게는 이러한 요구 사항이 복잡성을 초래합니다. 해결책은 기업 프록시를 통한 CONNECT 터널을 설정하는 것입니다.
Go에서 HTTP CONNECT 프록시를 통해 작동하는 gRPC 클라이언트를 설정하는 예:
import (
"net"
"net/http"
"golang.org/x/net/proxy"
"google.golang.org/grpc"
)
// gRPC를 위한 SOCKS5 프록시 사용
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),
)
시나리오 3: 테스트 및 개발
마이크로서비스를 개발할 때는 종종 다양한 네트워크 환경에서 서비스의 동작을 테스트해야 합니다 — 높은 지연에서 서비스가 어떻게 응답하는지 확인하거나 geo 의존 로직을 테스트하는 것입니다. 이러한 작업에는 특정 지역에서 실제 가정 사용자의 IP로 요청을 시뮬레이션할 수 있는 주거용 프록시가 유용합니다.
gRPC를 프록시를 통해 설정할 때의 일반적인 오류 및 해결 방법
gRPC를 프록시를 통해 설정할 때 개발자들이 자주 겪는 문제와 그 해결 방법을 살펴보겠습니다.
오류 1: "transport: received the unexpected content-type"
증상:
클라이언트가 transport: received the unexpected content-type "text/html; charset=utf-8" 오류를 받습니다.
원인: 프록시가 gRPC 응답 대신 오류가 있는 HTML 페이지(예: 502 Bad Gateway)를 반환했습니다. gRPC 클라이언트는 HTML을 처리할 수 없으므로 이 오류가 발생합니다.
해결 방법: 백엔드가 사용 가능한지 확인하십시오. 프록시 레벨에서 gRPC 오류 처리를 추가하십시오(위의 Nginx 예제에서 error502grpc 블록과 같이).
오류 2: 60-120초 후 연결이 끊어짐
증상:
스트리밍 gRPC 연결이 약 60-120초 후에 UNAVAILABLE: transport is closing 오류와 함께 예기치 않게 종료됩니다.
원인: 프록시가 유휴 연결을 타임아웃으로 종료합니다. 일반적인 값: AWS ELB — 60초, Nginx 기본값 — 60초.
해결 방법 1: 프록시에서 타임아웃을 늘리십시오(위의 예제에서 보여준 대로).
해결 방법 2: gRPC 클라이언트 측에서 keepalive를 설정하십시오:
import "google.golang.org/grpc/keepalive"
kaParams := keepalive.ClientParameters{
Time: 30 * time.Second, // 30초마다 핑
Timeout: 10 * time.Second, // 10초 동안 응답 대기
PermitWithoutStream: true, // 활성 RPC 없이도 핑
}
conn, err := grpc.Dial(
"grpc-service:50051",
grpc.WithKeepaliveParams(kaParams),
grpc.WithTransportCredentials(creds),
)
오류 3: HTTP/2 협상이 실패함 (ALPN failure)
증상:
오류 transport: failed to dial: context deadline exceeded 또는 no application protocol
원인: 프록시 또는 중간 장비가 ALPN(Application-Layer Protocol Negotiation)을 지원하지 않거나 h2가 지원 프로토콜 목록에 포함되어 있지 않습니다.
해결 방법: 프록시의 TLS 구성에서 h2 프로토콜이 명시적으로 지정되어 있는지 확인하십시오: alpn h2,http/1.1 (HAProxy) 또는 listen 443 ssl http2 (Nginx).
오류 4: 스트리밍이 멈춤 — 데이터가 오지 않음
증상:
서버 측 스트림이 백엔드에서 작동하고 있지만(로그에서 확인 가능), 클라이언트는 스트림이 완료될 때까지 메시지를 받지 못합니다.
원인: 프록시가 응답을 버퍼링하고 완료된 후에만 클라이언트에게 전송합니다. 이는 proxy_buffering on으로 설정된 프록시에서 발생하는 일반적인 문제입니다.
Nginx에 대한 해결 방법:
location / {
grpc_pass grpc://backend;
# gRPC 스트림에 대한 버퍼링 비활성화
grpc_buffer_size 0;
# 또는 일반 proxy_pass의 경우:
proxy_buffering off;
proxy_cache off;
}
gRPC 프록시 진단 체크리스트
✅ 체크리스트: gRPC 프록시 진단
- 프록시가 HTTP/2를 지원합니다 (확인하려면
curl --http2 -v사용) - 프록시의 TLS 구성에 h2가 포함되어 있습니다
- 클라이언트 및 서버의 타임아웃이 최소 300초로 설정되어 있습니다
- gRPC 엔드포인트에 대한 응답 버퍼링이 비활성화되어 있습니다
- 클라이언트에서 gRPC keepalive가 설정되어 있습니다 (Time: 30s, Timeout: 10s)
- 백엔드 오류가 HTTP 코드가 아닌 gRPC 상태로 반환됩니다
- 헬스 체크가 gRPC 헬스 체크 프로토콜을 사용합니다
- 로드 밸런싱이 L7 (HTTP/2 스트림)에서 작동하며 L4 (TCP)가 아닙니다
결론
gRPC를 프록시를 통해 설정하려면 HTTP/2와 HTTP/1.1의 주요 차이점인 스트림 다중화, 장기 연결, HTTP/2 트레일러 및 ALPN 협상을 이해해야 합니다. 일반적인 HTTP 프록시는 gRPC와 함께 특별한 설정 없이 작동하지 않으며, HTTP/2를 지원하는 L7 프록시(Nginx 1.13.10 이상, Envoy, HAProxy 1.9.2 이상) 또는 TCP CONNECT 터널링이 필요합니다.
프로덕션 환경에서는 Envoy를 추천합니다 — 이는 마이크로서비스 아키텍처를 위해 설계되었으며, gRPC에 대한 네이티브 지원을 제공하고 각 RPC 메서드에 대한 상세한 메트릭을 수집하며 대부분의 서비스 메쉬 솔루션의 기반이 됩니다. Nginx는 이미 API 게이트웨이로 사용하고 있고 gRPC 지원을 추가하고 싶다면 좋은 선택입니다. HAProxy는 성능이 매우 중요하고 구성에 익숙하다면 적합합니다.
선택한 프록시와 관계없이 세 가지 규칙은 변하지 않습니다: 장기 스트림을 위한 타임아웃을 늘리고, 응답 버퍼링을 비활성화하며, 클라이언트에서 keepalive를 설정하십시오. 이 세 가지 설정은 gRPC를 프록시를 통해 설정할 때 발생하는 80%의 문제를 해결합니다.
아키텍처에서 gRPC 서비스가 외부 네트워크를 통해 상호작용해야 하거나 특정 지역을 통한 트래픽 라우팅이 필요한 경우, 데이터 센터 프록시를 고려하십시오 — 이들은 안정적인 IP 주소, 낮은 지연 및 높은 대역폭을 제공하여 gRPC의 이진 프로토콜 및 지연에 대한 민감성에 특히 중요합니다.
```