gRPC概述
RPC
說到gRPC就不得不提RPC,所謂RPC(remote procedure call 遠程過程調用)框架實際是提供了一套機制,使得應用程序之間可以進行通信,簡單點來說就是我A機器上寫的函數可以在B機器上通過RPC協議直接調用。
它與http不同的是:
- RPC是基於TCP實現的,RESTFUL是基於HTTP來實現的。
- 從傳輸速度上來看,因為HTTP封裝的數據量更多所以數據傳輸量更大,所以RPC的傳輸速度是比RESTFUL更快的。
為什么內部(約定情況下的服務與服務)使用rpc,而外部(to customer)使用http
- 因為HTTP協議是各個框架都普遍支持的。在toC情況下,因為不知道情況來源的框架、數據形勢是什么樣的,所以在網關可以使用Restful利用http來接受。而在微服務內部的各模塊之間因為各協議方案是公司內部自己定的,所以知道各種數據方式,可以使用TCP傳輸以使各模塊之間的數據傳輸更快。所以可以網關和外界的數據傳輸使用RESTFUL,微服務內部的各模塊之間使用RPC。
gRPC又是什么呢
gRPC
是一個高性能、開源的通用RPC
框架,最初是由谷歌創建的,十多年來谷歌一直使用一個稱為Stubby
的通用RPC
基礎設施來連接在其數據中心內和跨數據中心運行的大量微服務。2015年3月,Google
決定構建下一個版本的Stubby
並使其開源。結果就是 gRPC
,它現在被谷歌以外的許多組織用於支持從微服務到“最后一英里”計算(移動、網絡和物聯網)的用例。
gRPC官方文檔:https://www.grpc.io/docs/what-is-grpc/
在 gRPC 中,客戶端應用程序可以直接調用不同機器上的服務器應用程序上的方法,就像它是本地對象一樣,使您可以更輕松地創建分布式應用程序和服務。與許多 RPC 系統一樣,gRPC 基於定義服務的思想,指定可以通過參數和返回類型遠程調用的方法。在服務器端,服務器實現了這個接口並運行一個 gRPC 服務器來處理客戶端調用。在客戶端,客戶端有一個存根(在某些語言中簡稱為客戶端),它提供與服務器相同的方法。
安裝
Golang IDE(Goland)
Goland詳細步驟安裝:https://blog.csdn.net/u014374975/article/details/120387180
Golang語法詳解請:https://blog.csdn.net/u014374975/article/details/120463448
Protocol Buffer
可以通過Go、C++、C#、Java、Python等語言輕松的創建gRPC服務,同時也意味着它可以跨語言進行遠程過程調用,那么就需要一門中間語言(IDL)來約束和定義遠程過程調用之間通訊的接口約束。Google官方推薦並且使用人數最多的就是Protocol Buffer
,它具有稍微簡化的語法,一些有用的新功能,並支持更多語言。Proto3 目前可用於 Java、C++、Dart、Python、Objective-C、C#等
Protocol Buffer官方文檔:https://developers.google.com/protocol-buffers
下載Protocal Buffer
在GitHub的protocolbuffers項目下,下載ProtocalBuffer編譯器
配置Protocal Buffer編譯器環境變量
將下載好的Protocal Buffer壓縮包解壓,並將運行目錄配置到環境變量
環境變量添加完畢后,打開cmd
窗口執行protoc --version
,出現版本號,表示配置成功
protoc-gen-go
protoc-gen-go是protobuf編譯插件系列中的Go版本,protoc-gen-go可以將Protocol Buffer寫的接口定義轉換封裝為Golang代碼
在下載protoc-gen-go之前,我們先設置下Golang代理地址
# 七牛雲
go env -w GOPROXY=https://goproxy.cn,direct
下載protoc-gen-go
go get -u github.com/golang/protobuf/protoc-gen-go
如果GOPATH的bin目錄下有這個文件即表示下載成功
定義Protocal Buffer
打開IDE,在GOPATH的src目錄下創建一個pbfiles
文件夾,並在文件夾中添加一個product.proto
文件,用於描述接口定義
syntax = "proto3";
package pbfiles;
option go_package = "../services";
message Product{
int32 id = 1;
string name = 2;
int32 count = 3;
string description = 4;
}
service pdService{
rpc GetProduct(Product) returns(Product);
}
添加完成后,通過protoc
編譯該文件為Golang代碼
protoc --go_out=plugins=grpc:./ *.proto
此時我們發現,protoc會在src目錄下自動創建一個services
目錄,並將上面寫的proto
文件自動編譯為product.pb.go
由於編譯出的Golang代碼使用了google.golang.org
等包,所以我們添加一個mod
文件,拉取缺少的模塊。
進入src目錄執行go mod init gRPCdemo
命令
創建完畢后輸入命令go mod tidy
,此時上面生成的product.pb.go
代碼就不會缺少引用和標紅了
添加gRPC服務
Golang服務端實現
在src目錄下創建grpc-server.go
文件,並輸入代碼:
package main
import (
"context"
"fmt"
"gRPCdemo/services"
"google.golang.org/grpc"
"net"
)
type productRequest struct {
}
func (this *productRequest) GetProduct(context context.Context, request *services.Product) (*services.Product, error) {
var product services.Product
switch request.Id {
case 1:
product.Id = 1
product.Name = "蘋果"
product.Description = "小蘋果"
case 2:
product.Id = 1
product.Name = "西瓜"
product.Description = "大西瓜"
default:
product.Id = 3
product.Name = "香蕉"
product.Description = "香蕉"
}
return &product, nil
}
func main() {
grpcService := grpc.NewServer()
services.RegisterPdServiceServer(grpcService, new(productRequest))
listen, err := net.Listen("tcp", ":5000")
if err != nil {
fmt.Println("listen err:", err)
return
}
grpcService.Serve(listen)
}
在代碼目錄下打開終端輸入go run grpc-server.go
運行程序,開始監聽
Golang客戶端實現
在src目錄下創建grpc-client.go
文件,並輸入代碼:
package main
import (
"context"
"fmt"
"gRPCdemo/services"
"google.golang.org/grpc"
)
func main() {
grpcCnn, err := grpc.Dial(":5000", grpc.WithInsecure())
if err != nil {
fmt.Println("grpc.dial err:", err)
return
}
grpcClient := services.NewPdServiceClient(grpcCnn)
var request services.Product
request.Id = 1
res, err := grpcClient.GetProduct(context.TODO(), &request)
if err != nil {
fmt.Println("GetProduct err:", err)
return
}
fmt.Println(res)
}
在代碼目錄下打開終端輸入go run grpc-client.go
運行程序
此時可以看到,已成功訪問gRPC服務
.NetCore訪問Golang搭建的gRPC服務
- 打開vs創建控制台項目
grpcClient
- 右鍵項目
管理Nuget程序包
,添加如下包
- Grpc.Net.Client,其中包含 .NET Core 客戶端。
- Google.Protobuf 包含適用於 C# 的 Protobuf 消息
- Grpc.Tools 包含適用於 Protobuf 文件的 C# 工具支持。 運行時不需要工具包,因此依賴項標記為 PrivateAssets="All"。
- 在 gRPC 客戶端項目中創建
Protos
文件夾 - 將剛剛在Golang項目中創建的proto(pbfiles/product.proto)文復制到當前.NetCore客戶端項目的Protos中。
- 將
product.proto
文件中的命名空間更新為.NetCore項目的命名空間:
syntax = "proto3";
package pbfiles;
option csharp_namespace = "grpcClient";
message Product{
int32 id = 1;
string name = 2;
int32 count = 3;
string description = 4;
}
service pdService{
rpc GetProduct(Product) returns(Product);
}
- 編輯
grpcClient.csproj
項目文件 - 添加具有引用
greet.proto
文件的<Protobuf>
元素的項組:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.18.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.39.0" />
<PackageReference Include="Grpc.Tools" Version="2.41.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!--添加Protobuf元素組-->
<Protobuf Include="Protos\product.proto" GrpcServices="Client" />
</ItemGroup>
</Project>
- 構建客戶端項目,以在
grpcClient
命名空間中創建類型。GrpcGreeter
類型是由生成進程自動生成的。 - 使用以下代碼更新
grpcClient
客戶端的 Program.cs 文件:
using Grpc.Net.Client;
using System;
namespace grpcClient
{
class Program
{
static void Main(string[] args)
{
// 只有 .NET Core 3.x 需要 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport 開關。 .NET 5 中不需要任何額外配置,也沒有這項要求。
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
using var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new pdService.pdServiceClient(channel);
var reply = client.GetProduct(new Product { Id = 1 });
Console.WriteLine(reply);
Console.ReadKey();
}
}
}
啟動程序后,.NetCore完美訪問Golang搭建的gRPC服務
參考
gRPC官方文檔:https://www.grpc.io/docs/what-is-grpc/
Protocol Buffer官方文檔:https://developers.google.com/protocol-buffers