日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

protobuf生成Go代码插件gogo/protobuf

發布時間:2023/12/16 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 protobuf生成Go代码插件gogo/protobuf 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 從json開始

談到序列化,大家最先想到的,可能是 JSON 或者 XML,這兩種序列化協議都是基于文本的編碼方式進行數據傳輸。類似的還有 YAML 等。

JSON 擁有許多優點,使之成為最廣泛使用的序列化協議之一。JSON 協議簡單,人眼可讀,序列化后十分簡潔且解析速度快。此外,JSON 具備 JavaScript 的先天性支持,被廣泛應用于 Web Browser 的應用場景中,并且是 Ajax 的事實標準協議。

JSON 的適用場景比較多,典型應用場景包括:

  • 公司外部之間傳輸數據量相對較小,實時性要求相對低的服務。

  • 基于 Web browser 的 Ajax 請求。

  • 接口經常發生變化,并對可調式性要求較高的場景,例如移動 App 與服務端的通信。

然而,由于 JSON 本身設計的一些特點,在一些場景下使用 JSON 仍然不是最優解。如:

  • 需要標準的 IDL ,增強參與各方業務約束的場景。由于 JSON 協議往往只能使用文檔的方式來進行約定,這可能會給調試帶來一些不便與不明確。

  • 對性能和簡潔性有較高要求的場景。JSON 在一些語言中的序列化和反序列化需要采用反射機制,在性能要求特別高的場景下,可能不是最優解。

  • 對于大數據量服務或持久化場景。JSON 進行序列化的額外空間開銷比較大,這也意味著較大的內存和磁盤開銷。

對于以上場景,使用一些基于 IDL、存儲方案為二進制存儲的序列化方案則更為合適, 如 ProtoBuf、Thrift、avro等。

IDL: 參與通訊的各方需要對通訊的內容做相關的約定。為了建立一個與語言和平臺無關的約定,這個約定需要采用與具體開發語言、平臺無關的語言來進行描述。這種語言被稱為接口描述語言(IDL),采用IDL撰寫的協議約定稱之為IDL文件。

2.?什么是 Protobuf

ProtoBuf 是 Protocol Buffers 的簡稱 ,是 Google 公司開源的一種語言無關、平臺無關、可擴展的序列化結構數據的方案,它可用于(數據)通信協議、數據存儲等。

ProtoBuf 是上述場景中比較適用的序列化方案之一。ProtoBuf 非常靈活、高效,我們可以通過定義 IDL (在這里是proto)文件,然后使用“生成的源代碼”輕松地在各種數據流中使用各種語言進行編寫和讀取結構數據。甚至可以更新數據結構,而不破壞由舊數據結構編譯的已部署程序。

上文提到,同類型的序列化方案還有 Thrift 和 Avro。其中 Thrift 并不僅僅是序列化協議,它被嵌入到 Thrift 框架中,這導致其很難和其他傳輸層協議共同使用;Avro 由于沒有成熟的 JS 實現,不適合 Web 環境, 也導致其使用場景也比較有限。

目前,gRPC 默認的序列化方式是 ProtoBuf。

ProtoBuf 包含序列化格式的定義、各種語言的庫以及一個 IDL 編譯器。正常情況下,我們需要定義?proto?文件,然后使用IDL 編譯器編譯成需要的語言。

3.?一個簡單的?proto?例子

syntax = "proto3"; // proto 版本,建議使用 proto3 option go_package = "main/proto"; // 包名聲明符message SearchRequestParam { // message 類型enum Type { // 枚舉類型PC = 0;Mobile = 1;}string query_text = 1; // 字符串類型 | 后面的「1」為數字標識符,在消息定義中需要唯一int32 limit = 3; // 整型Type type = 4; // 枚舉類型 }message SearchResultPage {repeated string result = 1; // 「repeated」表示字段可以重復任意多次(包括0次)int32 num_results = 2; } // test.proto

代碼中只是一些比較普通的字段定義,還有一些復雜的一些字段定義,如Oneof、Map、Reserved等可以參考官方文檔。

4. 根據?proto?文件生成 Go 代碼

在?proto?文件中定義好需要處理的結構化數據后,可以通過?protoc?工具,將?.proto?文件轉換為 C、C++、Golang、Java、Python 等多種語言的代碼。我們這里嘗試一下生成 Golang 語言代碼。

首先,需要安裝?protoc?工具

# 下載安裝包 (Mac) $ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-osx-x86_64.zip # 解壓到 /usr/local 目錄下 $ unzip protoc-3.15.6-osx-x86_64.zip -d protoc-3.15.6-osx-x86_64 $ mv protoc-3.5.0-osx-x86_64/bin/protoc /usr/local/bin/protoc # 執行如下表示成功: $ protoc --version libprotoc 3.15.6

然后,安裝一個官方生成 Golang 代碼的插件?protoc-gen-go

$ go get -u github.com/golang/protobuf/protoc-gen-go

接著,在?proto文件所在目錄下,執行以下命令以生成go文件:

$ protoc --go_out=. test.proto

protoc?命令還可以使用-I參數指定搜索 import 的?proto?的文件夾。其他參數詳情可以參考官方文檔。

在?proto文件所在目錄下,我們可以看到一個?test.pb.go?文件。其中主要結構體如下:

