学习 Protobuf:序列化、反序列化及与 JSON 的对比

一、Protobuf 简介

在构建高性能的分布式系统时,数据的序列化和反序列化是一个关键环节。

Protocol Buffers 是由 Google 开发的一种语言中立、平台中立、可扩展的序列化结构数据的方式, 它是一种高效的二进制序列化格式,适用于通信协议、数据存储等场合。它允许你定义结构化的数据,并生成多种语言的代码来读写这些数据。


二、项目准备

1. 定义 .proto 文件

首先,我们需要定义一个 .proto 文件来描述我们的数据结构和服务接口。以下是一个简单的 helloworld.proto 文件示例:

Go 复制代码
syntax = "proto3";

option go_package = "/proto1;proto1"; // 指定生成的 Go 包路径
//option go_package = ".;proto"; //这个可以生成在当前目录下


message HelloRequest {
  string name = 1; // 字段编号从1开始
}

2. 使用 protoc 编译器生成 Go 代码

接下来,使用 protoc 编译器生成 Go 语言的源码:

Go 复制代码
protoc --go_out=. --go-grpc_out=. helloworld.proto

这条命令会根据 helloworld.proto 文件生成相应的 Go 代码,这些代码会被放置在指定的包目录中。

附录:项目结构


三、序列化与反序列化实践

下面我们将展示如何使用生成的 Go 代码进行序列化和反序列化操作。

✅ 示例代码

Go 复制代码
package main

import (
	"awesomeProject1/rpc3/proto/proto1" // 使用生成的 proto1 包,其中包含 HelloRequest
	"fmt"
	"google.golang.org/protobuf/proto" // 标准库,用于 Marshal/Unmarshal
)

func main() {
	// 创建一个新的请求实例
	req := &proto1.HelloRequest{
		Name: "Bob",
	}

	// 序列化:将结构体转换为二进制数据
	data, err := proto.Marshal(req)
	if err != nil {
		panic(err)
	}

	fmt.Println("Serialized data:", data)

	// 反序列化:将二进制数据解析回结构体
	newReq := &proto1.HelloRequest{}
	err = proto.Unmarshal(data, newReq)
	if err != nil {
		panic(err)
	}

	fmt.Println("Deserialized name:", newReq.GetName())
}

代码解释

代码片段 解释
req := &proto1.HelloRequest{...} 创建一个 HelloRequest 实例并初始化字段
data, err := proto.Marshal(req) 将结构体序列化为二进制数据
fmt.Println("Serialized data:", data) 打印序列化后的数据(注意:这是二进制形式,不可读)
newReq := &proto1.HelloRequest{} 创建一个新的空结构体实例用于存储反序列化的结果
proto.Unmarshal(data, newReq) 将二进制数据反序列化回结构体

四、 对比 Protobuf 和 JSON

为了更好地理解 Protobuf 的优势,我们将其与常见的 JSON 格式做对比。

1. 压缩比

  • Protobuf:由于采用二进制编码,数据更加紧凑。
  • JSON:基于文本的格式,数据体积相对较大。

2. 可读性

  • Protobuf:序列化后的数据是二进制格式,不适合人类直接阅读。
  • JSON:以文本形式存在,易于阅读和调试。

3. 性能

  • Protobuf:因为使用了二进制格式,序列化和反序列化速度更快。
  • JSON:需要额外的时间来进行字符串解析。

示例对比

假设我们有如下 JSON 数据:

Go 复制代码
{
  "name": "Bob"
}

对应的 Protobuf 序列化后的数据可能看起来像这样(实际输出取决于具体实现):

Go 复制代码
Serialized data: [10 3 66 111 98]

虽然 Protobuf 的输出不如 JSON 直观,但它占用的空间更小,处理速度也更快,非常适合用于网络传输或持久化存储。


五、Protobuf 的优点

  1. 高效:相比 JSON,Protobuf 更加紧凑,减少了带宽消耗。
  2. 跨语言支持:支持多种编程语言,便于不同语言环境下的系统集成。
  3. 向前兼容性和向后兼容性:可以方便地更新消息格式而不会破坏现有服务。
  4. 自动代码生成 :通过 protoc 工具自动生成代码,简化开发流程。

学习建议

如果你刚开始接触 Protobuf,建议按照以下步骤学习:

  1. 编写 .proto 文件

    学习如何定义消息类型和服务接口。

  2. 安装 protoc 编译器

    确保你已经正确安装并配置了 protoc,以便能够生成目标语言的代码。

  3. 尝试序列化和反序列化

    使用生成的代码进行简单的序列化和反序列化练习。

  4. 探索更多功能

    探索 Protobuf 支持的其他特性,如枚举、嵌套消息等。

  5. 结合 gRPC 使用

    在微服务架构中使用 Protobuf 结合 gRPC,体验其强大之处。


六、总结

通过这篇博客,我们了解了如何使用 Protobuf 进行数据的序列化和反序列化,并与传统的 JSON 格式进行了比较。同时也了解到 Protobuf 是一种强大且灵活的数据序列化工具,特别适用于需要高效数据传输的场景。尽管 Protobuf 的数据不可读,但它的高效率和紧凑性使其成为构建分布式系统时的理想选择。

希望这篇文章能帮助你更好地掌握 Protobuf 的基本用法,Protobuf在rpc中的使用非常多,很多大公司都会选择开发自己的Protobuf,通过完善更多的功能,来应对更多的场景。

golang/protobuf: Go support for Google's protocol buffers

这是里面有Protobuf的源码,大家有能力之后,可以根据这个源码,写一套自己的插件。

相关推荐
小饕几秒前
RAG学习之-Rerank 技术详解:从入门到面试
人工智能·学习
爱凤的小光4 分钟前
ROS1/ROS2中TF坐标变换---个人学习篇
学习
报错小能手8 分钟前
ios开发方向——swift并发进阶核心 Task、Actor、await 详解
开发语言·学习·ios·swift
EnglishJun19 分钟前
ARM嵌入式学习(十九)--- 字符设备驱动的注册与调用流程
arm开发·学习
被放养的研究生20 分钟前
vscode-settings.json
ide·vscode·json
Engineer邓祥浩31 分钟前
JVM学习笔记(8) 第三部分 虚拟机执行子系统 第7章 虚拟机类加载机制
jvm·笔记·学习
深蓝海拓34 分钟前
基于QtPy (PySide6) 的PLC-HMI工程项目(七)上位机通信部分的初步建设:socket客户端
网络·笔记·python·学习·plc
送外卖的CV工程师34 分钟前
STM32 CubeMX Makefile 工程编译 入门指南
stm32·单片机·嵌入式硬件·学习·makefile·stm32cubemx
喜欢吃燃面35 分钟前
Linux 进程间通信:命名管道与 System V 共享内存深度解析
linux·运维·服务器·学习
承渊政道1 小时前
【递归、搜索与回溯算法】(递归问题拆解与经典模型实战大秘笈)
数据结构·c++·学习·算法·macos·dfs·bfs