Series MapLesson 15 / 35
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Build CoreOrdered learning track

gRPC and HTTP/2

gRPC, HTTP/2, and Binary Protocol Proxying

Memahami gRPC over HTTP/2, h2, h2c, grpc_pass, ALPN, streaming gRPC, backend protocol, dan observability.

8 min read1569 words
PrevNext
Lesson 1535 lesson track07–19 Build Core
#grpc#http2#grpc-pass#alpn+2 more

Part 015 — gRPC, HTTP/2, and Binary Protocol Proxying

1. Tujuan Part Ini

Tidak semua traffic enterprise backend berbentuk REST/JSON di atas HTTP/1.1.

Di sistem modern, terutama sistem yang punya internal service-to-service communication atau high-throughput API, kamu bisa menemukan:

  • gRPC;
  • HTTP/2;
  • binary payload;
  • streaming request;
  • streaming response;
  • bidirectional streaming;
  • service-to-service RPC;
  • protobuf-based contract;
  • long-lived HTTP/2 connection;
  • ingress yang harus membedakan REST, WebSocket, dan gRPC.

Part ini membangun mental model supaya kamu tidak memperlakukan gRPC seperti REST biasa.

REST/JAX-RS biasanya terlihat seperti ini:

HTTP request
  method: GET/POST/PUT/DELETE
  path: /quotes/{id}
  body: JSON
  response: JSON

gRPC terlihat berbeda:

HTTP/2 request
  method: POST
  path: /package.Service/Method
  content-type: application/grpc
  body: binary protobuf frames
  response: binary protobuf frames + grpc-status

Masalah besar di production muncul ketika salah satu layer menganggap gRPC sebagai HTTP biasa.

Contoh symptom:

REST endpoint sehat, tetapi gRPC selalu gagal.
Client mendapat UNAVAILABLE.
Ingress mengembalikan 502.
gRPC streaming putus setelah idle timeout.
Backend mendukung h2c, tetapi NGINX berbicara HTTP/1.1.
TLS termination berhasil, tetapi ALPN tidak negotiate h2.
Health check HTTP biasa sukses, tetapi gRPC call gagal.

Target part ini adalah membuat kamu mampu membaca, mereview, dan men-debug konfigurasi NGINX untuk gRPC/HTTP/2 secara production-oriented.


2. Mental Model: gRPC Bukan Sekadar HTTP POST

Secara transport, gRPC berjalan di atas HTTP/2.

Secara aplikasi, gRPC adalah RPC framework dengan contract protobuf.

Secara observability, gRPC punya status sendiri yang tidak selalu sama dengan HTTP status.

Secara proxy, gRPC membutuhkan perlakuan berbeda dari REST.

Diagram sederhana:

sequenceDiagram participant C as gRPC Client participant LB as L4/L7 Load Balancer participant N as NGINX / Ingress participant S as gRPC Backend Service C->>LB: TLS + ALPN h2 LB->>N: HTTP/2 or TCP pass-through N->>S: grpc_pass to backend S-->>N: HTTP/2 frames + grpc-status N-->>C: gRPC response stream

Yang penting:

gRPC requires HTTP/2 semantics.
HTTP/2 is connection-oriented and multiplexed.
gRPC status lives in trailers.
Streaming changes timeout and buffering behavior.
A successful HTTP response can still carry failed grpc-status.

Jadi saat debugging, jangan hanya tanya:

HTTP status-nya apa?

Tanya juga:

Protocol-nya HTTP/2 atau HTTP/1.1?
ALPN negotiate h2 atau tidak?
Content-Type application/grpc atau bukan?
grpc-status apa?
Trailers sampai ke client atau hilang?
Timeout terjadi di stream atau connect?

3. REST/JAX-RS vs gRPC Traffic

Dalam konteks Java backend, kamu mungkin melihat kombinasi:

External API     -> REST/JAX-RS
Internal RPC     -> gRPC
Partner API      -> REST/JSON
High-throughput  -> gRPC/protobuf
Legacy client    -> HTTP/1.1 REST

Perbedaan praktis:

