今天聊一个最近升级 go 的protobuf
的故事。过程很是奇妙(曲折)😳
前两天,一个项目的dependabot
提示包 github.com/golang/protobuf
可以从V1.3.5
升级到 V1.4.0
Round One
本以为直接升级就行,但是没过 CI,是发现旧版(V1.3.5
)测试代码用了 pb 生成代码的XXX_Size()
方法计算消息大小
在新版(v1.4.0
)里 panic
了
我们来看下他们有啥不同:
为简化,我们 proto 文件用官方的helloworld.proto[1]
通过以下方式生成V1.3.5
版本的 pb 文件
curl -O https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.protobrew install protobufGO111MODULE=on go get -u github.com/golang/protobuf/protoc-gen-go@v1.3.5protoc --go_out=plugins=grpc:. helloworld.proto
再替换github.com/golang/protobuf/protoc-gen-go@v1.4.0
,生成新版 pb 文件
查找XXX_Size
函数
旧版中没问题
// helloword.pb.gofunc (m *HelloRequest) XXX_Size() int { return xxx_messageInfo_HelloRequest.Size(m)}var xxx_messageInfo_HelloRequest proto.InternalMessageInfo// github.com/golang/protobuf@v1.3.5/proto/table_marshal.gofunc (a *InternalMessageInfo) Size(msg Message) int {
新版 pb 文件中没有了InternalMessageInfo
类型
但源码中能找到,是被废弃了。
// github.com/golang/protobuf@v1.4.0/proto/deprecated.go// Deprecated: Do not use.type InternalMessageInfo struct{}func (*InternalMessageInfo) Size(Message) int { panic("not implemented") }// 同样废弃的还有:DiscardUnknown, Marshal, Merge, Unmarshal
那新版代码中怎么获取大小?
查看源码中例子,proto.Size(m Message) int
可以实现
InternalMessageInfo
也变成了接口 type Message = protoiface.MessageV1
这个InternalMessageInfo
的废弃在版本升级中也提到了,详见 generated-code[2]
好,替换方法,第一回合结束
Round Two
等等,再仔细看了下github.com/golang/protobuf
文档,里边提到 v1.4.0
版本后, 后边代码将交由google.golang.org/protobuf
Repo 维护,看来谷歌要把 pb 的包都收到自己组织下
那我顺手直接把grpc
生成工具也替换过去呗!
GO111MODULE=on go get -u google.golang.org/protobuf/cmd/protoc-gen-go@v1.21.0
再次生成代码
新工具自动提示要求 proto 文件中增加:
option go_package = ".;helloworld";
居然失败了。。。提示:
--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC
难道是新增了 flag,尝试:
protoc --go-grpc_out=. helloworld.proto
What? 失败+1。。。
protoc-gen-go-grpc: program not found or is not executablePlease specify a program using absolute path or make sure the program is available in your PATH system variable--go-grpc_out: protoc-gen-go-grpc: Plugin failed with status code 1.
protoc-gen-go-grpc
是新工具?
搜了下,确实有这个工具,说新版本会用他来生成grpc
,主要是为了更好支持 protobuf reflection
这里说一下:
proto 文件中的
service
是需要grpc
的plugin
才能生成对应 pb 代码 所以旧版工具有参数--go_out=plugins=grpc:
尝试安装下:
GO111MODULE=on go get google.golang.org/protobuf/cmd/protoc-gen-go-grpc
失败+2。。。
go get google.golang.org/protobuf/cmd/protoc-gen-go-grpc: module google.golang.org/protobuf@upgrade found (v1.21.0), but does not contain package google.golang.org/protobuf/cmd/protoc-gen-go-grpc
goDoc 里有protoc-gen-go-grpc[3], Repo[4]里没有,这是什么操作?
猜测这问题应该有人遇到吧,果然搜到了 issue:plugins are not supported:grpc[5]
原来是google.golang.org/protobuf
先发布了,里边也包含了新版的 protoc-gen-go
,
只是其不再支持grpc
生成,需要另一个工具 protoc-gen-go-grpc
然而它还没有发布,还在Review[6]中。。。(当然目前也不会是稳定版本)
不过,官方也说了,依然可以用旧包github.com/golang/protobuf
的 protoc-gen-go-grpc
工具生成grpc
代码
因为旧包
protoc-gen-go-grpc
里依然可以用新包protoc-gen-go-grpc
里生成 grpc 代码的gengogrpc
, 见comment[7]
Round Three
好吧,那就只升级代码中调用的 protobuf 为google.golang.org/protobuf@v1.21.0
,代码生成工具还用旧版里 github.com/golang/protobuf/protoc-gen-go@v1.4.0
吧
再次生成 pb 文件, 终于没有问题了, peace finally
proto "github.com/golang/protobuf/proto"grpc "google.golang.org/grpc"codes "google.golang.org/grpc/codes"status "google.golang.org/grpc/status"protoreflect "google.golang.org/protobuf/reflect/protoreflect"protoimpl "google.golang.org/protobuf/runtime/protoimpl"
只是看着生成代码里的依然需要import
的旧包 github.com/golang/protobuf
,总感觉哪里怪怪的
升级完了,却依赖了两种protobuf
包。。。
最后,劝大家不着急就再等等再升级吧
(另外没事干升级到新包干什么!)
当然这次 protobuf 的 breaking change 还是很有意义的,不仅让将 protobuf 反射作为 pb 的一级功能,还提供了很多处理工具,详细看下: v1.21.0-release [8]
参考资料
[1]helloworld.proto: https://github.com/grpc/grpc-go/blob/master/examples/helloworld/helloworld/helloworld.proto
[2]generated-code: https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.20.0#v1.20-generated-code
[3]protoc-gen-go-grpc: https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go-grpc?tab=overview
[4]Repo: https://github.com/protocolbuffers/protobuf-go
[5]plugins are not supported:grpc: https://github.com/golang/protobuf/issues/1070#issuecomment-607465055
[6]Review: https://github.com/grpc/grpc-go/pull/3453
[7]comment: https://github.com/grpc/grpc-go/pull/3453#issuecomment-600879894
[8]v1.21.0-release: https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.21.0
推荐阅读
如果有用,点个 在看 ,让更多人看到
外链不能跳转,戳 阅读原文 查看参考资料