Go gRPC 入門與實(shí)踐

一. gRPC 是什么

  1. 官網(wǎng)簡(jiǎn)介: A high-performance, open-source universal RPC framework
    • gRPC 是一個(gè)高性能的, 開源統(tǒng)一的 RPC 框架
  2. RPC (Remote Procedure Calls), 是指遠(yuǎn)程過程調(diào)用
    • 包含了傳輸協(xié)議和編碼 (對(duì)象序列號(hào)) 協(xié)議
    • 服務(wù)的程序 A 調(diào)用另一臺(tái)服務(wù)的程序 B
  3. 除了 gRPC 框架之外, 還有 net/rpc (go 標(biāo)準(zhǔn)庫(kù)), Thrift (C++), Motan, Dubbo (Java) 等 RPC 框架.
    • 衍生出來的框架一般都具備簡(jiǎn)單, 通用, 安全, 效率等特點(diǎn)
  4. 是基于 http 開發(fā)的, 不同的是 RPC:
    • 是長(zhǎng)鏈接, 不必每次通信都要像 HTTP 一樣去 3 次握手什么的, 減少了網(wǎng)絡(luò)開銷
    • 對(duì)數(shù)據(jù)進(jìn)行深度編碼和解碼, 減少了對(duì)網(wǎng)絡(luò)帶寬的壓力
    • 一般都有注冊(cè)中心, 有豐富的監(jiān)控管理
    • 發(fā)布、下線接口赏枚、動(dòng)態(tài)擴(kuò)展等, 對(duì)調(diào)用方來說是無感知枚冗、統(tǒng)一化的操作
    • 參考: 有了HTTP,為什么還要RPC?

二. gRPC 的用途

  1. 一般應(yīng)用于大型的系統(tǒng), 提高性能和效率
  2. gRPC 是微服務(wù)架構(gòu)中, 首選的 RPC 框架之一

三. gRPC 的特點(diǎn)有哪些特點(diǎn), 為什么要使用它

  1. 支持多種語(yǔ)言
  2. 輕量級(jí), 高性能
    • 序列化支持 Protocol Buffer 和 Json
    • Json 是由 JavaScript 動(dòng)態(tài)語(yǔ)言推廣出來的, 特性是隨著 JavaScript, 字段和數(shù)據(jù)類型是可以隨意定義的
    • Protocol Buffer 的字段和數(shù)據(jù)類型是預(yù)定義的, 更適合靜態(tài)語(yǔ)言, 更安全. 另外 Protocol Buffer 是一種語(yǔ)言無關(guān)的高性能序列化框架
    • Protocol Buffer 可以加速站點(diǎn)之間數(shù)據(jù)傳輸速度, 解決數(shù)據(jù)傳輸不規(guī)范的問題
  3. 可插拔
  4. IDL
    • 基于文件定義服務(wù), 通過 proto3 工具生成指定語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)撵溃、服務(wù)端接口以及客戶端 Stub
  5. 基于標(biāo)準(zhǔn)的 HTTP2 設(shè)計(jì)
    • 支持雙向流邢笙、消息頭壓縮、單 TCP 的多路復(fù)用腥寇、服務(wù)端推送等特性
    • 這些特性使得 gRPC 在移動(dòng)端設(shè)備上更加省電和節(jié)省網(wǎng)絡(luò)流量
  6. 服務(wù)而非對(duì)象成翩、消息而非引用
    • 有利于解耦
    • 促進(jìn)微服務(wù)的系統(tǒng)間, 粗粒度的消息交互
  7. 負(fù)載無關(guān)
    • 不同的服務(wù)需要使用不同的消息類型和編碼
  8. 阻塞式和非阻塞式
    • 支持異步和同步處理在客戶端和服務(wù)端間交互的消息序列
  9. 元數(shù)據(jù)交換
    • 常見的橫切關(guān)注點(diǎn), 依賴數(shù)據(jù)交換
  10. 標(biāo)準(zhǔn)化狀態(tài)碼
    • 客戶端通常以有限的方式響應(yīng) API 調(diào)用返回的錯(cuò)誤
  11. 良好的設(shè)計(jì)理念
    • 生態(tài)好

