記一次奇妙的 go-protobuf 包升級之旅
檢視更多: 歷史集錄
今天聊一個最近升級 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
通過以下方式生成V1.3.5
版本的 pb 檔案
curl -O https://raw.githubusercontent.com/grpc/grpc-go/master/examples/helloworld/helloworld/helloworld.proto
brew install protobuf
GO111MODULE=on go get -u github.com/golang/protobuf/protoc-gen-go@v1.3.5
protoc --go_out=plugins=grpc:. helloworld.proto
再替換github.com/golang/protobuf/protoc-gen-go@v1.4.0
,生成新版 pb 檔案
查詢XXX_Size
函式
舊版中沒問題
// helloword.pb.go
func (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.go
func (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
好,替換方法,第一回合結束
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 executable
Please 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,Repo裡沒有,這是什麼操作?
猜測這問題應該有人遇到吧,果然搜到了 issue:plugins are not supported:grpc
原來是google.golang.org/protobuf
先發布了,裡邊也包含了新版的protoc-gen-go
,
只是其不再支援grpc
生成,需要另一個工具protoc-gen-go-grpc
然而它還沒有釋出,還在Review中。。。(當然目前也不會是穩定版本)
不過,官方也說了,依然可以用舊包github.com/golang/protobuf
的protoc-gen-go-grpc
工具生成grpc
程式碼
因為舊包
protoc-gen-go-grpc
裡依然可以用新包protoc-gen-go-grpc
裡生成 grpc 程式碼的gengogrpc
, 見comment
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
文章首發公眾號:newbmiao
推薦閱讀:Dig101-Go 系列
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- puppeteer爬蟲的奇妙之旅爬蟲
- 記一次版本升級遇到的坑
- 記一次mysql小版本升級MySql
- 記一次macOS Mojave升級GCCMacGC
- Java序列化流的奇妙之旅Java
- Python 列表與字典 排序 的奇妙之旅Python排序
- 記一次奇妙的某個edu滲透測試
- 記一次uboot升級過程的兩個坑boot
- 記一次omi的專案之旅
- 我的風變程式設計“升級”之旅程式設計
- 升級安裝包的製作
- 【經驗】記錄一次MySQL升級的運維實踐MySql運維
- 滴滴HBase大版本滾動升級之旅
- 記 一次 Gentoo Linux 的編譯之旅Linux編譯
- 分散式工具的一次小升級⏫分散式
- 一次系統升級的過程
- RPM包的安裝與升級
- 記一次h5動畫之旅H5動畫
- Flask連線資料庫打怪升級之旅Flask資料庫
- 記一次記憶體飆升的Windbg記憶體
- 物聯網裝置OTA軟體升級之:升級包下載過程之旅
- 卡巴斯基提供升級包 解決病毒庫升級
- 記一次JAVA 程式最佳化之旅Java
- 升級所有Python安裝包Python
- dp安裝包升級步驟
- 晶片科技:從微觀世界到現實應用的奇妙之旅晶片
- 記一次jar包簽名的坑JAR
- 記一次Android逆向之旅(入門向)Android
- 記一次升級Gradle外掛導致相容問題的解決方案Gradle
- 記一次8小時驚心動魄的伺服器+網站升級伺服器網站
- InstallShield製作升級安裝包
- 一次奇妙的任意使用者登入實戰
- 讀ORACLE升級筆記Oracle筆記
- kali linux升級記Linux
- 記一次簡單的wireshark抓包TCPTCP
- MySQL全面瓦解21(番外):一次深夜優化億級資料分頁的奇妙經歷MySql優化
- 記一次阿里雲 Redis 主從版升級到 Redis 叢集版的坑阿里Redis
- 升級MySQL8.0的歷險記MySql