type SearchRequestParam struct {state protoimpl.MessageStatesizeCache protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsQueryText string `protobuf:"bytes,1,opt,name=query_text..."` Limit int32 `protobuf:"varint,3,opt,name=limit,proto3"...."` Type SearchRequestParam_Type `protobuf:"varint,4,opt,name=type,proto3..."` } type SearchResultPage struct {state protoimpl.MessageStatesizeCache protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsResult []string `protobuf:"bytes,1,rep,name=result,proto3...."`NumResults int32 `protobuf:"varint,2,opt,name=num_results,json=numResults,proto3..."`

接下來,就可以在項目代碼中直接使用 .pb.go?類型文件了。

5. gogo/protobuf 是什么

在上文中,我們安裝了一個「生成 Golang 代碼的插件?protoc-gen-go」,這個插件其實是 golang 官方提供的 一個Protobuf api 實現。我們的主角?gogo/protobuf?是基于?golang/protobuf?的一個增強版實現。

gogo?庫基于官方庫開發,增加了很多的功能,包括:

  • 快速的序列化和反序列化。

  • 更規范的Go數據結構。

  • goprotobuf 兼容。

  • 可選擇的產生一些輔助方法,減少使用中的代碼輸入。

  • 可以選擇產生測試代碼和 benchmark 代碼。

  • 其它序列化格式。

目前,很多知名的項目都在使用該庫,如 etcd、k8s、tidb、docker swarmkit 等。

6. gogo/protobuf 如何使用

在 https://github.com/gogo/protobuf ?根目錄下,我們可以看到有很多文件夾,其中以 「protoc-gen」 為前綴的文件為生成代碼的插件,其他「proto」、「protobuf」、「gogoproto」等為庫文件。

gogo?庫目前有三種生成代碼的方式

  • gofast:速度優先,但此方式不支持其它 gogoprotobuf 的擴展選項。

  • gogofast、gogofaster、gogoslick:速度更快,但會生成更多的代碼。
$ go get github.com/gogo/protobuf/proto $ go get github.com/gogo/protobuf/{binary} // protoc-gen-gogofast、protoc-gen-gogofaster 、protoc-gen-gogoslick $ go get github.com/gogo/protobuf/gogoproto $ protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --{binary}_out=. myproto.proto // 這里的{binary}不包含「protoc-gen」前綴
  • gogofast類似gofast,但是會引入 gogoprotobuf 庫。
  • gogofaster類似gogofast,但是不會產生XXX_unrecognized類的指針字段,可以減少垃圾回收時間。
  • gogoslick類似gogofaster,但是會增加一些額外的string、gostring和equal method等。
  • protoc-gen-gogo:速度最快,可定制化的方式最多。

$?go?get?github.com/gogo/protobuf/proto $?go?get?github.com/gogo/protobuf/jsonpb $?go?get?github.com/gogo/protobuf/protoc-gen-gogo $?go?get?github.com/gogo/protobuf/gogoproto
  • 可以通過擴展選項高度定制序列化。

gogo/protobuf 提供了非常多的擴展選項,以便在產生代碼的時候進行更多的控制。上文提到的擴展選項這里有一個全面的介紹:extensions,擴展選項里主要包含一些生成快速序列化和反序列化代碼的可選項、生成更規范的Golang 數據結構的可選項、goprotobuf 兼容的可選項,一些產生輔助方法的可選項、產生測試代碼和benchmark 的可選項,還可以增加 jsontag 等。

有同學對以上多個生成方式的序列化性能做了一些壓測,在一般需求下,性能差距并不是很大,protoc-gen-gofast方式基本可以滿足大多數場景。

最后,生成的 go 語言代碼在項目中使用就非常簡單了,一般只需要使用proto.Marshal、proto.Unmarshal?方法就可以了,下面是一個例子:

package mainimport ("fmt""log"zaproto "git.xxxxx.com/data/za-proto/proto""github.com/gogo/protobuf/proto" )func main() {req := &zaproto.SearchRequestParam{QueryText: "xxxxxx",Limit: 10,Type: zaproto.SearchRequestParam_PC,}data, err := proto.Marshal(req)if err != nil {log.Fatal("Marshal err : err")}// send datafmt.Println(string(data))var respData []bytevar result = zaproto.SearchResultPage{}if err = proto.Unmarshal(respData, &result); err == nil {fmt.Println(result)} else {log.Fatal("Unmarshal err : err")} }

?

參考:

alecthomas/go_serialization_benchmarks: Benchmarks of Go serialization methods (github.com)

So you want to use?GoGo?Protobuf (jbrandhorst.com)

Schema evolution in Avro, Protocol Buffers and Thrift — Martin Kleppmann’s blog

Language Guide ?| Protocol Buffers ?| Google Developers

序列化和反序列化 - 美團技術團隊 (meituan.com)

Protobuf 有沒有比 JSON 快 5 倍?-InfoQ

幾種Go序列化庫的性能比較 | 鳥窩 (colobu.com)

思考gRPC :為什么是protobuf | 橫云斷嶺的專欄 (hengyunabc.github.io)

幾種Go序列化庫的性能比較 | 鳥窩 (colobu.com)

https://github.com/gogo/protobuf

?

總結

以上是生活随笔為你收集整理的protobuf生成Go代码插件gogo/protobuf的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。