AreaREST/JAX-RSgRPC
ProtocolHTTP/1.1 atau HTTP/2HTTP/2
PayloadJSON/XML/textprotobuf binary
MethodGET/POST/PUT/DELETEbiasanya POST
Pathresource-orientedservice/method-oriented
StatusHTTP statusHTTP status + grpc-status
Streamingoptional/manualfirst-class
Browser supportnative untuk RESTperlu gRPC-Web untuk browser
Debuggingcurl mudahgrpcurl lebih tepat
Proxy directiveproxy_passgrpc_pass

Kesalahan umum adalah menyamakan gRPC dengan REST karena terlihat seperti HTTP POST.

Secara NGINX, ini berbeda.

REST proxy:

location /api/ {
    proxy_pass http://java_rest_backend;
}

gRPC proxy:

location /package.Service/ {
    grpc_pass grpc://grpc_backend;
}

Untuk upstream TLS:

location /package.Service/ {
    grpc_pass grpcs://grpc_backend;
}

4. HTTP/2 Concepts yang Relevan untuk NGINX

HTTP/2 memperkenalkan beberapa konsep yang penting untuk production debugging.

4.1 Multiplexing

Satu TCP connection bisa membawa banyak stream.

1 TCP connection
  stream 1 -> RPC A
  stream 3 -> RPC B
  stream 5 -> RPC C

Dampaknya:

  • connection count tidak sama dengan request concurrency;
  • satu koneksi bermasalah bisa memengaruhi banyak stream;
  • load balancing per connection bisa berbeda efeknya dari load balancing per request;
  • observability harus melihat request/stream, bukan hanya connection.

4.2 Header Compression

HTTP/2 menggunakan header compression.

Dampak praktis untuk backend engineer tidak sebesar timeout/routing, tetapi tetap penting saat melihat wire-level debugging.

4.3 Binary Framing

HTTP/2 tidak berbentuk plain text seperti HTTP/1.1.

Ini alasan kenapa debugging dengan telnet atau membaca raw payload tidak cukup.

Gunakan:

grpcurl
curl --http2
openssl s_client -alpn h2
nghttp

4.4 Trailers

gRPC banyak mengandalkan trailers untuk membawa status akhir.

Contoh konsep:

HTTP/2 response headers
response messages
response trailers:
  grpc-status: 0
  grpc-message: OK

Jika proxy, gateway, atau observability pipeline tidak memahami trailers, hasil debugging bisa menyesatkan.


5. h2, h2c, TLS, and ALPN

Ada dua mode penting:

h2   = HTTP/2 over TLS
h2c  = HTTP/2 cleartext tanpa TLS

Di edge publik, biasanya:

client -> TLS -> ALPN h2 -> NGINX

Di internal network, variasinya bisa:

NGINX -> h2c -> gRPC backend
NGINX -> TLS h2 -> gRPC backend
NGINX -> Kubernetes Service -> Pod gRPC port

ALPN adalah mekanisme TLS untuk memilih protocol seperti h2 atau http/1.1.

Jika client ingin gRPC tetapi ALPN tidak menghasilkan h2, request bisa gagal sebelum sampai ke aplikasi.

Debug command:

openssl s_client -connect api.example.com:443 -alpn h2 -servername api.example.com

Yang dicari:

ALPN protocol: h2

Jika hasilnya:

ALPN protocol: http/1.1

maka gRPC native kemungkinan tidak berjalan seperti yang diharapkan.


6. NGINX gRPC Proxying Model

NGINX menyediakan modul HTTP gRPC untuk meneruskan request ke gRPC server.

Mental model:

client speaks HTTP/2 gRPC
NGINX accepts request
NGINX maps location
NGINX forwards using grpc_pass
backend receives gRPC request
backend returns gRPC response/trailers
NGINX forwards response to client

Contoh basic:

http {
    upstream quote_grpc_backend {
        server quote-service:9090;
    }

    server {
        listen 443 ssl http2;
        server_name grpc.example.com;

        ssl_certificate     /etc/nginx/tls/tls.crt;
        ssl_certificate_key /etc/nginx/tls/tls.key;

        location /quote.v1.QuoteService/ {
            grpc_pass grpc://quote_grpc_backend;
        }
    }
}

