Protocol Buffers (Protobuf) 详解

简介: Protocol Buffers(Protobuf)是Google推出的高效数据序列化格式,语言无关、平台无关,比JSON和XML更小更快。支持多语言代码生成,具备良好的兼容性与类型安全,广泛应用于gRPC、微服务通信及数据存储等场景。

@TOC

Protocol Buffers (Protobuf) 详解

1. 什么是 Protocol Buffers?

Protocol Buffers(简称 Protobuf)是 Google 开发的一种语言无关、平台无关、可扩展的序列化数据结构的机制。它比 XML 和 JSON 更小、更快、更简单。

2. 核心特性

2.1优点

  • 高效性:二进制格式,体积小,序列化/反序列化速度快
  • 跨语言:支持多种编程语言
  • 向前/向后兼容:通过字段编号机制实现
  • 代码生成:自动生成数据访问类
  • 结构化数据:强类型定义

2.2 缺点

  • 可读性差:二进制格式不易阅读
  • 需要预编译:需要预定义 .proto 文件

3. 基本语法

3.1 基本消息定义

syntax = "proto3";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

3.2 字段规则

  • singular: 单个值(默认)
  • repeated: 数组/列表
  • map<K, V>: 键值对

3.3 数据类型

.proto 类型 C++ 类型 Java 类型 Python 类型
double double double float
float float float float
int32 int32 int int
int64 int64 long int/long
bool bool boolean bool
string string String str
bytes string ByteString bytes

4. 版本差异

proto2 vs proto3

// proto2
syntax = "proto2";
message Example {
  required string name = 1;    // 必须字段
  optional int32 id = 2;       // 可选字段
  repeated string emails = 3;  // 重复字段
}

// proto3
syntax = "proto3";
message Example {
  string name = 1;            // 默认都是可选
  int32 id = 2;
  repeated string emails = 3;
}

5. 高级特性

5.1 Oneof

message SampleMessage {
  oneof test_oneof {
    string name = 1;
    int32 id = 2;
  }
}

5.2 Map

message Product {
  map<string, string> properties = 1;
}

5.3 嵌套消息

message Outer {
  message Inner {
    string text = 1;
  }
  Inner inner = 1;
}

5.4 导入其他文件

import "other.proto";

5.5 包和命名空间

package my.package;

// Java 特定选项
option java_package = "com.example.generated";
option java_outer_classname = "ExampleProto";

6. 实际应用示例

6.1 完整的 .proto 文件

syntax = "proto3";

package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

6.2 Python 使用示例

import addressbook_pb2

# 创建消息
person = addressbook_pb2.Person()
person.id = 1234
person.name = "John Doe"
person.email = "jdoe@example.com"

phone = person.phones.add()
phone.number = "555-4321"
phone.type = addressbook_pb2.Person.HOME

# 序列化
serialized_data = person.SerializeToString()

# 反序列化
new_person = addressbook_pb2.Person()
new_person.ParseFromString(serialized_data)

print(f"Name: {new_person.name}")
print(f"Email: {new_person.email}")

6.3 Java 使用示例

// 创建 Builder
Person person = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .addPhones(
        Person.PhoneNumber.newBuilder()
            .setNumber("555-4321")
            .setType(Person.PhoneType.HOME)
            .build())
    .build();

// 序列化
byte[] serializedData = person.toByteArray();

// 反序列化
Person newPerson = Person.parseFrom(serializedData);

System.out.println("Name: " + newPerson.getName());
System.out.println("Email: " + newPerson.getEmail());

7. 编译和使用

7.1 安装编译器

# 下载 protoc 编译器
# 或使用包管理器安装

7.2 编译 .proto 文件

# 生成 Java 代码
protoc --java_out=. addressbook.proto

# 生成 Python 代码
protoc --python_out=. addressbook.proto

# 生成多种语言
protoc --java_out=. --python_out=. --cpp_out=. addressbook.proto

8. 最佳实践

8.1 字段编号

  • 使用 1-15 作为常用字段(占用 1 字节)
  • 16-2047 作为不常用字段
  • 不要随意更改字段编号

