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

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

gRPC(rpc远程调用)

gRPC-微服务间通信实践

  • 场景:A服务主动发起请求到B服务,同步方式
  • 范围:只在微服务间通信应用

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

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

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

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

搭建框架介绍

新建项目

  1. 新建解决方案 DotNetCore.Cap.Demo
  2. 新建项目 DotNetCore.Cap.Demo.Publisher 消息发布端
  3. 新建项目 DotNetCore.Cap.Demo.Subscriber 消息订阅端

主要sdk

  • 项目框架 netcoreapp 3.1
  • 消息队列选用RabbitMQ
  • 数据库存储选用PostgreSql

根据实际情况选择合适的消息队列和数据库存储

CAP 支持 Kafka、RabbitMQ、AzureServiceBus 消息队列:

PM> Install-Package DotNetCore.CAP.Kafka
PM> Install-Package DotNetCore.CAP.RabbitMQ
PM> Install-Package DotNetCore.CAP.AzureServiceBus

CAP 提供了 Sql Server, MySql, PostgreSQL,MongoDB 作为数据库存储:

PM> Install-Package DotNetCore.CAP.SqlServer
PM> Install-Package DotNetCore.CAP.MySql
PM> Install-Package DotNetCore.CAP.PostgreSql
PM> Install-Package DotNetCore.CAP.MongoDB

本次demo使用的nuget包如下所示

$ dotnet list package
项目“DotNetCore.Cap.Demo.Publisher”具有以下包引用
[netcoreapp3.1]:
顶级包 已请求 已解决
> DotNetCore.CAP 3.1.1 3.1.1
> DotNetCore.CAP.PostgreSql 3.1.1 3.1.1
> DotNetCore.CAP.RabbitMQ 3.1.1 3.1.1
> Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.10.9 1.10.9
> Npgsql.EntityFrameworkCore.PostgreSQL 3.1.4 3.1.4
> Npgsql.EntityFrameworkCore.PostgreSQL.Design 1.1.0 1.1.0 项目“DotNetCore.Cap.Demo.Subscriber”具有以下包引用
[netcoreapp3.1]:
顶级包 已请求 已解决
> DotNetCore.CAP 3.1.1 3.1.1
> DotNetCore.CAP.PostgreSql 3.1.1 3.1.1
> DotNetCore.CAP.RabbitMQ 3.1.1 3.1.1
> Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.10.9 1.10.9
> Npgsql.EntityFrameworkCore.PostgreSQL 3.1.4 3.1.4
> Npgsql.EntityFrameworkCore.PostgreSQL.Design 1.1.0 1.1.0

DotNetCore.Cap.Demo.Publisher 消息发布端

修改Startup文件

注入dotnetcore.cap组件及数据库上下文

    services.AddDbContext<PgDbContext>(p => p.UseNpgsql("数据库连接字符串"));

    services.AddCap(x =>
{
//rabbitmq在docker运行时,需要映射两个端口:5672和15672
//5672供程序集访问
//15672供web访问
//默认用户名和密码为:guest/guest
x.UseRabbitMQ(p =>
{
p.HostName = "localhost";
p.Port = 5672;
p.UserName = "guest";
p.Password = "guest";
});
x.UseEntityFramework<PgDbContext>();
//x.FailedRetryCount = 1;
//x.UseDashboard();
});

新建Controller作为Publisher

  • 构造函数注入DotNetCore.CAP.ICapPublisher

提供了同步和异步的消息发布方法

  • 发布字符串消息

await _capPublisher.PublishAsync("消息名称", "消息内容");

        [HttpGet("string")]
public async Task<IActionResult> PublishString()
{
await _capPublisher.PublishAsync("sample.rabbitmq.demo.string", "this is text!");
return Ok();
}
  • 发布对象

await _capPublisher.PublishAsync("消息名称", "消息对象");

        [HttpGet("dynamic")]
public async Task<IActionResult> PublishDynamic()
{
await _capPublisher.PublishAsync("sample.rabbitmq.demo.dynamic", new
{
Name = "xiao gou",
Age = 18
});
return Ok();
}
  • 分布式事务场景

当需要在数据库操作后,发布消息出去,DotNetCore.Cap也提供了分布式事务的解决方案。它扩展的transcation能保证只有在数据库操作和消息发送都完成后,才提交Commit

        [HttpGet("transcation")]