Untuk upstream TLS:

location /quote.v1.QuoteService/ {
    grpc_ssl_server_name on;
    grpc_pass grpcs://quote-grpc.internal:9443;
}

Perhatikan perbedaannya:

proxy_pass -> HTTP upstream
grpc_pass  -> gRPC upstream

Jangan mengganti grpc_pass dengan proxy_pass kecuali kamu benar-benar sedang menggunakan gRPC-Web atau translation layer lain.


7. Kubernetes Ingress untuk gRPC

Di Kubernetes, gRPC biasanya diatur melalui annotation backend protocol.

Contoh umum pada ingress-nginx community controller:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: quote-grpc
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - grpc.example.com
      secretName: grpc-example-tls
  rules:
    - host: grpc.example.com
      http:
        paths:
          - path: /quote.v1.QuoteService
            pathType: Prefix
            backend:
              service:
                name: quote-grpc-service
                port:
                  number: 9090

Untuk backend TLS, annotation bisa berbeda tergantung controller.

Contoh konseptual:

nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"

Hal yang harus diverifikasi:

Controller apa yang digunakan?
Annotation ini didukung oleh controller tersebut?
Apakah value-nya GRPC, GRPCS, HTTP, HTTPS, atau AUTO?
Apakah service port benar?
Apakah backend benar-benar berbicara gRPC di port itu?

Jangan copy annotation dari internet tanpa memverifikasi controller.

NGINX Inc controller dan community ingress-nginx tidak selalu punya annotation, defaults, dan behavior yang sama.


8. Path Routing untuk gRPC

gRPC path biasanya berbentuk:

/package.Service/Method

Contoh:

/quote.v1.QuoteService/CreateQuote
/quote.v1.QuoteService/GetQuote
/quote.v1.QuoteService/StreamQuoteStatus

Ingress path yang aman biasanya menggunakan prefix service:

path: /quote.v1.QuoteService
pathType: Prefix

Pitfall:

path: /quote

Ini mungkin tidak match request gRPC sebenarnya.

Pitfall lain:

nginx.ingress.kubernetes.io/rewrite-target: /

Rewrite yang umum untuk REST bisa menghancurkan path gRPC.

Jika NGINX mengubah:

/quote.v1.QuoteService/GetQuote

menjadi:

/GetQuote

backend gRPC bisa mengembalikan unimplemented method atau unknown service.

Rule praktis:

Untuk gRPC, hindari rewrite kecuali kamu tahu persis efeknya terhadap fully-qualified service/method path.

9. Timeout untuk gRPC

gRPC punya karakter yang berbeda dari REST biasa.

Ada RPC pendek:

CreateQuote -> response cepat

Ada streaming panjang:

SubscribeOrderStatus -> stream event selama menit/jam

NGINX timeout yang relevan mirip dengan proxy timeout, tetapi directive gRPC berbeda:

grpc_connect_timeout 5s;
grpc_send_timeout    60s;
grpc_read_timeout    60s;

Untuk streaming, grpc_read_timeout terlalu pendek bisa memutus stream saat tidak ada data dalam interval tertentu.

Masalah umum:

Backend stream masih sehat.
Tidak ada event selama 60 detik.
NGINX menganggap upstream idle.
Connection ditutup.
Client melihat UNAVAILABLE atau stream terminated.

Solusi konseptual:

  • align timeout client, load balancer, NGINX, backend;
  • gunakan keepalive/ping jika stack mendukung;
  • bedakan timeout RPC pendek dan streaming endpoint;
  • observasi idle disconnect pattern.

Jangan menaikkan timeout global secara membabi buta.

Lebih aman:

short RPC host/path -> timeout pendek
streaming RPC host/path -> timeout lebih panjang dan terkontrol

10. Retry dan gRPC Safety

Pada REST, retry sering dikaitkan dengan method idempotency.

Pada gRPC, retry safety harus dilihat dari method semantics.

Contoh:

