gRPC nâng cao thực chiến cho backend

Sê-ri nâng cao về gRPC cho lập trình viên backend: 4 kiểu RPC, protobuf wire format, streaming, interceptor, deadline, error model, retry, load balancing, reflection, so sánh với REST — mỗi bài demo THẬT bằng Go (protoc + grpc-go) trong Docker, đo số liệu thật (kích thước byte, độ trễ, throughput).

12/12 phần đã đăng Lập trình
1 Vì sao gRPC: đo thật protobuf gọn hơn JSON 63%, và RPC gọi như hàm cục bộ REST + JSON có mặt khắp nơi và dễ đọc — vậy vì sao nhiều hệ chuyển sang gRPC cho giao tiếp nội bộ? Bài này đo thật: cùng một Order, protobuf chỉ 26 byte so với JSON 70 byte (gọn hơn 63%), và một unary gRPC call đạt gần 14.000 call/s với 0,072 ms/call. Giải thích vì sao protobuf nhỏ thế, gRPC nhanh thế, và cái giá phải trả: cần .proto, codegen, và byte nhị phân không đọc được bằng mắt. 22/09/2026 · 7 phút đọc 2 Protobuf wire format: giải mã từng byte để hiểu vì sao nó gọn và field number là hợp đồng Bài trước đo được protobuf gọn hơn JSON 63% nhưng chưa nói vì sao. Bài này mổ xẻ từng byte: serialize {id:1001, name:abc, big:7} ra 11 byte rồi giải mã thủ công — 08 là tag field 1, e907 là varint 1001, a001 là tag field 20 tốn 2 byte. Đo thật varint co giãn theo giá trị (id 5 tốn 2 byte, id 10 tỷ tốn 6 byte), và vì sao wire chỉ chứa số field nên đổi tên không phá nhưng đổi field number thì phá. 22/09/2026 · 7 phút đọc 3 Bốn kiểu RPC của gRPC: unary, server/client/bidirectional streaming — chạy thật cả bốn REST chỉ có một mô hình: request rồi response. gRPC có bốn, mở khoá bằng từ khoá stream trong .proto. Bài này chạy thật cả bốn trong một service: unary (1 req→1 resp), server streaming (1 req→5 resp), client streaming (4 req→1 resp tổng đúng 500), và bidirectional (3 msg↔3 msg xen kẽ). Mỗi kiểu hợp một dạng dữ liệu khác nhau, và chọn đúng kiểu là một quyết định thiết kế API thật. 22/09/2026 · 7 phút đọc 4 Server streaming thực chiến: đo thật time-to-first-item nhanh hơn 9 lần so với unary Server streaming có làm API nhanh hơn không? Có và không. Bài này đo thật: server tạo 10 item mỗi cái 50ms. Unary bắt client chờ 529ms mới nhận được gì; server streaming đẩy item đầu sau chỉ 58ms — nhanh hơn 9 lần về time-to-first-item. Nhưng tổng thời gian gần như bằng nhau (529 vs 533ms). Streaming không rút ngắn tổng — nó thắng ở độ trễ item đầu, bộ nhớ, và xử lý song song. 22/09/2026 · 6 phút đọc 5 Client streaming và bidirectional: upload theo luồng và chat hai chiều, chạy thật Hai kiểu streaming còn lại của gRPC. Bài này chạy thật: client streaming upload 5 chunk (1024+2048+512+4096+256) rồi server gộp trả đúng 7936 byte trong một response; bidirectional gửi số và nhận bình phương ngay lập tức, xen kẽ (3→9, 5→25, 8→64, 10→100). Kèm cái bẫy deadlock kinh điển của bidi: nếu gửi và nhận cùng một goroutine, cả hai cùng chờ nhau và treo. 22/09/2026 · 7 phút đọc 6 Interceptor trong gRPC: middleware bọc mọi RPC cho log, đo thời gian, auth tập trung Cần log, đo thời gian, và xác thực cho mọi RPC — nhưng không muốn lặp code ở từng handler. Interceptor là lời giải: một lớp bọc quanh mọi call. Bài này chạy thật một chain hai interceptor: logging đo thời gian mỗi call (Fast 1µs, Slow 46ms), và auth chặn /Secure khi thiếu token (trả Unauthenticated, handler không chạy) nhưng cho qua khi token đúng. Viết một lần, áp cho toàn hệ. 22/09/2026 · 6 phút đọc 7 Deadline và cancellation trong gRPC: huỷ call đúng lúc thay vì treo vô hạn Một call không có deadline là một quả bom hẹn giờ: nếu server treo, client chờ mãi, tài nguyên cạn dần. Bài này chạy thật: server handler tốn 500ms, client đặt deadline 100ms — call bị huỷ sau đúng 101ms (không phải 500ms), client nhận DeadlineExceeded, và server phát hiện context bị huỷ nên dừng việc ngay thay vì tốn CPU cho kết quả client đã bỏ. Deadline lan truyền toàn chuỗi call qua context. 22/09/2026 · 7 phút đọc 8 Error model của gRPC: status code chuẩn và details có cấu trúc thay cho chuỗi lỗi mơ hồ Trả về error là một chuỗi text thì client phải đoán xem có nên retry không, lỗi do input hay do server. gRPC có bộ status code chuẩn giải quyết điều đó. Bài này chạy thật: server trả InvalidArgument kèm details có cấu trúc (field nào sai), NotFound, và OK; client đọc code để quyết định tự động — retry với Unavailable, bỏ với InvalidArgument. Code là ngôn ngữ chung máy hiểu, hơn hẳn một dòng text. 22/09/2026 · 7 phút đọc 9 Retry và backoff trong gRPC: để framework tự thử lại, và chỉ thử lại lỗi tạm thời Viết vòng lặp retry bằng tay ở từng chỗ gọi là lặp code và dễ sai. gRPC có retry policy khai bằng cấu hình. Bài này chạy thật: server fail 2 lần đầu với Unavailable rồi OK — client cấu hình retry tự thử lại và nhận thành công sau đúng 3 lần gọi server (đo bằng counter thật), với backoff tăng dần. Nhưng lỗi InvalidArgument thì không retry: server chỉ bị gọi 1 lần, vì gọi lại input sai vẫn sai. 22/09/2026 · 6 phút đọc 10 Load balancing phía client trong gRPC: rải request qua nhiều backend không cần proxy gRPC giữ kết nối lâu dài, nên load balancer tầng kết nối không rải được từng request — gRPC tự cân bằng ở phía client. Bài này chạy thật với 3 server: chính sách mặc định pick_first dồn cả 300 request vào một server (2 server ngồi không); đổi sang round_robin thì 300 request rải đều 100/101/99. Đo bằng counter thật mỗi server. Client biết danh sách backend qua resolver và tự chọn — không cần proxy ở giữa. 22/09/2026 · 6 phút đọc 11 Reflection trong gRPC: gọi và khám phá service không cần file .proto, bằng grpcurl Bài 1 nói gRPC khó debug vì byte nhị phân và cần codegen. Reflection gỡ đúng nỗi đau đó. Bài này chạy thật: server bật reflection một dòng, rồi grpcurl — curl cho gRPC — liệt kê service, xem schema message, và gọi GetOrder nhận về JSON, tất cả KHÔNG cần file .proto trên máy. Server tự khai schema lúc chạy. Công cụ debug mạnh nhất cho gRPC — nhưng nên tắt ở production nhạy cảm vì nó lộ toàn bộ API. 22/09/2026 · 6 phút đọc 12 Tổng kết gRPC: khung quyết định gRPC vs REST và checklist từ 12 bài đo thật Mười một phần qua ta mổ xẻ gRPC bằng demo đo thật. Bài cuối ghép lại: một service capstone gộp interceptor, deadline và error model cùng chạy; bảng tổng hợp mọi con số đo thật xuyên 12 bài (protobuf 26 vs JSON 70 byte, deadline huỷ 101ms, round_robin 100/101/99...); và khung quyết định gRPC vs REST — gRPC không tốt hơn, nó đánh đổi khác, hợp bài toán khác. 22/09/2026 · 6 phút đọc