RPC是什么?
所謂RPC(remote procedure call 遠(yuǎn)程過程調(diào)用)框架實(shí)際是提供了一套機(jī)制,使得應(yīng)用程序之間可以進(jìn)行通信,而且也遵從server/client模型。使用的時(shí)候客戶端調(diào)用server端提供的接口就像是調(diào)用本地的函數(shù)一樣。
gRPC是什么?
與許多RPC系統(tǒng)一樣,gRPC基于定義服務(wù)的思想,指定可以使用其參數(shù)和返回類型遠(yuǎn)程調(diào)用的方法。默認(rèn)情況下,gRPC使用協(xié)議緩沖區(qū)作為接口定義語言(IDL)來描述服務(wù)接口和有效負(fù)載消息的結(jié)構(gòu)。
gRPC有什么好處以及在什么場景下需要用gRPC
既然是server/client模型,那么我們直接用restful api不是也可以滿足嗎,為什么還需要RPC呢?下面我們就來看看RPC到底有哪些優(yōu)勢
gRPC vs. Restful API
gRPC和restful API都提供了一套通信機(jī)制,用于server/client模型通信,而且它們都使用http作為底層的傳輸協(xié)議(嚴(yán)格地說, gRPC使用的http2.0,而restful api則不一定)。不過gRPC還是有些特有的優(yōu)勢,如下:
- gRPC可以通過protobuf來定義接口,從而可以有更加嚴(yán)格的接口約束條件。關(guān)于protobuf可以參見筆者之前的小文Google Protobuf簡明教程
- 另外,通過protobuf可以將數(shù)據(jù)序列化為二進(jìn)制編碼,這會(huì)大幅減少需要傳輸?shù)臄?shù)據(jù)量,從而大幅提高性能。
- gRPC可以方便地支持流式通信(理論上通過http2.0就可以使用streaming模式, 但是通常web服務(wù)的restful api似乎很少這么用,通常的流式數(shù)據(jù)應(yīng)用如視頻流,一般都會(huì)使用專門的協(xié)議如HLS,RTMP等,這些就不是我們通常web服務(wù)了,而是有專門的服務(wù)器應(yīng)用。)
使用場景
- 需要對接口進(jìn)行嚴(yán)格約束的情況,比如我們提供了一個(gè)公共的服務(wù),很多人,甚至公司外部的人也可以訪問這個(gè)服務(wù),這時(shí)對于接口我們希望有更加嚴(yán)格的約束,我們不希望客戶端給我們傳遞任意的數(shù)據(jù),尤其是考慮到安全性的因素,我們通常需要對接口進(jìn)行更加嚴(yán)格的約束。這時(shí)gRPC就可以通過protobuf來提供嚴(yán)格的接口約束。
- 對于性能有更高的要求時(shí)。有時(shí)我們的服務(wù)需要傳遞大量的數(shù)據(jù),而又希望不影響我們的性能,這個(gè)時(shí)候也可以考慮gRPC服務(wù),因?yàn)橥ㄟ^protobuf我們可以將數(shù)據(jù)壓縮編碼轉(zhuǎn)化為二進(jìn)制格式,通常傳遞的數(shù)據(jù)量要小得多,而且通過http2我們可以實(shí)現(xiàn)異步的請求,從而大大提高了通信效率。
但是,通常我們不會(huì)去單獨(dú)使用gRPC,而是將gRPC作為一個(gè)部件進(jìn)行使用,這是因?yàn)樵谏a(chǎn)環(huán)境,我們面對大并發(fā)的情況下,需要使用分布式系統(tǒng)來去處理,而gRPC并沒有提供分布式系統(tǒng)相關(guān)的一些必要組件。而且,真正的線上服務(wù)還需要提供包括負(fù)載均衡,限流熔斷,監(jiān)控報(bào)警,服務(wù)注冊和發(fā)現(xiàn)等等必要的組件。不過,這就不屬于本篇文章討論的主題了,我們還是先繼續(xù)看下如何使用gRPC。
gRPC的使用通常包括如下幾個(gè)步驟
- 通過protobuf來定義接口和數(shù)據(jù)類型
- 編寫gRPC server端代碼
- 編寫gRPC client端代碼
protobuf的安裝
mac:brew install protobuf
windows:protoc 下載:官方地址,然后將 bin 路徑添加到 path 環(huán)境變量下去
linux:
安裝需要的依賴包:
[root@localhost ~]# yum -y install autoconf automake libtool curl make g++ unzip
[root@localhost ~]# unzip protobuf-master.zip
[root@localhost ~]# cd protobuf-master
生成configure文件的腳本文件,如果不執(zhí)行這步,以下操作將通不過
[root@localhost protobuf-master]# ./autogen.sh
[root@localhost protobuf-master]# ./configure
可以修改安裝目錄通過 ./configure --prefix=命令,統(tǒng)一安裝在/usr/local/protobuf下
[root@localhost protobuf-master]# ./configure --prefix=/usr/local/protobuf
[root@localhost protobuf-master]# make
[root@localhost protobuf-master]# make check
[root@localhost protobuf-master]# make install
[root@localhost protobuf-master]# ldconfig # refresh shared library cache.
安裝成功
[root@localhost protobuf-master]# protoc -I=./ --cpp_out=./ test.proto
安裝grpc包
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u google.golang.org/grpc
protoc --go_out=plugins=grpc:. *.proto
定義接口和數(shù)據(jù)類型
syntax = "proto3";
package rpc_package;
// define a service
service HelloWorldService {
// define the interface and data type
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// define the data type of request
message HelloRequest {
string name = 1;
}
// define the data type of response
message HelloReply {
string message = 1;
}
使用protobuf生成工具生成對應(yīng)語言的庫函數(shù)
protoc --go_out=plugins=grpc:. helloworld.proto
server.go
// server.go
import (
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "helloworld/helloworld"
)
const (
port = ":50051"
)
type server struct {}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatal("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, server{})
s.Serve(lis)
}
client.go
package main
//client.go
import (
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "helloworld/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatal("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
name := defaultName
if len(os.Args) >1 {
name = os.Args[1]
}
r, err := c.SayHello(context.Background(), pb.HelloRequest{Name: name})
if err != nil {
log.Fatal("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
以上就是golang 微服務(wù)之gRPC與Protobuf的使用的詳細(xì)內(nèi)容,更多關(guān)于golang gRPC與Protobuf的資料請關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- 在go語言中安裝與使用protobuf的方法詳解
- golang grpc 負(fù)載均衡的方法
- 詳解golang consul-grpc 服務(wù)注冊與發(fā)現(xiàn)
- go grpc安裝使用教程