blog.dopana

Back

REST thống trị API trong một thập kỷ. GraphQL đến và giải quyết over-fetching. Nhưng cả hai đều sinh ra với JSON và HTTP/1.1 — công nghệ của 20 năm trước. Khi bạn cần giao tiếp giữa các microservices với tốc độ cao, low latency, streaming — gRPC là lựa chọn tối ưu.

gRPC Là Gì?#

gRPC là framework RPC (Remote Procedure Call) mã nguồn mở của Google. Thay vì gọi HTTP endpoint và nhận JSON, bạn gọi function như local — dữ liệu được serialize bằng Protocol Buffers và truyền qua HTTP/2.

// Định nghĩa service trong .proto file
service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (stream User);
}

message GetUserRequest {
  string id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}
protobuf

Sau đó code gen ra client/server code tự động:

// Server
func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
    user, err := s.db.FindUser(req.Id)
    if err != nil {
        return nil, err
    }
    return &pb.User{Id: user.ID, Name: user.Name, Email: user.Email}, nil
}

// Client — gọi như function local
user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: "123"})
fmt.Println(user.Name)
go

Protocol Buffers#

Thay vì JSON (text, ~200-500 bytes cho object nhỏ), Protobuf là binary format:

  • Nhỏ hơn: 10x nhỏ hơn JSON
  • Nhanh hơn: Encode/decode nhanh hơn JSON ~10-100x
  • Typed: Schema bắt buộc, code gen tự động
  • Backward compatible: Thêm field mới không break client cũ
syntax = "proto3";

message Product {
  string id = 1;
  string name = 2;
  double price = 3;
  repeated string tags = 4;  // Array
  bool available = 5;
  oneof source {              // Union
    string internal_id = 6;
    string external_url = 7;
  }
}
protobuf

HTTP/2 Lợi Thế#

gRPC dùng HTTP/2 (không phải HTTP/1.1 như REST truyền thống):

  • Multiplexing: Nhiều request song song trên một connection — không cần connection pool
  • Header compression: HPACK — header chỉ vài bytes sau lần đầu
  • Server push: Server gửi dữ liệu trước khi client request
  • Streaming: Một connection có thể gửi/nhận nhiều message liên tục

Bốn Kiểu API#

Unary RPC (giống REST)#

rpc GetUser(GetUserRequest) returns (User);
// Request → Response
protobuf

Server Streaming#

rpc ListUsers(ListUsersRequest) returns (stream User);
// Request → nhiều Response (real-time feed)
protobuf

Client Streaming#

rpc UploadFile(stream FileChunk) returns (UploadResponse);
// Nhiều Request → một Response
protobuf

Bidirectional Streaming#

rpc Chat(stream ChatMessage) returns (stream ChatMessage);
// Nhiều Request ↔ nhiều Response (WebSocket-like)
protobuf

Bidirectional streaming là killer feature — chat, real-time data, gaming đều dùng pattern này.

Code Demo: User Service#

Proto#

Generate Code#

protoc --go_out=. --go-grpc_out=. user.proto
# Sinh ra user.pb.go và user_grpc.pb.go
bash

Server (Go)#

Client (Go)#

conn, _ := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure))
defer conn.Close()

client := pb.NewUserServiceClient(conn)

// Unary call
user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: "123"})

// Streaming call
stream, _ := client.SearchUsers(ctx, &pb.SearchRequest{Query: "Alice"})
for {
    user, err := stream.Recv()
    if err == io.EOF { break }
    fmt.Println(user.Name)
}
go

Client (Node.js)#

const client = new proto.UserService('localhost:50051', grpc.credentials.createInsecure())

// Unary
client.getUser({ id: '123' }, (err, user) => {
  console.log(user.name)
})

// Streaming
const call = client.searchUsers({ query: 'Alice' })
call.on('data', user => console.log(user.name))
call.on('end', () => console.log('done'))
javascript

So Sánh API Trilogy#

Tiêu chíRESTGraphQLgRPC
FormatJSON (text)JSON (text)Protobuf (binary)
Giao thứcHTTP/1.1HTTP/1.1 hoặc 2HTTP/2
SchemaKhông (hoặc OpenAPI)Có (SDL)Có (proto) bắt buộc
Code genThủ công hoặc OpenAPIGen từ schemaGen từ proto
StreamingServer-Sent EventsSubscriptionBidirectional
Browser supportNativeNativeCần grpc-web hoặc proxy
Payload sizeLớn (JSON)Trung bìnhNhỏ (binary)
Tốc độ encodeChậmTrung bìnhNhanh
HọcThấpTrung bìnhCao (proto + HTTP/2)
Công cụcurl, PostmanPlaygroundgrpcurl, Postman

Khi Nào Dùng Cái Nào?#

gRPC — internal microservices communication

  • Service-to-service: latency sensitive, throughput cao
  • Streaming data: real-time feed, chat, log shipping
  • Polyglot environment: nhiều ngôn ngữ, cần code gen
  • Ví dụ: Netflix, Uber, Spotify dùng gRPC cho internal traffic

REST — external/public API

  • Browser/ mobile app gọi API
  • Third-party integration
  • Cần caching (HTTP cache)
  • Developer familiarity (curl, Postman, mọi người đều biết)

GraphQL — complex data fetching

  • Nhiều client khác nhau cần data khác nhau
  • Frontend team muốn tự do select fields
  • Dashboard, mobile app với nhiều màn hình

Pattern Phổ Biến#

[Browser/Mobile] → REST/GraphQL → [API Gateway] → gRPC → [Microservices]
plaintext

Netflix, Spotify, Mercari đều dùng pattern này. Bên ngoài là REST/GraphQL, bên trong là gRPC.

gRPC Trong Thực Tế#

Netflix — 10,000+ services nói chuyện với nhau qua gRPC, xử lý hàng tỷ request/ngày.

Spotify — thay thế in-house RPC framework Hermes bằng gRPC + Envoy, giảm độ phức tạp vận hành.

Uber — dùng gRPC cho toàn bộ internal traffic, với Envoy làm sidecar proxy.

Cloudflare — hỗ trợ gRPC over HTTP/3 (QUIC) trên CDN, giảm latency 47% trên mobile network.

Giới Hạn#

  • Browser support: gRPC-Web cần proxy (Envoy) hoặc grpc-web client
  • Không dùng curl: Cần grpcurl hoặc Postman
  • Human-readable: Protobuf binary, cần tool để decode
  • Load balancing: HTTP/2 multiplexing phải được hỗ trợ bởi LB
  • HTTP/3: Còn experimental cho gRPC, chưa production-ready

Kết Luận#

REST và GraphQL không sai — nhưng chúng sinh ra cho client-server communication. gRPC sinh ra cho service-to-service.

Nếu bạn đang xây dựng hệ thống microservices, đặc biệt với nhiều ngôn ngữ khác nhau, gRPC là lựa chọn tối ưu: Protobuf nhỏ hơn JSON 10x, HTTP/2 multiplexing, bidirectional streaming, code gen tự động.

API Gateway nhận REST/GraphQL từ frontend, chuyển thành gRPC cho internal services — đó là kiến trúc đang chạy ở Netflix, Uber, Spotify, và hàng ngàn công ty khác.

Tài liệu tham khảo#