最近在學習.net core的微服務體系架構。微服務之間的通信常常通過 gRPC
進行同步通信,但是需要注意的是,大多數微服務之間的通信是通過事件總線進行異步通信。在微軟介紹.net微服務體系架構的項目eShop中,微服務之間進行同步通信的場景很多,大多數都是HTTP/REST,目前隻有自定義聚合器與微服務之間通信是使用的gRPC。整套微服務架構體系,其實除了用戶端與網關(BFF)之間,使用HTTP/REST,均可使用gRPC(隻要網關支援HTTP/REST與gRPC的轉換)
- BFF轉發外部請求
- 微服務之間
- 自定義聚合器與微服務
1.gRPC是什麼?
A high-performance, open-source universal RPC framework。
gRPC
是一個高性能的通信協定,它基于
HTTP/2
和
protocol buffers
。它是微服務之間進行同步通信的主要選擇。與之相對的,就是其他協定,如AMQP的異步通信隊列或者釋出/訂閱模式。
RPC
(remote procedure call 遠端過程調用)架構實際是提供了一套機制,使得應用程式之間可以進行通信,而且也遵從
server/client模型
。使用的時候用戶端調用server端提供的接口就像是調用本地的函數一樣.
與HTTP/JSON相比,gRPC的優勢:
- 高性能:協定緩沖區是一種二進制的高性能序列化機制。根據語言的不同,實作協定緩沖區的速度比JSON序列化快8倍,而消息的大小可能比JSON序列化小60%-80%。
- 支援資料流,說白了,還是快
- 約定顯示,與語言無關:使用proto檔案定義服務端與用戶端之間的約定
2.在.net core中使用gRPC
在.NET Core 3.0衆多更新中,其中有一個重要的更新就是對gRPC的原生支援。從.NET Core3.0開始,無論是開發工具還是架構中,都與gRPC進行了深度的內建,這讓使用gRPC的體驗如絲般順滑。
真的有這麼絲滑嗎?
2.1 工具
工具內建-絲滑享受,主要展現在
msbuild
,開發者可以直接使用宇宙第一IDE:
Vistual Studio
或者
.NET Core SDK
指令
dotnet build
,通過
.proto
檔案去生成需要的gRPC服務端和用戶端代碼。這裡有兩個必要條件:
安裝工具包
Google.Protobuf,Grpc.Tools
Install-Package Google.Protobuf -Version 3.12.2
Install-Package Grpc.Tools -Version 2.29.0
.proto的引用
proto檔案必須在
.csproj
中引用。在中使用
标簽。
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
其中
GrpcServices
屬性:指明生成的代碼是用戶端還是服務端,或者Both(這是預設值)。當編譯代碼時(無論是通過運作
Visual Studio
的
Build
還是
dotnet build
),所有代碼都将生成并放在
obj
檔案夾中。這是微軟故意這樣做的,因為這些代碼不應該出現在源代碼控制存儲庫中,他們都是生成的,隻要.proto檔案在,他們都能随時生成。
2.2 實際使用的技巧-親測有用
參考曉晨部落格
主要目标
- 讓用戶端和服務端共用一個Protos檔案夾,避免重複
- 使用
變量在MSBuild
中添加csproj
标簽,避免繁瑣修改Protobuf
csproj
服務端
<ItemGroup>
<Protobuf Include="..\Protos\*.proto" GrpcServices="Server" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
用戶端
<ItemGroup>
<Protobuf Include="..\Protos\*.proto" GrpcServices="Client" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
-
:加通配符的路徑,去指定proto檔案的路徑Include

