gRPC-微服务间通信实践

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

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

  • 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<Startup>().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<Startup>();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<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 的异常,转换为 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"表示当前是服务端。改好后重新生成下项目。

<ItemGroup><Protobuf Include="Protos/GrpcTest.Protos" GrpcServices="Server" /></ItemGroup>

创建OrderService

手动创建OrderService,继承自Order.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方法,此处就可以写你的实际的业务代码,相当于Controller接口入口。如果业务中需要主动抛出异常,可以使用RpcException,有定义好的一套状态码和异常封装。

修改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服务端搭建完成。

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

<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客户端调用不安全的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<IEnumerable<WeatherForecast>> Get(){var result = await _orderClient.CreateOrderAsync(new CreateOrderRequest{ItemCode = "123",ItemName = "名称1"});}}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307468.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动 Azure 资源后如何快速修复 Dashboard

点击上方蓝字关注“汪宇杰博客”导语Azure 用户经常因为不够有钱&#xff0c;需要把资源移动到另一个资源组或订阅中。移动完成后&#xff0c;会导致资源对应的 Dashboard 失效。通常&#xff0c;我们都需要从 Dashboard 上将找不到的资源删除&#xff0c;并逐个重建。有没有快…

八大排序算法之插入排序

一:直接插入排序 1:思想 首先选择一个哨兵,我们默认将第一个数作为哨兵,随着循环的进行,我们一直将我们待插入数的前一个数作为哨兵然后就是插入的数与哨兵比较&#xff0c;比哨兵小的话&#xff0c;就将哨兵后移&#xff0c;然后再与哨兵前面的数进行比较&#xff0c;直到遇…

跟我一起学Redis之五种基本类型及其应用场景举例(干了6个小时)

前言来啦&#xff0c;老弟&#xff1f;来啦&#xff0c;上一篇就当唠唠嗑&#xff0c;接下来就开始进行实操撸命令&#xff0c;计划是先整体单纯说说Redis的各种用法和应用&#xff0c;最后再结合代码归纳总结。Redis默认有16个数据库(编号为0~15)&#xff0c;默认使用第0个&am…

leetcode周赛6070. 计算字符串的数字和

