Bài đầu loạt này chỉ ra một nhược điểm thật của gRPC so với REST: khó debug. REST chỉ cần curl và đọc JSON bằng mắt; gRPC là byte nhị phân, và để gọi thử một method bạn thường cần file .proto để sinh client. Nếu không có .proto trong tay (service của team khác, môi trường production), bạn gần như không gọi được. Reflection gỡ đúng nỗi đau này: nó cho server tự khai báo schema của mình lúc chạy, để công cụ như grpcurl — "curl cho gRPC" — khám phá và gọi method mà không cần file .proto nào. Bài này (phần 11 loạt gRPC nâng cao) chạy thật grpcurl qua reflection để thấy debug gRPC dễ như curl REST.
Reflection: server tự khai schema lúc chạy
Bình thường, thông tin về service (có những method nào, message hình dạng ra sao) nằm trong file .proto ngoài server. Reflection đưa thông tin đó vào server: server phục vụ một service đặc biệt (grpc.reflection.ServerReflection) trả về chính schema của nó khi được hỏi. Bật nó chỉ một dòng:
// SERVER: bật reflection một dòng
g := grpc.NewServer()
pb.RegisterOrderServiceServer(g, &srv{})
reflection.Register(g) // ← cho phép khám phá schema
g.Serve(lis)
Sau đó, bất kỳ công cụ nào cũng hỏi server về schema rồi gọi method. grpcurl là công cụ phổ biến nhất — nó như curl nhưng cho gRPC:
# liệt kê service (không cần .proto)
grpcurl -plaintext localhost:50060 list
# liệt kê method của một service
grpcurl -plaintext localhost:50060 list shop.OrderService
# xem schema message
grpcurl -plaintext localhost:50060 describe shop.Order
# GỌI method (gửi JSON, nhận JSON)
grpcurl -plaintext -d '{"id":42}' localhost:50060 shop.OrderService/GetOrder

Hình 1: Server bật reflection chỉ một dòng reflection.Register(g). Sau đó grpcurl — curl cho gRPC — list service, list method, describe message, và gọi method bằng -d '{...}', tất cả không cần file .proto. Reflection nên tắt ở production nhạy cảm vì lộ toàn bộ API.
Đo thật: khám phá và gọi, không có .proto
Mình dựng server có reflection trên go-lab, rồi dùng grpcurl (không có file .proto nào trong thư mục gọi):

Hình 2: Output thật từ grpcurl qua reflection. list → thấy shop.OrderService; list shop.OrderService → method GetOrder; describe shop.Order → schema đầy đủ (id, amount, currency) lấy từ server; call GetOrder -d '{"id":42}' → kết quả JSON {id:42, amount:250000, currency:VND}. Tất cả không cần file .proto.
Đọc kết quả:
list→ khám phá service: grpcurl hỏi server có service nào, nhận vềshop.OrderService(cùng các service reflection nội bộ). Bạn không cần biết trước server có gì — nó tự khai.list shop.OrderService→ khám phá method: liệt kêGetOrder. Giờ bạn biết gọi được method nào.describe shop.Order→ khám phá schema: in ra đúng định nghĩa messageOrder(id, amount, currency với kiểu và field number) — lấy từ server lúc chạy, không từ file. Bạn biết chính xác gửi gì và nhận gì.call GetOrder -d '{"id":42}'→ gọi thật: gửi JSON, grpcurl tự dịch sang protobuf (nhờ schema lấy qua reflection), gọi server, và dịch kết quả ngược về JSON:{id:42, amount:250000, currency:VND}. Bạn vừa gọi một gRPC method bằng JSON trên dòng lệnh, không viết một dòng code hay có một file.protonào.
Thông điệp cốt lõi: reflection biến gRPC từ "cần codegen mới gọi được" thành "gọi được ngay như curl REST". Đây chính là lời giải cho nhược điểm "khó debug" của bài 1 — công cụ bù lại cho tính nhị phân.
Vì sao reflection đổi cả cách làm việc với gRPC
Trước reflection, quy trình debug một gRPC service là: xin file .proto, sinh client, viết code gọi, compile, chạy — nặng nề cho một lần thử. Với reflection, nó rút xuống một dòng grpcurl. Điều này mở ra cả hệ sinh thái công cụ động: Postman gọi gRPC qua reflection, các UI khám phá API (như gRPC UI), service mesh tự lấy schema để định tuyến/validate. Reflection cũng là nền cho grpc_cli và nhiều công cụ vận hành. Nó không chỉ tiện debug — nó làm gRPC tương tác được (introspectable) như một hệ thống mở, thay vì một hộp đen cần tài liệu ngoài.
Đánh đổi cần cân nhắc
Reflection lộ toàn bộ API surface — tắt ở production nhạy cảm. Đây là đánh đổi bảo mật quan trọng nhất. Bật reflection nghĩa là bất kỳ ai kết nối được tới server đều liệt kê được mọi service, method, và schema của bạn — một tấm bản đồ hoàn chỉnh cho kẻ tấn công dò tìm. Với service nội bộ sau firewall, tiện lợi debug thường đáng; với service tiếp xúc internet hoặc nhạy cảm, nên tắt reflection ở production (hoặc chỉ bật ở môi trường dev/staging). Reflection là công cụ, không phải tính năng luôn-bật.
Reflection không thay thế .proto cho phát triển. grpcurl + reflection tuyệt cho debug và thử nghiệm, nhưng không thay việc có .proto khi viết code client thật: bạn vẫn cần .proto để sinh type-safe client, để review thay đổi schema, để versioning. Reflection cho schema lúc chạy (dynamic), còn phát triển nghiêm túc cần schema lúc compile (static, type-safe). Dùng reflection để khám phá và debug, dùng .proto để xây dựng.
Schema qua reflection phản ánh server đang chạy, có thể lệch với .proto nguồn. Reflection trả về schema compile vào binary đang chạy — nếu server deploy một phiên bản cũ, reflection cho schema cũ, có thể khác file .proto mới nhất trong repo. Điều này thường tốt (bạn thấy đúng cái server thực sự hiểu), nhưng có thể gây nhầm nếu bạn tưởng reflection = nguồn sự thật mới nhất. Nó là sự thật của binary đang chạy, không phải của repo.
Ba ý mang về
- Reflection cho khám phá và gọi gRPC không cần .proto: đo thật grpcurl
list/describe/callservice, schema và method lấy từ server lúc chạy, gọi GetOrder bằng JSON nhận JSON — gỡ nhược điểm "khó debug" của gRPC, dễ như curl REST. - Bật một dòng, mở cả hệ công cụ động:
reflection.Register(g)đủ để grpcurl, Postman, gRPC UI và service mesh introspect server; biến gRPC từ hộp đen cần tài liệu ngoài thành hệ tương tác được. - Tắt ở production nhạy cảm, không thay .proto: reflection lộ toàn bộ API surface (bản đồ cho kẻ tấn công) nên tắt ở service tiếp xúc internet; nó cho schema lúc chạy để debug, còn phát triển type-safe vẫn cần
.protolúc compile.
Nguồn
- gRPC docs — Server reflection: https://grpc.io/docs/guides/reflection/
- grpcurl — công cụ CLI cho gRPC: https://github.com/fullstorydev/grpcurl
- gRPC — Server Reflection Protocol: https://github.com/grpc/grpc/blob/master/doc/server-reflection.md
Phần sau là bài tổng kết loạt gRPC: ghép mọi mảnh — protobuf, bốn kiểu RPC, interceptor, deadline, error, retry, LB, reflection — thành khung quyết định gRPC vs REST và checklist thực chiến.