GetQuote       -> biasanya aman di-retry
CreateQuote    -> belum tentu aman
SubmitOrder    -> berisiko duplicate side effect
StreamStatus   -> retry bisa reconnect, tetapi perlu resume semantics

NGINX punya konsep next upstream untuk gRPC.

Contoh konseptual:

grpc_next_upstream error timeout;
grpc_next_upstream_tries 2;

Risiko:

Client mengirim request mutating.
NGINX sudah meneruskan ke backend A.
Backend A memproses tapi response gagal.
NGINX retry ke backend B.
Side effect bisa terjadi dua kali.

Rule produksi:

Retry di proxy harus conservative.
Retry mutating RPC harus dikontrol oleh idempotency key atau application-level semantics.

Untuk quote/order system, ini krusial.

Duplikasi submit order lebih berbahaya daripada transient failure yang terlihat oleh client.


11. gRPC Status vs HTTP Status

gRPC membawa status aplikasi melalui grpc-status.

Contoh:

grpc-status: 0   -> OK
grpc-status: 5   -> NOT_FOUND
grpc-status: 13  -> INTERNAL
grpc-status: 14  -> UNAVAILABLE

HTTP status bisa tetap 200 untuk respons gRPC yang secara aplikasi gagal.

Contoh:

HTTP/2 200
grpc-status: 5

Artinya secara HTTP transport berhasil, tetapi RPC mengembalikan NOT_FOUND.

Jangan membuat dashboard gRPC hanya berdasarkan HTTP 5xx.

Minimal observability harus bisa melihat:

http status
grpc-status
grpc-message
upstream connect time
upstream response time
request duration
method/service name
client identity jika ada

Jika log NGINX tidak menangkap grpc-status, kamu harus menambah observability di backend atau gateway layer yang memahami gRPC.


12. Streaming gRPC

gRPC mendukung beberapa pola:

Unary RPC              -> one request, one response
Server streaming       -> one request, many responses
Client streaming       -> many requests, one response
Bidirectional streaming -> many requests, many responses

Setiap pola punya konsekuensi proxy.

Unary RPC mirip request-response pendek.

Server streaming mirip SSE tetapi berbasis HTTP/2/gRPC.

Bidirectional streaming lebih sensitif terhadap:

  • idle timeout;
  • connection reset;
  • flow control;
  • max concurrent streams;
  • long-lived connection draining;
  • rolling deployment;
  • load balancer behavior.

Production concern:

Apakah deployment memutus stream?
Apakah client punya reconnect logic?
Apakah reconnect aman?
Apakah server punya resume token?
Apakah NGINX dan cloud LB timeout selaras?

Tanpa jawaban ini, streaming endpoint akan menjadi sumber incident yang sulit direproduksi.


13. Health Check untuk gRPC

HTTP health check biasa:

GET /health

Belum tentu cukup untuk gRPC service.

Kondisi buruk:

/health HTTP OK
port gRPC salah
protobuf service tidak terdaftar
HTTP/2 tidak aktif
backend protocol mismatch
gRPC method selalu UNIMPLEMENTED

Untuk gRPC, pertimbangkan:

  • gRPC health checking protocol;
  • grpcurl smoke test;
  • application-level unary RPC lightweight;
  • separate readiness for gRPC listener;
  • Kubernetes readiness probe yang benar;
  • ingress smoke test setelah rollout.

Contoh debug:

grpcurl -plaintext quote-grpc-service.default.svc.cluster.local:9090 list

Untuk TLS:

grpcurl -authority grpc.example.com grpc.example.com:443 list

Jika reflection tidak diaktifkan, gunakan proto descriptor atau test method khusus.


14. Observability untuk gRPC di NGINX

Access log REST biasa sering berisi:

method path status request_time upstream_response_time

Untuk gRPC, path mengandung service dan method.

Contoh:

POST /quote.v1.QuoteService/CreateQuote
POST /quote.v1.QuoteService/StreamQuoteStatus

Log format perlu membantu menjawab:

Service/method mana yang lambat?
HTTP status apa?
grpc-status apa?
Upstream mana yang dipilih?
Berapa durasi request/stream?
Apakah client disconnect?
Apakah upstream timeout?

