博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
gRPC-微服务间通信实践
阅读量:4033 次
发布时间:2019-05-24

本文共 6223 字,大约阅读时间需要 20 分钟。

微服务间通信常见的两种方式

由于微服务架构慢慢被更多人使用后,迎面而来的问题是如何做好微服务间通信的方案。我们先分析下目前最常用的两种服务间通信方案。

  • gRPC(rpc远程调用)

场景:A服务主动发起请求到B服务,同步方式

范围:只在微服务间通信应用

  • EventBus(基于消息队列的集成事件)

技术:NotNetCore.Cap + Rabbitmq + Database

场景:A服务要在B服务做某件事情后响应,异步方式
实现:B服务在完成某件事情后发布消息,A服务订阅此消息
范围:只在微服务间通信应用

通过对比,两种方式完全不一样。rpc是类似于http请求的及时响应机制,但是比http更轻量、快捷,它更像以前的微软的WCF,可以自动生成客户端代码,充分体现了面向实体对象的远程调用的思想;Eventbus是异步的消息机制,基于cap的思想,不关心下游订阅方服务是否消费成功,保障了主服务业务的流畅性,同时也是一款分布式事务的实现方案,可以保障分布式架构中的数据的最终一致性。

我们今天主要介绍gRPC在微服务中的实践案例。

gRPC-Server(服务端)

框架介绍

  • .Net Core sdk 3.1

  • Grpc.AspNetCore 2.30.0

  • Grpc.Core 2.30.0

搭建步骤

以.net core webapi 项目为例,详细说明如何集成gRPC。

创建项目

创建web api项目,此步骤说明省略

引入nuget包

引入gRPC 服务端需要的 nuget包,Grpc.AspNetCore 2.30.0和Grpc.Core 2.30.0

外部访问

考虑到项目发布后,有webapi本身的http的接口和gRPC的接口都要给外部访问,就需要暴露http1和http2两个端口。

方式1:本地调试时,可以直接暴露http和https,如果你的服务器支持https,也可以在生产环境使用https来访问gRPC服务。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>            WebHost.CreateDefaultBuilder(args)                .UseStartup
() .UseNLog() .UseUrls("http://*:5000;https://*:5001");

方式2:如果在容器化部署场景下,一般会在dockerfile中指定ASPNETCORE_PORT环境变量,然后程序监听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
(); webBuilder.UseNLog(); });

异常处理

由于gRPC服务端只能throw 基于 Grpc.Core.RpcException 的异常类型,所以我们可以自定义中间件来统一处理下异常

using Grpc.Core;using Grpc.Core.Interceptors;using System;using System.Threading.Tasks;public class ExceptionInterceptor : Interceptor    {        public override async Task
UnaryServerHandler
( TRequest request, ServerCallContext context, UnaryServerMethod
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 的异常,转换为 RpcException。此中间件也是根据具体的业务需求来做的,主要是告诉大家可以重写 Grpc.Core.Interceptors.Interceptor 的拦截器来统一处理一些事情。

定义协议缓冲区(protocol3)

新建项搜索rpc可以出现协议缓冲区文件

定义示例接口,创建订单方法,以及创建订单入参和出参。关于proto3协议具体说明,请参考往期文章。

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"表示当前是服务端。改好后重新生成下项目。

创建OrderService

手动创建OrderService,继承自Order.OrderBase(proto自动生成的代码)

public class OrderService : Order.OrderBase    {        public async override Task
CreateOrder(CreateOrderRequest request, ServerCallContext context) { //todo something //throw RpcException异常 throw new RpcException(new Status(StatusCode.NotFound, "资源不存在")); //返回 return new CreateOrderReply { Success = true }; } }

重写CreateOrder方法,此处就可以写你的实际的业务代码,相当于Controller接口入口。如果业务中需要主动抛出异常,可以使用RpcException,有定义好的一套状态码和异常封装。

修改Startup

在ConfigureServices方法中加入AddGrpc,以及上面提到的异常处理中间件,代码如下

services.AddGrpc(option => option.Interceptors.Add
());

在Configure方法中将OrderService启用,代码如下

app.UseEndpoints(endpoints =>            {                endpoints.MapGrpcService
(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync("this is a gRPC server"); }); });

至此 gRPC服务端搭建完成。

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客户端

创建项目

创建web api项目,此步骤说明省略

引入nuget包

引入gRPC 客户端需要的 nuget包,Google.Protobuf 3.12.4、Grpc.Tools 2.30.0和Grpc.Net.ClientFactory 2.30.0

引入proto文件

将服务端的 order.proto 拷贝到客户端的web api项目中,并在csproj文件中添加ItemGroup节点。GrpcServices="Client"表示当前是客户端。改好后重新生成下项目。

修改Startup

在ConfigureServices方法中加入AddGrpcClient,代码如下

services.AddHttpContextAccessor(); AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);  var baseUrl = "http://localhost:5001/"; services.AddGrpcClient
( options => { options.Address = new Uri(baseUrl); });

注意:要使用.NET Core客户端调用不安全的gRPC服务,需要进行其他配置。gRPC客户端必须将System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport开关设置为true,并在服务器地址中使用http。可以在以下链接查看具体说明。

[Troubleshoot gRPC on .NET Core]

另外说明下services.AddGrpcClient方法,来自于nuget包Grpc.Net.ClientFactory 2.30.0,将gRPC客户端的注入封装,具体代码实现可以查看以下链接。

Grpc.Net.ClientFactory

客户端调用

以在Controller中调用为例,示例代码如下

[ApiController]    [Route("[controller]")]    public class WeatherForecastController : ControllerBase    {        private readonly Order.OrderClient _orderClient;        public WeatherForecastController(Order.OrderClient orderClient)        {            _orderClient = orderClient;        }        [HttpGet]        public async Task
> Get() { var result = await _orderClient.CreateOrderAsync(new CreateOrderRequest { ItemCode = "123", ItemName = "名称1" }); } }

通过构造函数注入gRPC客户端,然后就可以使用里面的同步或者异步方法啦!

转载地址:http://kbkdi.baihongyu.com/

你可能感兴趣的文章
Servlet和JSP的线程安全问题
查看>>
GBK编码下jQuery Ajax中文乱码终极暴力解决方案
查看>>
Oracle 物化视图
查看>>
PHP那点小事--三元运算符
查看>>
解决国内NPM安装依赖速度慢问题
查看>>
Brackets安装及常用插件安装
查看>>
Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
查看>>
fastcgi_param 详解
查看>>
Nginx配置文件(nginx.conf)配置详解
查看>>
标记一下
查看>>
一个ahk小函数, 实现版本号的比较
查看>>
IP报文格式学习笔记
查看>>
autohotkey快捷键显示隐藏文件和文件扩展名
查看>>
Linux中的进程
查看>>
学习python(1)——环境与常识
查看>>
学习设计模式(3)——单例模式和类的成员函数中的静态变量的作用域
查看>>
自然计算时间复杂度杂谈
查看>>
当前主要目标和工作
查看>>
Intellij IDEA启动优化,让开发的感觉飞起来
查看>>
使用 Springboot 对 Kettle 进行调度开发
查看>>