8.2 向后兼容

  • 不要删除已使用的字段编号
  • 新字段使用新的编号
  • 已删除的字段可添加 reserved 声明
message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

8.3 版本管理

  • 在文件名或包名中包含版本信息
  • 使用语义化版本控制

9. 与其他序列化格式对比

特性 Protobuf JSON XML
大小 很大
速度 很慢
可读性
类型安全
跨语言 优秀 优秀 优秀

10. 使用场景

  • 微服务通信:gRPC 的默认序列化格式
  • 数据存储:高效存储结构化数据
  • 配置文件:强类型的配置定义
  • API 设计:定义清晰的接口契约

Protobuf 在现代分布式系统中扮演着重要角色,特别是在性能要求高、需要跨语言协作的场景中表现出色。

相关文章
|
5月前
|
JSON Java 编译器
Protobuf 是什么?一篇文章搞懂这个高性能序列化神器
Protobuf是Google开源的高效二进制序列化协议,体积小、速度快,支持跨语言、向后兼容。相比JSON,更适合RPC等高性能场景,广泛应用于微服务通信。通过`.proto`文件定义结构,自动生成代码,实现数据的快速序列化与反序列化。
2525 158
|
3月前
|
编译器 Go PHP
FrankenPHP 原生支持 Windows 了
FrankenPHP 正式原生支持 Windows!基于 Go 1.26 对 MSVC Clang 的 CGO 支持,成功打通与官方 PHP(MSVC 编译)的链接难题,实现 100% 特性兼容——含 Worker Mode、Hot Reloading 及全部扩展。性能较 Nginx/PHP-FPM 提升超 260%,开箱即用。(239字)
481 157
|
5月前
|
网络协议 Dubbo Java
从 TCP 到 RPC:彻底搞懂「HTTP 与 RPC用法区别」
本文深入剖析HTTP与RPC的本质区别,从TCP底层原理讲起,解析粘包拆包、协议封装等核心问题,梳理二者演进脉络。通过对比服务发现、传输性能、适用场景等维度,结合Dubbo、gRPC等框架,帮你按场景精准选型,彻底搞懂微服务通信的技术逻辑。
855 160
|
1月前
|
SQL 运维 关系型数据库
DBA必备技能:MySQL误删恢复完全指南(全量备份+binlog回放)
本文详解误删数据(如`DELETE FROM orders`)后的紧急恢复三步法:查Binlog→临时库回放→差异导回,并附4条血泪预防措施。不讲段子,只教能救命的操作!
|
人工智能 网络协议 Linux
MCP 协议: Streamable HTTP 是最佳选择
随着AI应用变得越来越复杂并被广泛部署,原有的通信机制面临着一系列挑战。近期MCP仓库的PR #206引入了一个全新的Streamable HTTP传输层替代原有的HTTP+SSE传输层。本文将详细分析该协议的技术细节和实际优势。
7749 102
|
SQL 大数据 数据处理
Flink SQL 详解:流批一体处理的强大工具
Flink SQL 是为应对传统数据处理框架中流批分离的问题而诞生的,它融合了SQL的简洁性和Flink的强大流批处理能力,降低了大数据处理门槛。其核心工作原理包括生成逻辑执行计划、查询优化和构建算子树,确保高效执行。Flink SQL 支持过滤、投影、聚合、连接和窗口等常用算子,实现了流批一体处理,极大提高了开发效率和代码复用性。通过统一的API和语法,Flink SQL 能够灵活应对实时和离线数据分析场景,为企业提供强大的数据处理能力。
2418 27
|
存储 NoSQL Redis
Redis的数据过期策略有哪些 ?
Redis 采用两种过期键删除策略:惰性删除和定期删除。惰性删除在读取键时检查是否过期并删除,对 CPU 友好但可能积压大量过期键。定期删除则定时抽样检查并删除过期键,对内存更友好。默认每秒扫描 10 次,每次检查 20 个键,若超过 25% 过期则继续检查,单次最大执行时间 25ms。两者结合使用以平衡性能和资源占用。
379 11
|
XML 存储 编译器
Protobuf 详解
Protobuf 详解
|
存储 Java Go

热门文章

最新文章