3.建立服務端
3.1 安裝包
建立gRPC服務端,需要包Grpc.AspNetCore
Install-Package Grpc.AspNetCore -Version 2.29.0
很幸運,VS2019已經為我們準備好服務端的模闆。我們可以建立一個gRPC服務端項目。這個模闆已經引入了
Grpc.AspNetCore
包。你可以在模闆中搜到的。
3.2 引入proto檔案
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
當然這,模闆已經為我們生成了。并且生成了
GreeterService.cs
3.3 加入gRPC管道
- gRPC添加到終結點路由中
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
ASP.NET Core 中間件和功能共享路由管道,是以可以将應用配置為提供其他請求處理程式。 其他請求處理程式與已配置的 gRPC 服務并行工作。
- 注冊服務
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
當然這,模闆已經為我們生成了,不要模闆自己刀耕火種也是可以的。
4.建立用戶端
4.1 安裝包
建立gRPC用戶端,需要包Google.Protobuf,Grpc.Tools,Grpc.Net.Client
Install-Package Google.Protobuf -Version 3.12.2
Install-Package Grpc.Tools -Version 2.29.0
Install-Package Grpc.Net.Client -Version 2.29.0
4.2 引入與服務端相同的proto檔案
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
4.3 編碼
static async Task Main(string[] args)
{
Console.WriteLine("Hello gRPC!");
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var greeterClient = new Greeter.GreeterClient(channel);
//https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0&WT.mc_id=DT-MVP-5003133
var reply = await greeterClient.SayHelloAsync(new HelloRequest
{
Name = "Garfield"
});
Console.WriteLine("Greeter 服務傳回資料: " + reply.Message);
Console.ReadKey();
//var counterClient = new Count.CounterClient(channel);
//// This switch must be set before creating the GrpcChannel/HttpClient.
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//// The port number(5000) must match the port of the gRPC server.
//var channel = GrpcChannel.ForAddress("http://localhost:5000");
//var client = new Greet.GreeterClient(channel);
}
5.微服務中使用
如引言所述,gRPC主要用于微服務之間同步通信。
主要運用場景,已經根據業務劃分的多個微服務無法滿足實際出現的業務場景,需要聯合多個微服務進行業務處理。沒錯,這就是微服務架構體系中的自定義聚合器,實際上聚合器也是一種微服務,負責聚合多個微服務提供較粒度更小的微服務更為強大的自定義微服務。至于使用方式,依然是引入Grpc.Net.Client包,此包本來就是HttpClient基礎上實作的,大可以把此當作一個gPRC的HttpClient使用。
6.配置無TLS的gRPC
6.1 服務端配置
gRPC隻支援HTTP/2。通常,當用戶端連接配接到服務端時,連接配接使用HTTP1.1完成,隻有當伺服器和用戶端都支援HTTP/2時才提升為HTTP/2,這就是協定提升,實際上,同類似的, Websocket就是這樣通過http操作,走協定提升。這個協定提升使用協定協商執行,通常需要使用ALPN協定實作,這個協定要求必須TLS。
這意味着,在預設情況下,您需要啟用一個TLS端點,以便能夠使用gRPC。
但是,這裡有一個但是,在内部的微服務中,可能是沒有啟用TLS的,也沒必要,因為大家都是自己人,取消TLS,提高效率。在這種情況下,你有兩個選擇:
- 打開一個Kestrel,監聽HTTP/2
- 打開兩個Kestrel,一個監聽HTTP1.1,另一個監聽HTTP/2
如果您的伺服器除了支援gRPC用戶端還必須支援HTTP1.1用戶端,則需要第二個選項。下面的代碼就是展示了第二種方法(
Program.cs
):
WebHost.CreateDefaultBuilder(args)
.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5000, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
});
//Setup a HTTP/2 endpoint without TLS.
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
})
- 5000:提供http web api
- 5001:提供gRPC
6.2 在.NET Core用戶端調用
但是,這還不夠,我們需要告訴gRPC用戶端,用戶端可以直接連接配接到HTTP/2端點,而不需要TLS,口頭或者文檔說明。
在預設情況下.NET Core不允許
gRPC
用戶端連接配接到非TLS(non-TLS)端點-不安全的gRPC的服務,十有八九都會報異常
Unhandled exception. System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
那麼怎麼辦,就需要如下代碼:
// This switch must be set before creating the GrpcChannel/HttpClient.
AppContext.SetSwitch(
"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
// The port number(5000) must match the port of the gRPC server.
var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new Greet.GreeterClient(channel);
上述設定隻能在用戶端開始時設定一次。
7.配置TLS的gRPC
毫無疑問,微服務場景之外的gRPC服務還是需要TLS的。
7.1 方法一:appsetting.json
{
"Kestrel": {
"Endpoints": {
"HttpsInlineCertFile": {
"Url": "https://localhost:5001",
"Protocols": "Http2",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "<certificate password>"
}
}
}
}
}
7.2 方法二:Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
listenOptions.UseHttps("<path to .pfx file>",
"<certificate password>");
});
});
webBuilder.UseStartup<Startup>();
});
8.寫在末尾
Azure App Service 和IIS目前都還不支援gRPC. 另外Http.Sys也不支援gRPC所依賴的HTTP響應。詳情請看github issues
參考連結
https://grpc.io/
https://www.cnblogs.com/shanyou/p/3452938.html
https://blog.csdn.net/yangguosb/article/details/80592777
https://docs.microsoft.com/zh-cn/aspnet/core/grpc/aspnetcore?view=aspnetcore-3.1&tabs=visual-studio
https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.1
https://www.cnblogs.com/stulzq/p/11581967.html
作者:Garfield
同步更新至個人部落格:http://www.randyfield.cn/
本文版權歸作者所有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected]
微信公衆号
掃描下方二維碼關注個人微信公衆号,實時擷取更多幹貨
同步更新至:http://www.randyfield.cn/
出處:http://www.cnblogs.com/RandyField/
本文版權歸作者和部落格園共有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected].