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

相关文章
|
18天前
|
SQL 关系型数据库 MySQL
MySQL从入门到精通:系统性学习路径
“MySQL从入门到精通”系统梳理了从基础到高阶的完整学习路径,涵盖安装配置、SQL语法、数据库设计、事务锁机制、性能优化、主从复制及分库分表等核心内容,结合实战任务帮助开发者由浅入深掌握MySQL,助力成为数据库高手。
144 13
|
22天前
|
运维 监控 数据可视化
故障发现提速 80%,运维成本降 40%:魔方文娱的可观测升级之路
魔方文娱携手阿里云构建全栈可观测体系,实现故障发现效率提升 80%、运维成本下降 40%,并融合 AI 驱动异常检测,迈向智能运维新阶段。
209 34
|
22天前
|
人工智能 编解码 数据挖掘
如何给AI一双“懂节奏”的耳朵?
VARSTok 是一种可变帧率语音分词器,能智能感知语音节奏,动态调整 token 长度。它通过时间感知聚类与隐式时长编码,在降低码率的同时提升重建质量,实现高效、自然的语音处理,适配多种应用场景。
147 18
|
25天前
|
SQL 架构师 关系型数据库
【Java架构师体系课 | MySQL篇】⑤ 索引优化实战一
本文深入解析MySQL索引优化原理,涵盖联合索引使用、覆盖索引、索引下推、filesort排序机制及trace工具分析执行计划选择等内容,并结合实际案例提供索引设计原则与SQL优化策略。
101 5
|
25天前
|
边缘计算 自然语言处理 算法
实时交互数字人端到端延迟压至0.8秒:关键技术节点与商业价值解析
0.8秒是实时数字人体验的关键阈值,端到端延迟低于此值可实现自然流畅交互。本文解析其技术链路、核心支撑与商业价值,揭示为何这一指标成为数字人从“可用”到“好用”的分水岭。
|
19天前
|
消息中间件 Java 调度
深入探讨进程、线程和协程之间的区别和联系
本文深入解析进程、线程与协程的核心区别与联系,涵盖资源分配、调度机制、通信方式及性能对比。结合代码示例与实际场景,阐明三者在高并发系统中的协同应用,助你掌握现代并发编程设计精髓。(239字)
132 11
|
26天前
|
自然语言处理 JavaScript 前端开发
vue 插槽详解
本文系统讲解 Vue.js 插槽机制,涵盖默认插槽、具名插槽、作用域插槽及动态插槽等高级用法,结合代码示例与实际应用场景(如布局组件、表格、模态框),帮助开发者掌握组件内容分发的核心技术,提升组件复用性与灵活性。
223 8
|
1月前
|
人工智能 并行计算 算法
为什么 OpenSearch 向量检索能提速 13 倍?
本文介绍在最新的 OpenSearch 实践中,引入 GPU 并行计算能力 与 NN-Descent 索引构建算法,成功将亿级数据规模下的向量索引构建速度提升至原来的 13 倍。
601 24
为什么 OpenSearch 向量检索能提速 13 倍?
|
1月前
|
数据采集 监控 搜索推荐
低至 1% 性能损耗:阿里云 ARMS 配置模板如何实现精准可控的 JMX 数据采集
APM 一定要全量采集吗?ARMS 推出配置模板,支持按场景分级监控:核心应用上 Trace,非核心只采 JVM,成本直降 90%+ !
204 36
|
16天前
|
人工智能 前端开发 安全
AI 最先替代的开发工作:从重复劳动到人机协同的新范式
AI正加速替代基础开发工作:CRUD页面、样板代码、简单Bug修复、文档生成与基础测试等重复性任务已可通过低代码平台与AI工具高效完成,显著提升生产力。据Gartner报告,70%企业内部系统已采用AI辅助开发,人力投入减少60%-80%。GitHub Copilot等工具更让开发者节省45%编码时间。然而,产品需求分析、系统架构设计、复杂交互体验及创新研发等需深度判断与创造力的工作,仍依赖人类智慧。未来开发者将转型为“AI指挥官”,聚焦问题定义、提示工程与人机协同,核心竞争力转向系统思维、业务理解与技术创新。
192 15

热门文章

最新文章