gRPC-微服务间通信实践
微服務(wù)間通信常見的兩種方式
由于微服務(wù)架構(gòu)慢慢被更多人使用后,迎面而來的問題是如何做好微服務(wù)間通信的方案。我們先分析下目前最常用的兩種服務(wù)間通信方案。
gRPC(rpc遠程調(diào)用)
場景:A服務(wù)主動發(fā)起請求到B服務(wù),同步方式
范圍:只在微服務(wù)間通信應(yīng)用
EventBus(基于消息隊列的集成事件)
技術(shù):NotNetCore.Cap + Rabbitmq + Database
場景:A服務(wù)要在B服務(wù)做某件事情后響應(yīng),異步方式
實現(xiàn):B服務(wù)在完成某件事情后發(fā)布消息,A服務(wù)訂閱此消息
范圍:只在微服務(wù)間通信應(yīng)用
通過對比,兩種方式完全不一樣。rpc是類似于http請求的及時響應(yīng)機制,但是比http更輕量、快捷,它更像以前的微軟的WCF,可以自動生成客戶端代碼,充分體現(xiàn)了面向?qū)嶓w對象的遠程調(diào)用的思想;Eventbus是異步的消息機制,基于cap的思想,不關(guān)心下游訂閱方服務(wù)是否消費成功,保障了主服務(wù)業(yè)務(wù)的流暢性,同時也是一款分布式事務(wù)的實現(xiàn)方案,可以保障分布式架構(gòu)中的數(shù)據(jù)的最終一致性。
我們今天主要介紹gRPC在微服務(wù)中的實踐案例。
gRPC-Server(服務(wù)端)
框架介紹
.Net Core sdk 3.1
Grpc.AspNetCore 2.30.0
Grpc.Core 2.30.0
搭建步驟
以.net core webapi 項目為例,詳細說明如何集成gRPC。
創(chuàng)建項目
創(chuàng)建web api項目,此步驟說明省略
引入nuget包
引入gRPC 服務(wù)端需要的 nuget包,Grpc.AspNetCore 2.30.0和Grpc.Core 2.30.0
外部訪問
考慮到項目發(fā)布后,有webapi本身的http的接口和gRPC的接口都要給外部訪問,就需要暴露http1和http2兩個端口。
方式1:本地調(diào)試時,可以直接暴露http和https,如果你的服務(wù)器支持https,也可以在生產(chǎn)環(huán)境使用https來訪問gRPC服務(wù)。
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().UseNLog().UseUrls("http://*:5000;https://*:5001");方式2:如果在容器化部署場景下,一般會在dockerfile中指定ASPNETCORE_PORT環(huán)境變量,然后程序監(jiān)聽http1和http2兩個端口。
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{var aspnetcorePort = Environment.GetEnvironmentVariable("ASPNETCORE_PORT") ?? 5000;int.TryParse(aspnetcorePort, out int port);webBuilder.ConfigureKestrel(options =>{options.ListenAnyIP(port, options => options.Protocols = HttpProtocols.Http1);options.ListenAnyIP(port + 1, options => options.Protocols = HttpProtocols.Http2);}).UseStartup<Startup>();webBuilder.UseNLog();});異常處理
由于gRPC服務(wù)端只能throw 基于 Grpc.Core.RpcException 的異常類型,所以我們可以自定義中間件來統(tǒng)一處理下異常
using Grpc.Core; using Grpc.Core.Interceptors; using System; using System.Threading.Tasks;public class ExceptionInterceptor : Interceptor{public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request,ServerCallContext context,UnaryServerMethod<TRequest, TResponse> continuation){try{return await continuation(request, context);}catch (RpcException ex){throw ex;}catch (Exception ex){throw new RpcException(new Status(StatusCode.Internal, ex.Message + "\r\n" + ex.StackTrace));}}}代碼中被繼承的 Interceptor 是 Grpc.Core.Interceptors.Interceptor。主要處理的目的是把在gRPC接口中拋出的非 RpcException 的異常,轉(zhuǎn)換為 RpcException。此中間件也是根據(jù)具體的業(yè)務(wù)需求來做的,主要是告訴大家可以重寫 Grpc.Core.Interceptors.Interceptor 的攔截器來統(tǒng)一處理一些事情。
定義協(xié)議緩沖區(qū)(protocol3)
新建項搜索rpc可以出現(xiàn)協(xié)議緩沖區(qū)文件
定義示例接口,創(chuàng)建訂單方法,以及創(chuàng)建訂單入?yún)⒑统鰠ⅰjP(guān)于proto3協(xié)議具體說明,請參考往期文章。
syntax = "proto3";option csharp_namespace = "GrpcTest.Protos";service Order {rpc CreateOrder (CreateOrderRequest) returns (CreateOrderReply); }message CreateOrderRequest {string ItemCode = 1;string ItemName = 2;string Spec = 3;double Price = 4;double Quantity = 5;string Unit = 6;double Cost = 7; }message CreateOrderReply {bool success = 1; }在項目的csproj文件中,需要有proto包含進去,GrpcServices="Server"表示當(dāng)前是服務(wù)端。改好后重新生成下項目。
<ItemGroup><Protobuf Include="Protos/GrpcTest.Protos" GrpcServices="Server" /></ItemGroup>創(chuàng)建OrderService
手動創(chuàng)建OrderService,繼承自O(shè)rder.OrderBase(proto自動生成的代碼)
public class OrderService : Order.OrderBase{public async override Task<CreateOrderReply> CreateOrder(CreateOrderRequest request, ServerCallContext context){//todo something//throw RpcException異常throw new RpcException(new Status(StatusCode.NotFound, "資源不存在"));//返回return new CreateOrderReply{Success = true};}}重寫CreateOrder方法,此處就可以寫你的實際的業(yè)務(wù)代碼,相當(dāng)于Controller接口入口。如果業(yè)務(wù)中需要主動拋出異常,可以使用RpcException,有定義好的一套狀態(tài)碼和異常封裝。
修改Startup
在ConfigureServices方法中加入AddGrpc,以及上面提到的異常處理中間件,代碼如下
services.AddGrpc(option => option.Interceptors.Add<ExceptionInterceptor>());在Configure方法中將OrderService啟用,代碼如下
app.UseEndpoints(endpoints =>{endpoints.MapGrpcService<OrderService>();endpoints.MapGet("/", async context =>{await context.Response.WriteAsync("this is a gRPC server");});});至此 gRPC服務(wù)端搭建完成。
gRPC-Client(客戶端)
框架介紹
.Net Core sdk 3.1
Google.Protobuf 3.12.4
Grpc.Tools 2.30.0
Grpc.Net.ClientFactory 2.30.0
搭建步驟
以.net core webapi 項目為例,詳細說明如何集成gRPC客戶端
創(chuàng)建項目
創(chuàng)建web api項目,此步驟說明省略
引入nuget包
引入gRPC 客戶端需要的 nuget包,Google.Protobuf 3.12.4、Grpc.Tools 2.30.0和Grpc.Net.ClientFactory 2.30.0
引入proto文件
將服務(wù)端的 order.proto 拷貝到客戶端的web api項目中,并在csproj文件中添加ItemGroup節(jié)點。GrpcServices="Client"表示當(dāng)前是客戶端。改好后重新生成下項目。
<ItemGroup><Protobuf Include="Protos/OutpAggregation.proto" GrpcServices="Client" /></ItemGroup>修改Startup
在ConfigureServices方法中加入AddGrpcClient,代碼如下
services.AddHttpContextAccessor();AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);var baseUrl = "http://localhost:5001/";services.AddGrpcClient<Order.OrderClient>(options =>{options.Address = new Uri(baseUrl);});注意:要使用.NET Core客戶端調(diào)用不安全的gRPC服務(wù),需要進行其他配置。gRPC客戶端必須將System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport開關(guān)設(shè)置為true,并在服務(wù)器地址中使用http。可以在以下鏈接查看具體說明。
[Troubleshoot gRPC on .NET Core]
另外說明下services.AddGrpcClient方法,來自于nuget包Grpc.Net.ClientFactory 2.30.0,將gRPC客戶端的注入封裝,具體代碼實現(xiàn)可以查看以下鏈接。
Grpc.Net.ClientFactory
客戶端調(diào)用
以在Controller中調(diào)用為例,示例代碼如下
[ApiController][Route("[controller]")]public class WeatherForecastController : ControllerBase{private readonly Order.OrderClient _orderClient;public WeatherForecastController(Order.OrderClient orderClient){_orderClient = orderClient;}[HttpGet]public async Task<IEnumerable<WeatherForecast>> Get(){var result = await _orderClient.CreateOrderAsync(new CreateOrderRequest{ItemCode = "123",ItemName = "名稱1"});}}通過構(gòu)造函數(shù)注入gRPC客戶端,然后就可以使用里面的同步或者異步方法啦!
總結(jié)
以上是生活随笔為你收集整理的gRPC-微服务间通信实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中芯国际第二代FinFET工艺有望与20
- 下一篇: 移动 Azure 资源后如何快速修复 D