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

 一、Protobuf 简介

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

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


 二、项目准备

1. 定义 .proto 文件

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

syntax = "proto3";

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


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

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

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

protoc --go_out=. --go-grpc_out=. helloworld.proto

//这个命令使用了两个输出插件:--go_out=. 和 --go-grpc_out=.。它分别调用了 Go 相关的 Protobuf 插件和 gRPC Go 插件来生成对应的目标文件。其中:
//--go_out=. 表示使用 Go 的 Protobuf 编译插件生成对应的 Go 文件。
//--go-grpc_out=. 表示使用 Go 的 gRPC 编译插件生成 gRPC 服务相关的 Go 文件。

这条命令会根据 helloworld.proto 文件生成相应的 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 数据:

{
  "name": "Bob"
}

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

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的源码,大家有能力之后,可以根据这个源码,写一套自己的插件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值