四. gRPC 實(shí)踐

目標(biāo): 一步一步實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 gRPC 示例

1. 開發(fā)環(huán)境

  • macOS
  • go 1.15

2. 安裝依賴和環(huán)境配置

  • 安裝 protobuf 工具
# 使用 brew 命令
# 安裝 protobuf, 即安裝 protoc 可執(zhí)行文件/命令
brew install protobuf
  • 安裝 go-gRPC 工具, 配置環(huán)境

參考: Quick start | Go | gRPC

# 安裝 Go-gRPC 的編譯器插件
# 用于生成 *.pb.go 和 *_grpc.pb.go 兩個(gè)文件所需的 (在 $GOPATH/bin 下)
go get google.golang.org/protobuf/cmd/protoc-gen-go \
         google.golang.org/grpc/cmd/protoc-gen-go-grpc

# go mod
export GO111MODULE=on  # Enable module mode
# protoc 編譯器可以找到的插件路徑
export PATH="$PATH:$(go env GOPATH)/bin"

3. 編寫和編譯 proto

  • sayhello.proto
// 指定使用 proto3 版本
syntax = "proto3";

// 隨便定義一個(gè)報(bào)名
package grpc.service.sayhello;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}
  • 編譯
# --go_out 參數(shù)是指定生成 *.pb.go 文件的路徑
# --go-grpc_out 參數(shù)是指定生成 *_grpc.pb.go 文件的路徑
# -I, 相當(dāng)于 -IPATH 和 --proto_path, 指定 proto 文件依賴的包所要搜索的路徑 (這里沒有依賴, 可以不寫)
protoc -I. --go_out=. --go-grpc_out=. *.proto
  • 編譯報(bào)錯(cuò)
protoc-gen-go: unable to determine Go import path for

Please specify either:
    ? a "go_package" option in the .proto source file, or
    ? a "M" argument on the command line.

See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.

--go_out: protoc-gen-go: Plugin failed with status code 1.

要我們定義 go_package 或者 M 命令行參數(shù)

  • 選擇修改 proto, 定義 go_package
syntax = "proto3";

// ./ 是文件生成的路徑
// sayhello_proto 是生成的 .go 文件的包名
// 兩者之間, 用 ; 號(hào)分隔
// 參考: https://blog.csdn.net/raoxiaoya/article/details/109533734
option go_package = "./;sayhello_proto";

package grpc.service.sayhello;

// The greeting service definition.
service Greeter {
    // Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
    string name = 1;
}

// The response message containing the greetings
message HelloReply {
    string message = 1;
}
  • 重新編譯 proto
protoc -I. --go_out=. --go-grpc_out=. *.proto

編譯成功

4. 實(shí)現(xiàn)服務(wù)端

package main

import (
    "context"
    "log"
    "net"

    proto "github.com/-/sayhellogrpc/proto" // 此處隱姓埋名
    "google.golang.org/grpc"
)

const (
    // 綁定的端口
    port = ":8080"
)

type server struct {
    proto.UnimplementedGreeterServer
}