一:题目 二:上码 class Solution { public:/**思路:1.设置一个while循环&#xff0c;循环的条件是s.length<k2.while里面进行 1>:将字符串按k个进行拆分成个单个字符&#xff0c;并将其转换成数字,然后计算将计算结果再组成字符串 */string digitSum(string s, int k) {…

ASP.NET Core 中的 User Agent 识别及搜索引擎爬虫鉴定方法

User Agent中文名为用户代理&#xff0c;简称 UA&#xff0c;它是一个特殊字符串头&#xff0c;使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。百度百科在 ASP.NET Core 中&#xff0c;可以通过以下代码在 …

leetcode周赛6071. 完成所有任务需要的最少轮数

一:题目 二:上码 class Solution { public:/**思路:1.如果x1的话,那么的话 直接返回-12.如果x2的话&#xff0c;那么就一次执行3.如果x是3的倍数的话,那么就直接执行 x/3 次4.如果x/3 余数是1的话 那就执行 x/31,比方说是4 其实是两个2&#xff0c;但是我们求数的的时候,我们求…

netcore使用 jenkins + supervisor 实现standalone下多副本自动化发布

前面的文章聊过用 jenkins 做了一个简单的自动化发布&#xff0c;在shell中采用的是 BUILD_IDdontKillMe nohup dotnet xxx.dll & 这种简单的后台承载&#xff0c;如果你的业务量相对比较小&#xff0c;可以用这个方法玩一玩&#xff0c;但存在二个问题&#xff1a;1. 无法…

实战解读ASP.NET Core身份认证

长话短说&#xff1a;上文我们聊了 ASP.NET Core 基于声明的访问控制到底是什么鬼&#xff1f;今天我们乘胜追击&#xff1a;聊一聊ASP.NET Core 中的身份验证。身份验证是确定用户身份的过程。授权是确定用户是否有权访问资源的过程。1. 万变不离其宗显而易见&#xff0c;一个…

Java并发之AQS

文章目录一:AQS简介二:了解AQS 上锁和释放锁的原理1:前言2:上锁(非公平锁)(1):我们从main主函数中点进去(2):从lock进入(3):找到非公平锁中的lock(4):查看acquire()方法(5):查看tryAcquire(arg)方法a:前言介绍b:进入ReentrantLock类中的nonfairTryAcquire方法(6):addWaiter(Nod…

网络知识 | 《图解TCP/IP》读书笔记(上)

【网络知识】| 作者 / Edison Zhou这是EdisonTalk的第290篇原创内容作为一个专业的IT技术人&#xff0c;一个Web应用开发者&#xff0c;不了解网络基础和协议&#xff0c;怎么能行&#xff1f;本文是我2016年阅读《图解TCP/IP》一书的读书笔记&#xff0c;希望对你有所帮助&…

Java并发之semaphore(信号量)

文章目录1:官方解读2:通俗易懂的例子解析3:代码解析4:Semaphore的应用5:类结构和相关方法(1):类结构(2):acquire()方法(3):release()方法6:总结1:官方解读 semaphore信号量就是并发工具类,Semaphore管理着一组许可permit&#xff0c;许可的初始数量通过构造函数设定。 当线程要…

IdentityServer4系列 | 初识基础知识点

前言我们现在日常生活中&#xff0c;会使用各式各样的应用程序&#xff0c;层出不穷&#xff0c;其中有基于网页浏览方式的应用&#xff0c;有基于手机端的App&#xff0c;甚至有基于流行的公众号和小程序等等&#xff0c;这些应用&#xff0c;我们不仅要实现各个应用的功能之外…

八大排序算法之终章---归并排序

一:简单介绍 归并排序排序就是利用归并的思想实现的排序方法 它的原理是将初始化序列划分成n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并&#xff0c;得到(n/2)个长度为1或者2的有序子序列;然后再两两合并…不断重复 直到最后 得到一个长度为n的有序…

Firefox 18周岁

Mozilla Firefox 起源于开源运动兴起之初建立的一个项目组织——Mozilla 社区&#xff0c;可以说是最早以“开源”名义出现&#xff0c;并取得成功的项目之一。Firefox 首次发行是在2002年的9月23日&#xff0c;当时的代号为“Phoenix”&#xff08;凤凰&#xff09;。18年过去…

三种方式让你轻松监控 EntityFramework 中的 sql 流转

大家在学习entityframework的时候&#xff0c;都知道那linq写的叫一个爽&#xff0c;再也不用区分不同RDMS的sql版本差异了&#xff0c;但是呢&#xff0c;高效率带来了差灵活性&#xff0c;我们无法控制sql的生成策略&#xff0c;所以必须不要让自己缺乏好的工具去监控sql&…

java并发之CountdownLatch

一:CountdownLatch 1:基本含义 CountDownLatch中count down是倒数的意思&#xff0c;latch则是门闩的含义。整体含义可以理解为倒数的门栓&#xff0c;似乎有一点“三二一&#xff0c;芝麻开门”的感觉。CountDownLatch的作用也是如此&#xff0c;在构造CountDownLatch的时候…

leetcode142. 环形链表 II(详解)

一:题目 二:思路分析 三:上码 class Solution { public:ListNode *detectCycle(ListNode *head) {ListNode* slow head;ListNode* fast head;while (fast ! NULL && fast->next ! NULL && fast->next->next ! NULL) {//这里选用快指针fast fast-&g…

国产化之路-统信UOS /Nginx /Asp.Net Core+ EF Core 3.1/达梦DM8实现简单增删改查操作

引言经过前期的准备工作&#xff0c;.net core 3.1的运行环境和WEB服务器已经搭建完毕&#xff0c;这里需要注意一下&#xff0c;达梦DM8数据库对于Entity Framework Core 3.1 的驱动在NuGet官方源上并没有正式发布&#xff0c;需要从Win64安装版本中的drivers/dotNet提取&…

网络知识 | 《图解TCP/IP》读书笔记(下)

【网络知识】| 作者 / Edison Zhou这是EdisonTalk的第291篇原创内容作为一个专业的IT技术人&#xff0c;一个Web应用开发者&#xff0c;不了解网络基础和协议&#xff0c;怎么能行&#xff1f;本文是我2016年阅读《图解TCP/IP》一书的读书笔记下半部分。上半部分&#xff1a;点…

leetcode202. 快乐数(详解)

一:题目 二:上码 class Solution { public:/**思路&#xff1a;1.破解这道题的关键是 我们得破解这个无限循环2.根据这个题目给出的定义2 我们可以知道 无限循环的条件是我们 在计算的过程中出现了自己的数*/bool isHappy(int n) {unordered_set<int>s;s.insert(n);…