04.2 Protobuf
4.2 Protobuf
Protobuf ( Protocol Buffer ) 是 Google 开发的数据描述语言,可以作为跨语言的 RPC
序列化数据格式。
4.2.1 Protobuf 入门
下面将 Protobuf 和 RPC 结合在一起使用,通过 Protobuf 确保 RPC 的接口安全和规范。
首先创建 hello.proto
,其中包装了 HelloService 服务中用到的字符串类型
syntax = "proto3";
package main;
option go_pacakge = "../protobuffers"; // 需要指定 go package
message User {
string name = 1;
}
syntax
: “proto3” 表示采用 proto3 语法第三版的 Protobuf 对语言进行了简化,所有成员均采用零值初始化(不在支持自定义默认值),因此成员不需要支持 require 特性package
: “main” 指定当前包名, 可以自定义包路径和名称,这里和 Go 包名保持一致以简化代码option go_pacakge
: 决定生成文件的路径及文件包名
在 XML 或 JSON 等数据描述语言中,一般通过成员名称绑定对应的数据。Protobuf 编码通过成员的唯一编号来绑定对应数据,因此 Protobuf 编码后的数据的体积比较小。
要将 .proto
编译成 Go code,需要安装 protobuf 编译器和 Golang 插件
# protoc, 本人开发环境为 Manjaro 直接使用 pacman 安装
sudo pacman -S protoc
# 安装插件
# github.com/golang/protobuf/protoc-gen-go 已经过时
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
生成 go code :
protoc --go_out=. hello.proto
引入 proto 依赖:
go get -u google.golang.org/protobuf/proto
基于生成的代码,重新实现 HelloService 服务
package rpc_objects
import pb "rpc-and-protobuf/hello-protobuf/protobuffers"
type HelloService struct{}
func (HelloService) Hello(request *pb.User, reply *pb.User) error {
reply.Name = "Hello: " + request.GetName()
return nil
}
其中的 Hello 方法的输入参数和输出参数均改用 Protobuf 定义的 User 类型表示,因为新的输入参数为结构体类型,因此改用指针类型作为输入参数。
至此,初步实现了 Protobuf 和 RPC 组合工作。但是在启动 RPC 服务时,依然可以选择 gob 或 json 编码,并未提现出 protobuf 的特性。在之前的示例中为 RPC 服务添加了安全保障,但是得到的代码本身需要非常繁琐的手工维护并且仅适用于 Golang 环境。
我们可以通过在 Protobuf 中定义 RPC 服务来生成 RPC 代码,避免了繁琐的人工维护。
下面在 hello.proto
中定义 HelloService
服务
service HelloService {
rpc Hello(User) returns (User);
}
但是直接重新生成的代码并未发生变化,因为 RPC 实现有很多,protoc 编译器并不直到如何生成服务代码。
不过在
protoc-gen-go
中集成了grpc
插件用于生成gRPC
代码protoc --go_out=plugins=grpc: . hello.proto
新的 google.golang.org/protobuf/cmd/protoc-gen-go
不支持 gRpc 插件,需要使用 google.golang.org/grpc/cmd/protoc-gen-go-grpc
来生成.
// TODO: 实现自定义的 protoc 插件
- 阅读 protoc 官方文档, 了解插件的实现原理
- 阅读相关博客进行实践
Reference
- 4.2 Protobuf Advanced Go Programming
- protocol buffers google docs