// 實(shí)現(xiàn)定義的 SayHello API
// 參數(shù)和返回類型, 參考生成的 sayhello_grpc.pb.go 的
func (s *server) SayHello(ctx context.Context, in *proto.HelloRequest) (*proto.HelloReply, error) {
    log.Printf("Received: %v", in.GetName())
    msg := in.GetName() + " say hello for gRPC"
    reply := &proto.HelloReply{
        Message: msg,
    }
    return reply, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    srv := grpc.NewServer()
    // 注冊(cè)服務(wù)
    proto.RegisterGreeterServer(srv, &server{})

    log.Println("gRPC server is running...")
    // 起服務(wù)
    if err := srv.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

5. 實(shí)現(xiàn)客戶端

package main

import (
    "context"
    "log"
    "os"
    "time"

    proto "github.com/-/sayhellogrpc/proto" // 此處隱姓埋名
    "google.golang.org/grpc"
)

const (
    address = "localhost:8080"
    content = "xxxx"
)

func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()

    c := proto.NewGreeterClient(conn)

    // Contact the server and print out its response.
    name := content
    if len(os.Args) > 1 {
        // 通過命令行獲取發(fā)送的內(nèi)容
        name = os.Args[1]
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.SayHello(ctx, &proto.HelloRequest{Name: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

go.mod

如果報(bào) undefined: grpc.SupportPackageIsVersion7 這樣的錯(cuò)誤, 則要修改 google.golang.org/grpc 的版本, v1.32.0 及以上

module github.com/-/sayhellogrpc // 此處隱姓埋名

go 1.15

require (
    github.com/golang/protobuf v1.5.0
    google.golang.org/grpc v1.37.0
    google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect
    google.golang.org/protobuf v1.26.0
)

文件結(jié)構(gòu)

.
├── client
│   └── main.go
├── go.mod
├── go.sum
├── proto
│   ├── sayhello.pb.go
│   ├── sayhello.proto
│   └── sayhello_grpc.pb.go
└── server
    └── main.go

6. 驗(yàn)證

go run server/main.go

go run client/main.go

go run client/main.go abc

實(shí)現(xiàn)參考: https://github.com/grpc/grpc-go/tree/master/examples

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市花颗,隨后出現(xiàn)的幾起案子捕传,更是在濱河造成了極大的恐慌,老刑警劉巖扩劝,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庸论,死亡現(xiàn)場(chǎng)離奇詭異职辅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)聂示,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門域携,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鱼喉,你說我怎么就攤上這事秀鞭。” “怎么了扛禽?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵锋边,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我编曼,道長(zhǎng)豆巨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任掐场,我火速辦了婚禮往扔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘熊户。我一直安慰自己萍膛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布嚷堡。 她就那樣靜靜地躺著蝗罗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝌戒。 梳的紋絲不亂的頭發(fā)上绿饵,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音瓶颠,去河邊找鬼拟赊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛粹淋,可吹牛的內(nèi)容都是我干的吸祟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼桃移,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼屋匕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起借杰,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤过吻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纤虽,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乳绕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逼纸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洋措。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖杰刽,靈堂內(nèi)的尸體忽然破棺而出菠发,到底是詐尸還是另有隱情,我是刑警寧澤贺嫂,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布滓鸠,位于F島的核電站,受9級(jí)特大地震影響第喳,放射性物質(zhì)發(fā)生泄漏哥力。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一墩弯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寞射,春花似錦渔工、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至侵浸,卻和暖如春旺韭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掏觉。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工区端, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澳腹。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓织盼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親酱塔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沥邻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 寫在前面 首先聲明這篇文章只是介紹gRPC在Go語(yǔ)言中的使用入門級(jí)的文章,不包含多少深入的內(nèi)容羊娃,讀者對(duì)象是g...
    foundwei閱讀 2,632評(píng)論 0 5
  • 原文出處:gRPC gRPC分享 概述 gRPC 一開始由 google 開發(fā)唐全,是一款語(yǔ)言中立、平臺(tái)中立蕊玷、開源的遠(yuǎn)...
    小波同學(xué)閱讀 7,221評(píng)論 0 18
  • 原文連接: 一文了解RPC以及gRPC基于Golang和Java的簡(jiǎn)單實(shí)現(xiàn) 一:什么是RPC 簡(jiǎn)介:RPC:Re...
    賈順閱讀 8,905評(píng)論 2 12
  • 1.簡(jiǎn)介 在gRPC中邮利,客戶端應(yīng)用程序可以直接調(diào)用不同計(jì)算機(jī)上的服務(wù)器應(yīng)用程序上的方法弥雹,就像它是本地對(duì)象一樣,使您...
    第八共同體閱讀 1,880評(píng)論 0 6
  • gRPC(Remote Procedure Calls) 概述 GRPC是一個(gè)高性能近弟、通用的開源RPC框架缅糟,基于底...
    鬼鸮閱讀 17,926評(píng)論 0 1