Minimal log fields:

log_format grpc_json escape=json
'{'
  '"time":"$time_iso8601",'
  '"request_id":"$request_id",'
  '"remote_addr":"$remote_addr",'
  '"host":"$host",'
  '"method":"$request_method",'
  '"uri":"$request_uri",'
  '"status":$status,'
  '"request_time":$request_time,'
  '"upstream_addr":"$upstream_addr",'
  '"upstream_status":"$upstream_status",'
  '"upstream_response_time":"$upstream_response_time",'
  '"content_type":"$sent_http_content_type",'
  '"user_agent":"$http_user_agent"'
'}';

Catatan: capture grpc-status dari trailers tidak selalu sesederhana response header biasa. Validasi kemampuan controller/logging stack yang dipakai.


15. Common gRPC Proxy Failures

15.1 Backend Protocol Mismatch

Symptom:

502 Bad Gateway
upstream prematurely closed connection
client gets UNAVAILABLE

Kemungkinan:

NGINX memakai proxy_pass, backend expect gRPC.
NGINX memakai grpc_pass, backend bukan gRPC.
Backend protocol HTTP/1.1, client expect HTTP/2.
Ingress annotation backend-protocol salah.

Debug:

kubectl describe ingress quote-grpc
kubectl get svc quote-grpc-service -o yaml
grpcurl -plaintext <service-dns>:9090 list

15.2 ALPN Tidak h2

Symptom:

gRPC client gagal negotiate protocol.
REST masih berhasil.

Debug:

openssl s_client -connect grpc.example.com:443 -servername grpc.example.com -alpn h2

Cari:

ALPN protocol: h2

15.3 Path Rewrite Merusak Service Name

Symptom:

grpc-status: 12 UNIMPLEMENTED
unknown service

Kemungkinan:

Ingress rewrite-target menghapus package.Service dari path.
Location match terlalu luas.
Regex path salah.

15.4 Timeout pada Streaming

Symptom:

stream putus setiap 60 detik
stream putus saat idle
client reconnect terus

Kemungkinan:

grpc_read_timeout terlalu pendek
cloud LB idle timeout lebih pendek
backend tidak mengirim heartbeat
client tidak mengirim keepalive

15.5 Health Check False Positive

Symptom:

Kubernetes readiness OK
HTTP health OK
gRPC call gagal

Kemungkinan:

readiness probe tidak mengecek gRPC listener
service port salah
backend protocol mismatch
reflection/test method tidak tersedia

16. Security Concerns

gRPC tidak otomatis lebih aman daripada REST.

Security concern utama:

TLS termination boundary
mTLS identity
authorization per method
header/metadata spoofing
large message size
reflection exposure
plaintext h2c exposure
internal service exposed publicly
lack of method-level audit

16.1 Metadata Spoofing

gRPC metadata mirip header.

Jika NGINX atau gateway meneruskan identity metadata seperti:

x-user-id
x-tenant-id
x-client-cert-subject

pastikan metadata tersebut tidak bisa dikirim langsung dari external client.

Edge harus strip inbound untrusted identity metadata lalu set ulang metadata trusted.

16.2 Reflection Exposure

gRPC reflection membantu debugging, tetapi bisa mengekspos service/method list.

Rule:

reflection boleh di internal/dev jika dibutuhkan;
jangan expose reflection publik tanpa alasan kuat.

16.3 Message Size

gRPC punya message size concern.

Jika message terlalu besar:

memory pressure
latency spike
DoS vector
upstream reject
client error

Perlu limit di:

  • client;
  • NGINX/gateway jika memungkinkan;
  • backend server;
  • application validation.

17. Performance Concerns

Performance gRPC dipengaruhi oleh:

HTTP/2 multiplexing
TLS overhead
connection reuse
max concurrent streams
stream duration
payload size
protobuf serialization
backend thread/event loop model
worker_connections
LB connection distribution

Pitfall:

Satu client membuka sedikit connection tetapi banyak stream.
Load balancer berbasis connection bisa tidak meratakan request.
Long-lived stream menahan resource lama.
Timeout terlalu panjang menyembunyikan stuck stream.

