本文介绍如何在 Go 应用中使用 Protocol Buffer 数据。
Protocol Buffer 是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON),和 JSON 或 XML 一样,用于结构化数据序列化或反序列化。该数据格式的优势是较 xml 或 json 更小。
gRPC 默认使用 protocol buffers。
假如我们有一个对象,我们用三种数据结构进行表示:
<person>
<name>Elliot</name>
<age>24</age>
</person>
使用json表示占用空间更小:
{
"name": "Elliot",
"age": 24
}
如果使用protocol buffer格式表示:
[10 6 69 108 108 105 111 116 16 24 ......]
如果您仔细观察上面编码可能会看到,从数组位置2开始名字 ellio t被拼出来,e = 69, l = 108等等。后面是年龄的字节表示,24岁。
性能好/效率高
时间维度:XML,JSON格式对数据进行序列化和反序列化时性能差。
空间维度:XML,JSON格式为了可读性,必然在进行存储数据时,也会消耗空间。
整体而言,Protobuf以高效的二进制方式存储,比XML小3到10倍,快20到100倍。
代码生成机制
代码生成机制能够极大解放开发者编写数据协议解析过程的时间,提高工作效率;于开发者维护和迭代。
支持“向后兼容”和“向前兼容”
支持多种编程语言
Protocol buffer 不仅是 Google 开源的一个数据协议,还有很多种语言的开源项目实现。
可读性较差
为了提高性能,Protobuf采用了二进制格式进行编码。二进制格式编码对于开发者来说,是没办法阅读的。在进行程序调试时,比较困难。对于可读性要求高的数据报文程序就不建议使用。
缺乏自描述
Protocol buffer 是通过二进制格式进行数据传输,开发者面对二进制格式的 Protocol buffer,没有办法知道所对应的真实的数据结构,因此在使用Protobuf协议传输时,必须配备对应的proto配置文件。
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
如 :/protos/person.proto
// 声明规则版本
syntax = "proto3";
// 指定生成的包名
option go_package = "./protos";
// 定义Person结构体
message Person {
int32 id = 1;
string name = 2;
string email = 3;
}
生成 .go 文件
protoc --proto_path=./protos --go_out=. person.proto
编写 main.go 运行测试
package main
import (
"fmt"
"pb/protos"
"google.golang.org/protobuf/proto"
)
func main() {
p1 := &protos.Person{
Id: 1,
Name: "John",
Email: "john@gmail.com",
}
fmt.Println("原始数据:", p1)
// 序列化
dataMarshal, err := proto.Marshal(p1)
if err != nil {
fmt.Println("proto.Unmarshal.Err: ", err)
return
}
fmt.Println("编码数据:", dataMarshal)
// 反序列化
entity := protos.Person{}
err = proto.Unmarshal(dataMarshal, &entity)
if err != nil {
fmt.Println("proto.Unmarshal.Err: ", err)
return
}
fmt.Printf("解码数据: ID:%d 姓名:%s 邮箱:%s ", entity.GetId(), entity.GetName(), entity.GetEmail())
}