public async Task<IActionResult> PublishWithTranscation()
{
using (var trans = _pgDbContext.Database.BeginTransaction(_capPublisher))
{ var apiConfig = new ApiConfig
{
ApiName = "111122",
ApiDesc = "223",
ReturnType = "1",
ReturnExpect = "1",
IsAsync = true,
OperCode = "999",
OperTime = DateTime.Now
}; await _pgDbContext.ApiConfig.AddAsync(apiConfig);
await _pgDbContext.SaveChangesAsync(); _capPublisher.Publish("sample.rabbitmq.demo.transcation", apiConfig); trans.Commit(); return Ok();
}
}

DotNetCore.Cap.Demo.Subscriber 消息订阅端

修改Startup文件

注入dotnetcore.cap组件及数据库上下文

    services.AddDbContext<PgDbContext>(p => p.UseNpgsql("数据库连接字符串"));

    services.AddCap(x =>
{
//rabbitmq在docker运行时,需要映射两个端口:5672和15672
//5672供程序集访问
//15672供web访问
//默认用户名和密码为:guest/guest
x.UseRabbitMQ(p =>
{
p.HostName = "localhost";
p.Port = 5672;
p.UserName = "guest";
p.Password = "guest";
});
x.UseEntityFramework<PgDbContext>();
//x.FailedRetryCount = 1;
//x.UseDashboard();
});

新建Controller作为Subscriber

  • 订阅字符串消息

[NonAction] 标签:Indicates that a controller method is not an action method.

[CapSubscribe] 标签:标志此方法为订阅方法,并以消息名称匹配发布端的消息事件

        [NonAction]
[CapSubscribe("sample.rabbitmq.demo.string")]
public void SubscriberString(string text)
{
Console.WriteLine($"【SubscriberString】Subscriber invoked, Info: {text}");
}
  • 订阅对象消息

方法入参person即为消息体

        [NonAction]
[CapSubscribe("sample.rabbitmq.demo.dynamic")]
public void SubscriberDynamic(dynamic person)
{
Console.WriteLine($"【SubscriberDynamic】Subscriber invoked, Info: {person.Name} {person.Age}");
}

新建Service作为Subscriber

  • 除了Controller可以作为消息订阅端外,也可以用继承自DotNetCore.CAP.ICapSubscribe接口的Service作为订阅端
  • Controller作为订阅者时,不用继承ICapSubscribe;Service作为订阅者时,必须继承ICapSubscribe
  • Controller和Service同时订阅了一个消息时,只触发了Service的消费;若要多个消费,需要在不同的Group下
using DotNetCore.CAP;
using System; namespace DotNetCore.Cap.Demo.Subscriber.Services
{
/// <summary>
/// 消费订阅服务
/// </summary>
public class SubscriberService : ICapSubscribe
{ [CapSubscribe("sample.rabbitmq.demo.string")]
public void SubscriberString(string text)
{
Console.WriteLine($"【SubscriberString】Subscriber invoked, Info: {text}");
} [CapSubscribe("sample.rabbitmq.demo.dynamic")]
public void SubscriberDynamic(dynamic person)
{
Console.WriteLine($"【SubscriberDynamic】Subscriber invoked, Info: {person.Name} {person.Age}");
} [CapSubscribe("sample.rabbitmq.demo.object")]
public void SubscriberObject(Person person)
{
Console.WriteLine($"【SubscriberObject】Subscriber invoked, Info: {person.Name} {person.Age}");
} [CapSubscribe("sample.rabbitmq.demo.trans")]
public void SubscriberTrans(ApiConfig apiConfig)
{
Console.WriteLine($"【SubscriberTrans】Subscriber invoked, Info: {apiConfig.Id}");
}
}
}

总结

  • DotNetCore.Cap 是一种异步消息的通信,可以作为微服务间通信的一种方式
  • DotNetCore.Cap 为微服务架构提供了分布式事务的解决方案,保障了数据的最终一致性
  • 开发中,应根据实际业务需求和场景,选择合适可靠的微服务间通信方案

参考

https://github.com/dotnetcore/CAP/blob/master/README.md

https://book.douban.com/subject/33425123/