Untuk production review, tanyakan:

Berapa expected concurrent stream?
Berapa average stream duration?
Berapa max message size?
Apakah backend thread-per-request atau event-loop?
Apakah autoscaling berdasarkan CPU cukup?
Apakah ada metric active streams?

18. Debugging Toolkit

Gunakan tool sesuai layer.

TLS/ALPN

openssl s_client -connect grpc.example.com:443 -servername grpc.example.com -alpn h2

HTTP/2 Check

curl -v --http2 https://grpc.example.com/

gRPC Call

grpcurl grpc.example.com:443 list

Plaintext internal:

grpcurl -plaintext quote-grpc-service.default.svc.cluster.local:9090 list

Kubernetes

kubectl describe ingress quote-grpc
kubectl get ingress quote-grpc -o yaml
kubectl get svc quote-grpc-service -o yaml
kubectl get endpointslice -l kubernetes.io/service-name=quote-grpc-service
kubectl logs deploy/ingress-nginx-controller -n ingress-nginx

NGINX Config

nginx -T
nginx -t

Di ingress controller, config final bisa perlu diambil dari pod controller.


19. PR Review Checklist

Saat mereview perubahan gRPC/HTTP/2/NGINX, cek:

  • Apakah endpoint benar-benar gRPC native, gRPC-Web, atau REST?
  • Apakah TLS/ALPN mendukung HTTP/2?
  • Apakah Ingress annotation backend protocol benar?
  • Apakah grpc_pass dipakai untuk gRPC upstream?
  • Apakah path gRPC tidak rusak oleh rewrite?
  • Apakah upstream port benar?
  • Apakah service readiness mengecek listener yang benar?
  • Apakah timeout dibedakan untuk unary vs streaming RPC?
  • Apakah retry aman untuk method mutating?
  • Apakah observability bisa melihat grpc-status?
  • Apakah reflection aman?
  • Apakah identity metadata tidak bisa dipalsukan?
  • Apakah message size dibatasi?
  • Apakah rollback path jelas?

20. Internal Verification Checklist

Untuk konteks CSG/team, jangan asumsi. Verifikasi:

  • Apakah ada gRPC service di Quote & Order domain?
  • Apakah gRPC dipakai external, internal, atau tidak dipakai sama sekali?
  • Apakah edge mendukung HTTP/2 sampai NGINX?
  • Apakah HTTP/2 diteruskan ke backend atau terminate di NGINX?
  • Apakah backend memakai plaintext h2c atau TLS h2?
  • Apakah ingress controller mendukung annotation GRPC/GRPCS?
  • Apakah ada service mesh yang mengambil alih gRPC routing?
  • Apakah ada API gateway di depan NGINX?
  • Apakah observability mencatat grpc-status?
  • Apakah ada runbook untuk gRPC timeout/UNAVAILABLE?
  • Apakah reflection diaktifkan di environment tertentu?
  • Apakah mTLS dipakai untuk service-to-service?
  • Apakah retry policy ada di client, proxy, gateway, atau service mesh?
  • Apakah Java service memakai gRPC framework terpisah dari JAX-RS?

21. Key Takeaways

gRPC di NGINX harus diperlakukan sebagai HTTP/2 RPC traffic, bukan REST biasa.

Hal paling penting:

Protocol correctness first.
Routing correctness second.
Timeout and streaming behavior third.
Observability must include gRPC semantics.
Retry must respect application semantics.

Jika kamu hanya melihat HTTP status, kamu akan kehilangan sebagian besar informasi gRPC.

Jika kamu hanya copy Ingress annotation, kamu berisiko menciptakan protocol mismatch.

Jika kamu menyamakan unary RPC dan streaming RPC, kamu akan salah mendesain timeout.

Senior engineer harus bisa menelusuri:

client -> TLS/ALPN -> NGINX/Ingress -> backend protocol -> gRPC service -> grpc-status -> logs/metrics/traces

Itulah skill inti untuk mereview dan men-debug gRPC traffic di enterprise production system.

Lesson Recap

You just completed lesson 15 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.