go語言的gRPC教程-protobuf基礎

一、前言

RPC,全稱Remote Procedure Call,中文譯為遠程過程調用。通俗地講,使用RPC進行通信,調用遠程函數就像調用本地函數一樣,RPC底層會做好數據的序列化與傳輸,從而能使我們更輕松地創建分布式應用和服務。

gRPC是谷歌開源的一款高性能、支持多種開發語言的服務框架,對于一個rpc我們關注如下幾方面:

序列化協議gRPC使用protobuf,首先使用protobuf定義服務,然后使用這個文件來生成客戶端和服務端的代碼。因為pb是跨語言的,因此即使服務端和客戶端語言并不一致也是可以互相序列化和反序列化的

網絡傳輸層。gRPC使用http2.0協議,http2.0相比于HTTP 1.x ,大幅度的提升了 web 性能。
在這里插入圖片描述

二、Protobuf IDL

所謂序列化通俗來說就是把內存的一段數據轉化成二進制并存儲或者通過網絡傳輸,而讀取磁盤或另一端收到后可以在內存中重建這段數據

1、protobuf協議是跨語言跨平臺的序列化協議。

2、protobuf本身并不是和gRPC綁定的。它也可以被用于非RPC場景,如存儲等

json xml都是一種序列化的方式,只是他們不需要提前預定義idl,且具備可讀性,當然他們傳輸的體積也因此較大,可以說是各有優劣

所以先來介紹下protobuf的idl怎么寫。protobuf最新版本為proto3,在這里你可以看到詳細的文檔說明:https://protobuf.dev/programming-guides/proto3/

2.1、定義消息類型

protobuf里最基本的類型就是message,每一個messgae都會有一個或者多個字段(field),其中字段包含如下元素

在這里插入圖片描述

  • 類型:類型不僅可以是標量類型(intstring等),也可以是復合類型(enum等),也可以是其他message

  • 字段名:字段名比較推薦的是使用下劃線/分隔名稱

  • 字段編號:一個messgae內每一個字段編號都必須唯一的,在編碼后其實傳遞的是這個編號而不是字段名

  • 字段規則:消息字段可以是以下字段之一

    • singular:格式正確的消息可以有零個或一個字段(但不能超過一個)。使用 proto3 語法時,如果未為給定字段指定其他字段規則,則這是默認字段規則
    • optional:與 singular 相同,不過您可以檢查該值是否明確設置
    • repeated:在格式正確的消息中,此字段類型可以重復零次或多次。系統會保留重復值的順序
    • map:這是一個成對的鍵值對字段
  • 保留字段:為了避免再次使用到已移除的字段可以設定保留字段。如果任何未來用戶嘗試使用這些字段標識符,編譯器就會報錯

2.2、標量值類

標量類型會涉及到不同語言和編碼方式:

.proto TypeGo TypeNotes
doublefloat64
floatfloat32
int32int32使用可變長度的編碼。對負數的編碼效率低下 - 如果您的字段可能包含負值,請改用 sint32。
int64int64使用可變長度的編碼。對負數的編碼效率低下 - 如果字段可能有負值,請改用 sint64。
uint32uint32使用可變長度的編碼。
uint64uint64使用可變長度的編碼。
sint32int32使用可變長度的編碼。有符號整數值。與常規 int32 相比,這些函數可以更高效地對負數進行編碼。
sint64int64使用可變長度的編碼。有符號整數值。與常規 int64 相比,這些函數可以更高效地對負數進行編碼。
fixed32uint32始終為 4 個字節。如果值通常大于 2^28,則比 uint32 更高效。
fixed64uint64始終為 8 個字節。如果值通常大于 2^56,則比 uint64 更高效。
sfixed32int32始終為 4 個字節。
sfixed64int64始終為 8 個字節。
boolbool
stringstring字符串必須始終包含 UTF-8 編碼或 7 位 ASCII 文本,并且長度不得超過 232。
bytes[]byte可以包含任意長度的 2^32 字節。

