Bài 2: Tìm hiểu về Protocol Buffers (Protobuf) - "Trái tim" của gRPC
1. Protocol Buffers (Protobuf) là gì?
Protocol Buffers (hay gọi tắt là Protobuf) là cơ chế tuần tự hóa dữ liệu (serialization mechanism) mã nguồn mở do Google phát triển.
-
Nếu JSON dùng văn bản thô để mô tả dữ liệu (ví dụ:
{"name": "Alice", "age": 25}tốn rất nhiều ký tự và byte mạng), thì Protobuf sẽ biên dịch cấu trúc dữ liệu của bạn thành các chuỗi byte nhị phân (binary) siêu nhỏ gọn. -
Ví dụ trực quan: Cùng một dữ liệu, chuỗi JSON có thể nặng 100 bytes, nhưng khi dùng Protobuf, nó có thể thu gọn lại chỉ còn 10-20 bytes và máy tính đọc trực tiếp bằng mã máy mà không cần mất công phân tích cú pháp (parse) chuỗi rườm rà.
2. Cấu trúc cơ bản của một file .proto
Mọi service gRPC đều bắt đầu bằng việc định nghĩa cấu trúc dữ liệu và dịch vụ trong một file có phần mở rộng là .proto. Đây được gọi là API Contract chung cho tất cả các ngôn ngữ lập trình.
Hãy xem một ví dụ thực tế về file user.proto:
Protocol Buffers
syntax = "proto3"; // Khai báo sử dụng phiên bản Protobuf mới nhất (v3)
package user; // Định nghĩa namespace để tránh trùng lặp tên
// 1. Định nghĩa cấu trúc dữ liệu (Message)
message UserRequest {
int32 user_id = 1; // Số '1' ở đây là "Tag" (số định danh trường), KHÔNG PHẢI LÀ GIÁ TRỊ!
}
message UserResponse {
int32 id = 1;
string name = 2;
string email = 3;
bool is_active = 4;
}
// 2. Định nghĩa dịch vụ (Service) và các hàm (RPC methods)
service UserService {
// Hàm nhận vào UserRequest và trả về UserResponse
rpc GetUserInfo (UserRequest) returns (UserResponse);
}
🔍 Giải mã các điểm quan trọng trong file .proto:
-
syntax = "proto3";: Bắt buộc phải đặt ở dòng đầu tiên để trình biên dịch biết bạn đang dùng chuẩn Protobuf phiên bản 3. -
message: Từ khóa dùng để định nghĩa một cấu trúc dữ liệu (tương tự nhưstructtrong Go/C++, hayclassobject trong Java/Python/TypeScript). -
Các kiểu dữ liệu scalar cơ bản:
int32,int64,string,bool,float,double,... -
Các con số
= 1,= 2,= 3: Đây là Field Tag (thẻ định danh).- Lưu ý cực kỳ quan trọng: Số này không phải là giá trị của biến, mà là mã định danh trường khi dữ liệu được mã hóa thành nhị phân. Khi đã phát hành API, tuyệt đối không được đổi số tag của các trường cũ, vì hệ thống dựa vào số tag này để nhận diện dữ liệu.
3. Cơ chế hoạt động của Field Tag (Tại sao Protobuf lại nhanh?)
Trong JSON, nếu bạn đổi tên trường từ "name" thành "username", hệ thống bên nhận có thể bị lỗi hoặc phải map lại code.
Nhưng trong Protobuf:
-
Bên gửi và bên nhận không quan tâm đến tên biến (
namehayusername). -
Chúng chỉ quan tâm đến Tag Number (ví dụ: trường số
2chính là tên người dùng). -
Điều này giúp gói tin nhị phân trở nên cực kỳ nhẹ vì không cần gửi kèm tên trường lặp đi lặp lại hàng nghìn lần như JSON, đồng thời giúp việc thêm/bớt trường dữ liệu sau này trở nên tương thích ngược rất dễ dàng.
4. Công cụ protoc – Biến file .proto thành Code
File .proto chỉ là bản thiết kế trên giấy. Để sử dụng trong code thực tế (Go, Java, Python, Node.js...), bạn cần dùng Protobuf Compiler (protoc) kết hợp với các plugin tương ứng của ngôn ngữ đó để sinh ra mã nguồn tự động (Code Generation).
Ví dụ, khi bạn chạy lệnh biên dịch cho ngôn ngữ Go hoặc Python, protoc sẽ tự động tạo ra các file code chứa:
-
Các cấu trúc dữ liệu (Struct/Class) tương ứng với
message. -
Các interface/client stub để bạn chỉ việc gọi hàm
GetUserInfo()giống hệt như gọi hàm local bình thường mà không cần tự viết code socket hay xử lý HTTP/2 thủ công.
💡 Tóm tắt Bài 2:
Protobuf giúp nén dữ liệu thành nhị phân siêu nhỏ và siêu nhanh nhờ Field Tag.
File
.protođóng vai trò là "giao ước" chung, giúp đồng nhất dữ liệu giữa mọi ngôn ngữ lập trình.Công cụ
protoctự động hóa toàn bộ công đoạn sinh mã nguồn.
Bạn thấy thế nào về phần Protobuf này? Ở Bài 3, chúng ta sẽ khám phá một điểm cực kỳ thú vị của gRPC: 4 loại Streaming trong gRPC (giúp mở rộng khả năng truyền nhận dữ liệu vượt xa mô hình Request-Response truyền thống). Bạn đã sẵn sàng sang Bài 3 chưa?
All rights reserved