CAP-微服务间通信实践的更多相关文章

  1. gRPC-微服务间通信实践

    微服务间通信常见的两种方式 由于微服务架构慢慢被更多人使用后,迎面而来的问题是如何做好微服务间通信的方案.我们先分析下目前最常用的两种服务间通信方案. gRPC(rpc远程调用) 场景:A服务主动发起 ...

  2. .NET Core 微服务学习与实践系列文章目录索引(2019版)

    参考网址: https://archy.blog.csdn.net/article/details/103659692 2018年,我开始学习和实践.NET Core,并开始了微服务的学习,以及通过各 ...

  3. 浅谈服务间通信【MQ在分布式系统中的使用场景】

    解决的问题 一项技术的产生必然是为了解决问题而生,了解了一项技术解决的问题,就能够很轻松的理解这项技术的设计根本,从而更好地理解与使用这项技术. 消息中间件和RPC从根本上来说都是为了解决分布式系统的 ...

  4. 007. 服务间通信 RPC & REST over HTTP(s) & 消息队列

    服务间通信 服务间通信的几种方式: RPC.REST over HTTP(s).消息队列.  https://www.jianshu.com/p/2a01d4383d0b RPC https://bl ...

  5. 从Uber微服务看最佳实践如何炼成?

    导读:Uber成长非常迅速,工程师团队快速扩充,据说Uber有2000名工程师,8000个代码仓库,部署了1000多个微服务.微服务架构是Uber应对技术团队快速增长,功能快速上线很出色的解决方案.本 ...

  6. SpringCloud使用Feign实现服务间通信

    SpringCloud的服务间通信主要有两种办法,一种是使用Spring自带的RestTemplate,另一种是使用Feign,这里主要介绍后者的通信方式. 整个实例一共用到了四个项目,一个Eurek ...

  7. Docker+Kubernetes(k8s)微服务容器化实践

    第1章 初识微服务微服务的入门,我们从传统的单体架构入手,看看在什么样的环境和需求下一步步走到微服务的,然后再具体了解一下什么才是微服务,让大家对微服务的概念有深入的理解.然后我们一起画一个微服务的架 ...

  8. 如何使用REDIS进行微服务间通讯

    如何使用REDIS进行微服务间通讯 尽可能避免service - to - service通信.为此,需要在服务之间推一个消息队列.回顾一下微服务的概念小型的,非常集中的进程彼此独立运行并且易于维护, ...

  9. eShopOnContainers 知多少[11]:服务间通信之gRPC

    引言 最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信.那就索性也写一篇,作为系列的补充. gRPC 老规矩,先来理一下gRPC的基本概念 ...

随机推荐

  1. java执行器

    Executor 执行已提交的 Runnable 任务对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.Executor 接口并没有严格地要求执行是 ...

  2. SessionMiddleware源码分析

    settings.py文件中 MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', ] # from djang ...

  3. Final终态类和Finally

  4. 在CentOS Linux 7.5上安装MySQL

    本文来自与https://www.linuxidc.com/Linux/2018-05/152574.htm 随着CentOS 7 MySQL的发布,世界上最流行的开源关系数据库管理系统在CentOS ...

  5. C++ (C#)实现获取NX PART预览图

    VS环境下 C++版本: 1 int GetPreviewImage(const TCHAR* prtFile, const TCHAR* imageFile) 2 { 3 IStorage* pSt ...

  6. python语言概述

    python语言的发展 python语言诞生于1990年,由Guide van Rossum设计并领导开发. python语言是开源项目的优秀代表,其解释器的全部代码都是开源的. 编写Hello程序 ...

  7. 关于TCP建立连接

    TCP大家大多称之为"三次握手".今天看了一篇文章,学到了"三步握手". TCP建立连接,客户端发送SYN给服务端,服务端接收到请求回应ACK.服务端发送SYN ...

  8. Appium 用途和特点

    Appium 是一个移动 App (手机应用)自动化工具. 手机APP 自动化有什么用? 自动化完成一些重复性的任务 比如微信客服机器人 爬虫 就是通过手机自动化爬取信息. 为什么不通过网页.HTTP ...

  9. 适用于 deno 的多版本管理工具 dvm 发布

    不知不觉中,deno 已经默默的发布了 3 个版本了: 0.1.0 0.1.1 0.1.2 昨晚通宵做了一个 deno 多版本的管理工具: dvm. github 地址: https://github ...

  10. spring cloud gateway(三、实现限流)

    限流一般有两个实现方式,令牌桶和漏桶 金牌桶是初始化令牌(容器)的个数,通过拿走里边的令牌就能通过, 没有令牌不能报错,可以设置向容器中增加令牌的速度和最大个数 漏桶是向里边放入请求,当请求数量达到最 ...