2.3、復合類型

(1)數組
message SearchResponse {repeated Result results = 1;
}message Result {string url = 1;string title = 2;repeated string snippets = 3;
}
(2)枚舉
message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}
(3)服務

定義的method僅能有一個入參和出參數。如果需要傳遞多個參數需要定義成message

service SearchService {rpc Search(SearchRequest) returns (SearchResponse);
}

2.4、使用其他消息類型

使用import引用另外一個文件的pb

syntax = "proto3";import "google/protobuf/wrappers.proto";package ecommerce;message Order {string id = 1;repeated string items = 2;string description = 3;float price = 4;google.protobuf.StringValue destination = 5;
}

三、protoc使用

protoc就是protobuf的編譯器,它把proto文件編譯成不同的語言

3.1、安裝

https://github.com/google/protobuf/releases
在這里插入圖片描述

  • Windows 下載壓縮包解壓,并添加解壓路徑中的 bin 文件夾路徑到環境變量Path中,新開終端 protoc --version驗證安裝。

  • Linux, using apt or apt-get, for example:

$ apt install -y protobuf-compiler
$ protoc --version  # Ensure compiler version is 3+
  • MacOS, using Homebrew:
$ brew install protobuf
$ protoc --version  # Ensure compiler version is 3+

3.2、使用

$ protoc --help
Usage: protoc [OPTION] PROTO_FILES-IPATH, --proto_path=PATH   #指定搜索路徑--plugin=EXECUTABLE: # 指定要使用的插件可執行文件。通常,protocol會在PATH中搜索插件....--cpp_out=OUT_DIR           Generate C++ header and source.--csharp_out=OUT_DIR        Generate C# source file.--java_out=OUT_DIR          Generate Java source file.--js_out=OUT_DIR            Generate JavaScript source.--objc_out=OUT_DIR          Generate Objective C header and source.--php_out=OUT_DIR           Generate PHP source file.--python_out=OUT_DIR        Generate Python source file.--ruby_out=OUT_DIR          Generate Ruby source file@<filename>                #proto文件的具體位置
(1) 搜索路徑參數

第一個比較重要的參數就是搜索路徑參數,即上述展示的-IPATH, --proto_path=PATH。它表示的是我們要在哪個路徑下搜索.proto文件,這個參數既可以用-I指定,也可以使用--proto_path=指定。

如果不指定該參數,則默認在當前路徑下進行搜索;另外,該參數也可以指定多次,這也意味著我們可以指定多個路徑進行搜索。

(2) 語言插件參數

語言參數即上述的--cpp_out=--python_out=等,protoc支持的語言長達13種,且都是比較常見的

運行help出現的語言參數,說明protoc本身已經內置該語言對應的編譯插件,我們無需安裝

LanguageGenerated CodeSource
C++ (include C++ runtime and protoc)C++src
JavaJavajava
PythonPythonpython
Objective-CObjective-Cobjectivec
C#C#csharp
RubyRubyruby
PHPPHPphp

下面的語言是由google維護,通過protoc的插件機制來實現,所以倉庫單獨維護

  • Dart
  • Go
(3) proto文件位置參數

proto文件位置參數即上述的@<filename>參數,指定了我們proto文件的具體位置,如proto1/greeter/greeter.proto

3.3、 語言插件

(1) golang插件

非內置的語言支持就得自己單獨安裝語言插件,比如--go_out=對應的是protoc-gen-go,安裝命令如下:

# 最新版
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest# 指定版本
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.3.0

可以使用下面的命令來生成代碼

$ protoc --proto_path=src --go_out=. --go_opt=paths=source_relative foo.proto bar/baz.proto
注意

protoc-gen-go要求pb文件必須指定go包的路徑,即

option go_package = ".;streaming";
----proto_path

