Protobuf trong thực tế

Tôi đã làm việc với các sản phẩm Bluetooth, bao gồm thiết bị đeo và khóa thông minh, trong nhiều năm. Việc tạo điều kiện cho việc truyền message giữa các thành phần hệ thống là một khía cạnh quan trọng do sự khác biệt về ngôn ngữ lập trình, yêu cầu về tính nhất quán và giới hạn về kích thước truyền dữ liệu. Để giải quyết những thách thức này, chúng tôi sử dụng Protocol Buffers.
Protocol Buffers, còn được gọi là Protobuf, là một định dạng dữ liệu đa nền tảng mã nguồn mở và miễn phí được sử dụng để serialize dữ liệu có cấu trúc, được phát triển bởi Google. Nó được thiết kế để hiệu quả, có thể mở rộng và thân thiện với người dùng. Trong bài hướng dẫn này, chúng ta sẽ tìm hiểu những kiến thức cơ bản về việc tạo một Protocol Buffers message đơn giản, định nghĩa schema và generate code trong các ngôn ngữ lập trình khác nhau.
Cài đặt
Để cài đặt protobuf compiler, hãy làm theo hướng dẫn được nêu trong protobuf-compiler-installation.
Cách sử dụng cơ bản có thể được tóm tắt bằng hình ảnh dưới đây.

Các bước để thiết lập:
Cài đặt protobuf compiler. Trên Mac, sử dụng brew:
brew install protobufXác nhận việc cài đặt đã hoàn tất thành công:
protoc --version.Cài đặt Code Generator Plugin: Protobuf hỗ trợ nhiều ngôn ngữ lập trình khác nhau. Bạn cần tìm và cài đặt code generator cho ngôn ngữ cụ thể tùy thuộc vào ngôn ngữ lập trình nào được sử dụng trong dự án của bạn. Ví dụ, cho Swift, sử dụng
swift-protobuf:brew install swift-protobuf. Cho JavaScript, sử dụngnpm install -g protoc-gen-js.Định nghĩa các scheme của bạn: Truy cập Programming Guides để tìm hiểu cách sử dụng ngôn ngữ protocol buffer để cấu trúc dữ liệu protocol buffer của bạn
example.proto 1
2
3
4
5message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
}Compile các file
.protođể generate code cho các ngôn ngữ cụ thể.1
2
3
4nguyenuy@192 ~/Desktop/protobuf protoc --js_out=. example.proto
nguyenuy@192 ~/Desktop/protobuf protoc --java_out=. example.proto
nguyenuy@192 ~/Desktop/protobuf protoc --cpp_out=. example.proto
nguyenuy@192 ~/Desktop/protobuf protoc --dart_out=. example.protoPhân phối (import) các file đã generate vào các dự án của bạn.
Cài đặt runtime plugin. Ví dụ, trong dự án iOS, include framework
SwiftProtobuftrongPodfile. Cho các dự án Flutter, thêmprotobufvào filepubspec.yaml. Cho các dự án ReactJS, includegoogle-protobuftrong filepackage.json.Triển khai serialization và deserialization:
Ví dụ trong Python1
2
3
4
5
6
7
8
9
10
11
12
13person = example_pb2.Person()
# Set values
person.name = "Uy Nguyen"
person.id = 1
person.email = "uynguyen.itus@gmail.com"
# Serialize the message to bytes
serialized_data = person.SerializeToString()
# Parse the bytes back into a message
new_person = example_pb2.Person()
new_person.ParseFromString(serialized_data)Ví dụ trong Java
1
2
3
4
5
6
7
8
9
10
11Person person = Person.newBuilder()
.setName("Uy Nguyen")
.setId(1)
.setEmail("uynguyen@gmail.com")
.build();
// Serialize the message to bytes
byte[] serializedData = person.toByteArray();
// Parse the bytes back into a message
Person newPerson = Person.parseFrom(serializedData);Ví dụ trong Swift
1
2
3
4
5
6
7
8
9
10var p = Person()
p.id = 1
p.email = "uynguyen.itus@gmail.com"
p.name = "Uy Nguyen"
// Serialize the message to bytes
let data = try? p.serializedData()
// Parse the bytes back into a message
let converted = try? Person(serializedData: data!)
Dưới đây là cách các file được generate trông như thế nào trong các ngôn ngữ khác nhau.
Ưu điểm
- Định dạng nhị phân:
Protobufsử dụng định dạng nhị phân để serialization, nhỏ gọn hơn so với định dạng dựa trên văn bản củaJSON. Điều này dẫn đến kích thước message nhỏ hơn, làm cho nó hiệu quả hơn về cả băng thông và lưu trữ. - Hiệu suất: Do định dạng nhị phân và encoding hiệu quả, quá trình serialization và deserialization của
Protobufthường nhanh hơnJSON. Điều này có thể đặc biệt quan trọng trong các tình huống yêu cầu throughput cao hoặc độ trễ thấp, chẳng hạn như các hệ thống sử dụng BLE. - Code Generation:
Protobufdựa vào code generation để tạo các data class trong các ngôn ngữ lập trình khác nhau dựa trên schema đã định nghĩa. Điều này có thể dẫn đến code type-safe và hiệu quả, giảm khả năng xảy ra lỗi runtime liên quan đến sự không khớp cấu trúc dữ liệu. - Hỗ trợ nhiều ngôn ngữ: Protobuf hỗ trợ code generation trong nhiều ngôn ngữ lập trình, phù hợp cho các dự án với các công nghệ khác nhau. Điều này cho phép các service khác nhau được viết bằng các ngôn ngữ khác nhau dễ dàng giao tiếp bằng cách sử dụng cùng các cấu trúc dữ liệu.
Nhược điểm
- Khả năng đọc: Định dạng nhị phân của
Protobufkhông thể đọc được bởi con người, điều này có thể làm cho việc debug và khắc phục sự cố khó khăn hơn so vớiJSON. Định dạng văn bản thuần túy củaJSONcho phép các nhà phát triển dễ dàng kiểm tra dữ liệu. - Độ phức tạp khi debug: Do tính chất nhị phân của
protobuf, việc debug có thể phức tạp hơn khi so sánh vớiJSON. Thường cần các công cụ chuyên dụng để kiểm tra nội dung của các message được encode bằngprotobuf. - Ít phổ biến trong công nghệ Web:
JSONphổ biến hơn trong phát triển web và được hỗ trợ natively bởi nhiều web API. Nếu khả năng tương tác với các công nghệ web là ưu tiên hàng đầu,JSONcó thể là một lựa chọn tự nhiên hơn. - Phức tạp với cấu trúc lồng nhau: Việc xử lý các cấu trúc lồng nhau trong
protobufmessage đôi khi có thể ít trực quan hơn so với trongJSON. Cần chú ý khi thiết kế các cấu trúc lồng nhau để tránh sự phức tạp không cần thiết.
Tổng kết
Tóm lại, trong khi protobuf mang lại những lợi thế đáng kể về hiệu quả và hiệu suất, việc áp dụng nó nên được xem xét dựa trên các yêu cầu và ràng buộc cụ thể của dự án. Điều cần thiết là xem xét các ưu và nhược điểm và chọn định dạng serialization phù hợp nhất với mục tiêu và ràng buộc của dự án.