grpc簡介
- gRPC由google開發,是一款語言中立、平台中立、開源的遠程過程調用系統
- gRPC客戶端和服務端可以在多種環境中運行和交互,例如用java寫一個服務端,可以用go語言寫客戶端調用
grpc和protobuf介紹
- 微服務架構中,由於每個服務對應的代碼庫是獨立運行的,無法直接調用,彼此間的通信就是個大問題
- gRPC可以實現微服務,將大的項目拆分為多個小且獨立的業務模塊,也就是服務,各服務間使用高效的protobuf協議進行RPC調用,gRPC默認使用protocol buffers,這是* * * google開源的一套成熟的結構數據序列化機制(當然也可以使用其他數據格式如JSON)
- 可以用proto files創建gRPC服務,用message類型來定義方法參數和返回類型
安裝grpc和protobuf
- 安裝protobuf
go get github.com/golang/protobuf/proto
- 安裝grpc
go get google.golang.org/grpc
- 安裝protoc-gen-go.exe
go get github.com/golang/protobuf/protoc-gen-go
上面安裝好后,會在GOPATH/bin下生成protoc-gen-go.exe - 安裝protoc.exe
https://github.com/protocolbuffers/protobuf/releases/tag/v3.19.1
下載后解壓,然后將解壓的protoc.exe同樣放在GOPATH/bin下
grpc官網介紹
gRPC 是一個高性能、開源、通用的RPC框架,由Google推出,基於HTTP2協議標准設計開發,默認采用Protocol Buffers數據序列化協議,支持多種開發語言。gRPC提供了一種簡單的方法來精確的定義服務,並且為客戶端和服務端自動生成可靠的功能庫。
在gRPC客戶端可以直接調用不同服務器上的遠程程序,使用姿勢看起來就像調用本地程序一樣,很容易去構建分布式應用和服務。和很多RPC系統一樣,服務端負責實現定義好的接口並處理客戶端的請求,客戶端根據接口描述直接調用需要的服務。客戶端和服務端可以分別使用gRPC支持的不同語言實現。
主要特性
- 強大的IDL
gRPC使用ProtoBuf來定義服務,ProtoBuf是由Google開發的一種數據序列化協議(類似於XML、JSON、hessian)。ProtoBuf能夠將數據進行序列化,並廣泛應用在數據存儲、通信協議等方面。 - 多語言支持
gRPC支持多種語言,並能夠基於語言自動生成客戶端和服務端功能庫。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它語言的版本正在積極開發中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等語言,grpc-java已經支持Android開發。 - HTTP2
gRPC基於HTTP2標准設計,所以相對於其他RPC框架,gRPC帶來了更多強大功能,如雙向流、頭部壓縮、多復用請求等。這些功能給移動設備帶來重大益處,如節省帶寬、降低TCP鏈接次數、節省CPU使用和延長電池壽命等。同時,gRPC還能夠提高了雲端服務和Web應用的性能。gRPC既能夠在客戶端應用,也能夠在服務器端應用,從而以透明的方式實現客戶端和服務器端的通信和簡化通信系統的構建。
小案例
按照慣例,這里也從一個Hello項目開始,本項目定義了一個Hello Service,客戶端發送包含字符串名字的請求,服務端返回Hello消息。
流程:
- 編寫.proto描述文件
- 編譯生成.pb.go文件
- 服務端實現約定的接口並提供服務
- 客戶端按照約定調用.pb.go文件中的方法請求服務
項目結構:
1. 編寫描述文件:hello.proto
syntax = "proto3"; // 指定proto版本
package hello; // 指定默認包名
// 指定golang包名
option go_package = "../hello";
// 定義Hello服務
service Hello {
// 定義SayHello方法
rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
// HelloRequest 請求結構
message HelloRequest {
string name = 1;
}
// HelloResponse 響應結構
message HelloResponse {
string message = 1;
}
hello.proto文件中定義了一個Hello Service,該服務包含一個SayHello方法,同時聲明了HelloRequest和HelloResponse消息結構用於請求和響應。客戶端使用HelloRequest參數調用SayHello方法請求服務端,服務端響應HelloResponse消息。一個最簡單的服務就定義好了。
2. 編譯生成.pb.go文件
$ cd proto/hello
# 編譯hello.proto
$ protoc -I . --go_out=plugins=grpc:. ./hello.proto
在當前目錄內生成的hello.pb.go文件,按照.proto文件中的說明,包含服務端接口HelloServer描述,客戶端接口及實現HelloClient,及HelloRequest、HelloResponse結構體。
注意:不要手動編輯該文件
3. 實現服務端接口 server/main.go
點擊查看代碼
package main
import (
"fmt"
pb "goGrpc/proto/hello" // 引入編譯生成的包
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"net"
)
const (
// Address gRPC服務地址
Address = "127.0.0.1:50052"
)
// 定義helloService並實現約定的接口
type helloService struct{}
// HelloService Hello服務
var HelloService = helloService{}
// SayHello 實現Hello服務接口
func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
resp := new(pb.HelloResponse)
resp.Message = fmt.Sprintf("Hello %s.", in.Name)
return resp, nil
}
func main() {
listen, err := net.Listen("tcp", Address)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
// 實例化grpc Server
s := grpc.NewServer()
// 注冊HelloService
pb.RegisterHelloServer(s, HelloService)
fmt.Println("Listen on " + Address)
_ = s.Serve(listen)
}
運行:
$ go run main.go
Listen on 127.0.0.1:50052 //服務端已開啟並監聽50052端口
4. 實現客戶端調用 client/main.go
點擊查看代碼
package main
import (
"fmt"
pb "goGrpc/proto/hello" // 引入proto包
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
)
const (
// Address gRPC服務地址
Address = "127.0.0.1:50052"
)
func main() {
// 連接
conn, err := grpc.Dial(Address, grpc.WithInsecure())
if err != nil {
grpclog.Fatalln(err)
}
defer conn.Close()
// 初始化客戶端
c := pb.NewHelloClient(conn)
// 調用方法
req := &pb.HelloRequest{Name: "馬亞南"}
res, err := c.SayHello(context.Background(), req)
if err != nil {
grpclog.Fatalln(err)
}
//grpclog.Println(res.Message)
fmt.Println(res.Message)
}
建議到這里仔細看一看hello.pb.go文件中的內容,對比hello.proto文件,理解protobuf中的定義轉換為golang后的結構。