這個選項用于指定 protoc 編譯器在查找 .proto 文件時應該搜索的根目錄。當你在 .proto 文件中使用 import 語句導入其他 .proto 文件時,編譯器需要知道去哪里找到這些被導入的文件

–go_out

指定go代碼生成的基本路徑

–go_opt:設定插件參數

protoc-gen-go提供了 --go_opt 來為其指定參數,并可以設置多個

1、如果使用 paths=import , 生成的文件會按go_package路徑來生成,當然是在--go_out目錄下,即

$go_out/$go_package/pb_filename.pb.go

2、如果使用 paths=source_relative , 就在當前pb文件同路徑下生成代碼。注意pb的目錄也被包含進去了。即

$go_out/$pb_filedir/$pb_filename.pb.go
(2) grpc go插件

google.golang.org/protobuf中,protoc-gen-go純粹用來生成pb序列化相關的文件,不再承載gRPC代碼生成功能。

生成gRPC相關代碼需要安裝grpc-go相關的插件protoc-gen-go-grpc

 $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

執行code gen命令

$ protoc --go_out=. --go_opt=paths=source_relative \--go-grpc_out=. --go-grpc_opt=paths=source_relative \routeguide/route_guide.proto
–go-grpc_out

指定grpc go代碼生成的基本路徑

命令會產生如下文件

  • route_guide.pb.go: protoc-gen-go的產出物,包含所有類型的序列化和反序列化代碼

  • route_guide_grpc.pb.go: protoc-gen-go-grpc的產出物,包含

    • 定義在 RouteGuide service中的用來給client調用的接口定義
    • 定義在 RouteGuide service中的用來給服務端實現的接口定義
–go-grpc_opt

protoc-gen-go類似,protoc-gen-go-grpc提供 --go-grpc_opt 來指定參數,并可以設置多個

? github.com/golang/protobuf vs google.golang.org/protobuf

github.com/golang/protobuf雖然已經廢棄,但網上搜索時經常還能搜到,方便理解整理兩者區別。

代碼差異

這兩個庫,google.golang.org/protobufgithub.com/golang/protobuf的升級版本,v1.4.0之后github.com/golang/protobuf僅是google.golang.org/protobuf的包裝

功能差異

google.golang.org/protobuf,純粹用來生成pb序列化相關的文件,不再承載gRPC代碼生成功能。生成gRPC相關代碼需要安裝grpc-go相關的插件protoc-gen-go-grpc

github.com/golang/protobuf ,可以同時生成pb和gRPC相關代碼的

用法差異

google.golang.org/protobuf

$ protoc --go_out=. --go_opt=paths=source_relative \--go-grpc_out=. --go-grpc_opt=paths=source_relative \routeguide/route_guide.proto

github.com/golang/protobuf

$ protoc --go_out=plugins=grpc,paths=import:. \routeguide/route_guide.proto

--go_out的寫法是,參數之間用逗號隔開,最后加上冒號來指定代碼的生成位置,比如--go_out=plugins=grpc,paths=import:.

--go_out主要的兩個參數為pluginspaths,分別表示生成Go代碼所使用的插件,以及生成的Go代碼的位置。

plugins參數有不帶grpc和帶grpc兩種,兩者的區別如下,帶grpc的會多一些跟gRPC相關的代碼,實現gRPC通信

paths參數有兩個選項,分別是 importsource_relative,默認為 import

  • import表示按照生成的Go代碼的包的全路徑去創建目錄層級
  • source_relative 表示按照 proto源文件的目錄層級去創建Go代碼的目錄層級,如果目錄已存在則不用創建。

總之,用google.golang.org/protobuf就對了!

Buf 工具

可以看到使用protoc的時候,當使用的插件逐漸變多,插件參數逐漸變多時,命令行執行并不是很方便和直觀。例如后面使用到了grpc-gateway+swagger插件時

$ protoc -I ./pb \--go_out ./ecommerce --go_opt paths=source_relative \--go-grpc_out ./ecommerce --go-grpc_opt paths=source_relative \--grpc-gateway_out ./ecommerce --grpc-gateway_opt paths=source_relative \--openapiv2_out ./doc --openapiv2_opt logtostderr=true \./pb/ecommerce/v1/product.proto

其次依賴某些外部的protobuf文件時,只能通過拷貝到本地的方式,也不夠方便

因此誕生了? Buf 這個項目,它除了能解決上述問題,還有額外的功能

  • 不兼容破壞檢查
  • linter
  • 集中式的版本管理

初始化模塊

在pb文件的根目錄執行,為這個pb目錄創建一個buf的模塊。此后便可以使用buf的各種命令來管理這個buf模塊了

$ buf mod init

此時會在根目錄多出一個buf.yaml文件,內容為

# buf.yaml
version: v1
breaking:use:- FILE
lint:use:- DEFAULT

Lint pb文件

$ buf lint
ecommerce/v1/product.proto:10:9:Service name "ServiceOrderManagement" should be suffixed with "Service".
ecommerce/v1/product.proto:11:18:RPC request type "getOrderReq" should be named "GetOrderRequest" or "ServiceOrderManagementGetOrderRequest".

調整lint規則

 # buf.yamlversion: v1breaking:use:- FILElint:use:- DEFAULT
+  except:
+    - PACKAGE_VERSION_SUFFIX
+    - FIELD_LOWER_SNAKE_CASE
+    - SERVICE_SUFFIX

生成代碼

插件:和使用protoc一樣,該裝的插件一樣要裝

插件模版

創建一個buf.gen.yaml ,它是buf生成代碼的配置。上面的protoc同等功能的buf.gen.yaml可以寫成如下形式,相對protoc更加直觀

# buf.gen.yaml
version: v1
plugins:- plugin: goout: ecommerceopt:- paths=source_relative- plugin: go-grpcout: ecommerceopt:- paths=source_relative- name: grpc-gatewayout: ecommerceopt:- paths=source_relative- generate_unbound_methods=true- name: openapiv2out: docopt:- logtostderr=true

生成代碼

buf generate pb

buf generate 命令將會

  • 搜索每一個buf.yaml配置里的所有protobuf文件
  • 復制所有protobuf文件到內存
  • 編譯所有protobuf文件
  • 執行模版文件里的每一個插件

添加依賴

在使用grpc-gateway時依賴了google.api.http,在不使用buf的場景,我們需要手動復制.proto到本地。

buf為我們提供了 Buf Schema Registry (BSR),除了可以使用其他人發布的模塊,也可以把我們自己的模塊發布到BSR

在模塊的文件里聲明依賴項

 # buf.yamlversion: v1breaking:use:- FILElint:use:- DEFAULT
+deps:
+  - buf.build/googleapis/googleapis

然后執行

buf mod update

buf mod update 把你所有的 deps 更新到最新版。并且會生成 buf.lock 來固定版本

# Generated by buf. DO NOT EDIT.
version: v1
deps:- remote: buf.buildowner: googleapisrepository: googleapiscommit: 75b4300737fb4efca0831636be94e517

此時執行buf generate pb 即使本地沒有依賴,也不會再報錯缺少依賴了

參考

  • Buf 官方文檔
  • Protocol Buffers Documentation
  • https://segmentfault.com/a/1190000043353574

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916899.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916899.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916899.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux基本指令,對路徑的認識

引言簡單介紹一些Linux的基本指令&#xff0c;快速上手Linux操作系統。一、ls指令語法&#xff1a;ls [選項] [目錄或文件]功能&#xff1a;&#xff1a;對于目錄&#xff0c;該命令列出該目錄下的所有子目錄與文件。對于文件件&#xff0c;將列出文件名以及其他信息常用選項&a…

25. html 使用的字符集是什么,有什么特點

總結 utf-8&#xff0c;支持所有語言一、HTML 默認使用的字符集? HTML 頁面推薦使用 UTF-8 字符集<meta charset"UTF-8" />這是 HTML5 中推薦的標準字符編碼&#xff0c;用于定義網頁中字符的編碼方式。二、什么是字符集&#xff08;Character Encoding&#…

MySQL 讀寫分離(含示例代碼)

背景 面對日益增加的系統訪問量,數據庫的吞吐量面臨著巨大瓶頸。對于同一時刻有大量并發讀操作和較少寫操作類型的應用系統來說,將數據庫拆分為主庫和從庫,主庫負責處理事務性的增刪改操作,從庫負責處理查詢操作,能夠有效的避免由數據更新導致的行鎖,使得整個系統的查詢性…

C#中Visual Studio平臺按照OfficeOpenXml步驟

找到包的地址&#xff1a; NuGet Gallery | DocumentFormat.OpenXml.Framework 3.3.0 https://nuget.info/packages 報錯&#xff1a; 嚴重性 代碼 說明 項目 文件 行 禁止顯示狀態 錯誤 無法解析依賴項“EPPlus”。使用的源: Officeopenxml, Mic…

【Linux】重生之從零開始學習運維之備份恢復

備份恢復準備工作16主機-ubuntu系統準備日志目錄mkdir -p /data/mysql/logs/ chown mysql:mysql -R /data/mysql定制日志配置vim /etc/mysql/mariadb.conf.d/50-server.cnf log_bin/data/mysql/logs/binlog systemctl restart mariadb刪除db1數據庫drop database db1;13主機-ub…

VoIP技術全面深度學習指南:從原理到實踐的認知進化

一、VoIP技術的本質認知與歷史演進 1.1 技術本質的深層理解 VoIP&#xff08;Voice over Internet Protocol&#xff0c;IP語音傳輸&#xff09;從根本上代表了通信技術的范式轉換。這不僅僅是將模擬語音信號數字化那么簡單&#xff0c;而是將傳統的電路交換模式徹底轉向包交換…

CentOS Nginx 1.13.9 部署文檔

以下是 Nginx 1.13.9 的詳細安裝步驟&#xff08;基于 CentOS/Ubuntu 系統&#xff09;&#xff1a;1. 安裝依賴 CentOS/RHEL sudo yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-develUbuntu/Debian sudo apt update && sudo apt install -y b…

CSS-in-JS 動態主題切換與首屏渲染優化

動態主題切換的實現方式1. 使用 CSS 變量&#xff08;CSS Custom Properties&#xff09;CSS 變量是實現主題切換最直接的方式&#xff1a;:root {--primary-color: #4285f4;--background-color: #ffffff;--text-color: #333333; }[data-theme"dark"] {--primary-col…

不止 “聽懂”,更能 “感知”!移遠通信全新AI 音頻模組 重新定義智能家居“聽覺”邏輯

7月29日&#xff0c;在 2025 世界人工智能大會&#xff08;WAIC&#xff09;期間&#xff0c;移遠通信正式發布全新 VA500-GL AI 音頻模組。該產品基于本地化 AI 算法&#xff0c;為智能家電賦予精準 “聽覺” 與主動交互能力&#xff0c;借助環境狀態智能檢測、離線語音控制及…

【Python】 切割圖集的小腳本

Python 切割圖片腳本 前言&#xff1a; 有短時間沒寫博客了&#xff0c;今天打算再寫一篇MonoGame的教程&#xff0c;這篇是我再做我自己的2D 游戲項目的時候我需要一些已經切割好的圖片但我得到圖片是合在一起圖集&#xff0c;這個腳本適合正在做2D游戲開發且不依賴于游戲引…

網絡安全是什么?手把手教你認識網絡安全

網絡安全是什么&#xff1f;手把手教你認識網絡安全 提到網絡安全&#xff0c;不少人會聯想到電影里黑客指尖翻飛攻破系統的炫酷場景。但實際上&#xff0c;它并非遙不可及的技術名詞&#xff0c;而是與我們日常生活息息相關的 “數字保鏢”。從手機支付密碼到社交賬號信息&am…

AtCoder Beginner Contest 416(2025.7.26)

文章目錄A Vacation ValidationB 1D Akari&#xff08;補&#xff09;C Concat (X-th)&#xff08;補&#xff09;題目考查題意簡述解法思路 &#xff1a;AC代碼D Match, Mod, Minimize 2&#xff08;補&#xff09;題目分數/評級題目考查時間復雜度題意簡述解法思路 &#xff…

基于 Hadoop 生態圈的數據倉庫實踐 —— OLAP 與數據可視化(五)

目錄 五、Hue、Zeppelin 比較 1. Zeppelin 簡介 2. Zeppelin 安裝配置 &#xff08;1&#xff09;安裝環境 &#xff08;2&#xff09;Zeppelin 及其相關組件 &#xff08;3&#xff09;配置 Zeppelin &#xff08;4&#xff09;啟動 Zeppelin &#xff08;5&#xff0…

《消息隊列學習指南:從 MQ 基礎到 SpringAMQP 實踐》

初識MQ 同步調用 目前我們采用的是基于OpenFeign的同步調用&#xff0c;也就是說業務執行流程是這樣的&#xff1a; 支付服務需要先調用用戶服務完成余額扣減 然后支付服務自己要更新支付流水單的狀態 然后支付服務調用交易服務&#xff0c;更新業務訂單狀態為已支付 三個…

深度學習 --- 過擬合與欠擬合

深度學習 — 過擬合與欠擬合 文章目錄深度學習 --- 過擬合與欠擬合一.概念1.1 過擬合1.2 欠擬合1.3 判斷方式二&#xff0c;解決欠擬合三&#xff0c;解決過擬合3.1 L2正則化3.1.1 定義以及作用3.1.2 代碼3.2 L1正則化3.3 L1與L2對比3.4 Dropout示例3.5 數據增強3.5.1 圖片縮放…

Python 之抽象方法 @abstractmethod 的理解

如果你熟悉 Java 的話&#xff0c;Java 里有一個抽象接口的概念&#xff0c;Python 里的抽象方法基本上與其類似。在 Python 中&#xff0c;abstractmethod 是一個裝飾器&#xff0c;用于定義抽象方法。它是實現抽象基類&#xff08;Abstract Base Class, ABC&#xff09;的核心…

深度學習·pytorch

廣播機制 從末尾開始逐個維度遍歷兩個矩陣的shape&#xff0c;如果維度不相同&#xff0c;則考慮廣播&#xff1a;任一方的維度為1或者維度不存在(小矩陣廣播為大矩陣)&#xff0c;這樣的運算可以廣播 可以廣播的例子 xtorch.empty(5,3,4,1) ytorch.empty(3,1,1) (x.add_(y)).s…

SpringBoot集成deepseek

pom文件&#xff1a;<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…

JetBrains Annotations:從入門到落地,徹底告別 NullPointerException

本文基于三篇高質量博客&#xff08;JetBrains Annotations官方文檔、Jakarta Validation 規范、《Effective Java》第3版&#xff09;的原文內容&#xff0c;結合作者在一線研發團隊落地 JetBrains Annotations 的實戰經驗&#xff0c;系統梳理了該注解庫的核心能力、使用姿勢…

基于Rust與HDFS、YARN、Hue、ZooKeeper、MySQL

基于Rust與HDFS、YARN、Hue、ZooKeeper、MySQL集合 以下是基于Rust與HDFS、YARN、Hue、ZooKeeper、MySQL等技術棧結合的實例,涵蓋不同場景和應用方向: 數據處理與分析 使用Rust編寫MapReduce作業,通過YARN提交到HDFS處理大規模數據集。Rust的高性能特性適合處理密集型計算…