.NET Core微服务架构设计与实现

在现代软件开发中,微服务架构因其灵活性和可扩展性而受到青睐。本文将介绍如何使用.NET Core构建一个基于消息的微服务架构,并展示如何通过RabbitMQ和MongoDB实现后端服务的解耦和数据持久化。

本文是关于.NET Core微服务架构设计的第二部分,继前一篇之后,将演示如何使用.NET Core构建一个命令驱动/基于消息的解决方案。在前一篇中,实现了一个简单的自动银行功能,如余额查询、存款和取款,使用ASP.NET Core Web API和C#.NET,以及Entity Framework和SQL Server。本部分将介绍如何设计一个基于队列的消息解决方案,使用RabbitMQ插入一个功能,通过后台服务生成月度账户报表,并将其存储在No-SQL数据库(MongoDB)中,然后通过一个单独的微服务进行访问。

问题描述

从SQL Server中实时生成用户账户报表等报告,由于数据量巨大,会导致实时系统中的性能问题。更好的处理方法是将报表生成过程(写/命令)和数据访问(读/查询)分离。本文将展示如何通过后台服务分离命令责任,并通过单独的微服务查询数据,从而解决性能问题,使系统能够通过独立扩展服务来处理大量数据。

应用架构

下图是更新后的架构图。突出显示的部分是新添加的微服务,用于访问账户报表。这个"Statement"服务使用MongoDB作为持久存储,并使用Redis Cache作为临时存储,数据从MongoDB加载到缓存中一段时间,并在后续访问中从缓存中检索。

解决方案设计

下图显示了后台实现的高级设计,它通过命令/消息处理和查询数据分离写操作。它有三个核心组件,通过命令/消息处理和查询数据分离写操作。

  • 发布者API/调度服务
  • 接收者服务
  • 报表API

发布者API/调度服务:当需要为给定月份生成月度账户报表时,此微服务将命令发布到消息总线(消息队列)。此服务有一个自动调度器,按计划时间触发报表生成过程,并且也公开WebApi端点以手动触发该过程。

接收者服务:接收者服务是一个监听器,监听消息队列并消费传入的消息并处理它。接收者与其它依赖服务通信以获取数据,并为给定月份生成用户的月度账户报表,并将文档存储在MongoDB中。

报表API:此微服务公开一个WebApi端点,通过数据存储库与Redis Cache和MongoDB通信以访问账户报表。

开发环境

.NET Core 2.2 SDK Visual Studio .NET 2017 Microsoft Azure SQL Server Management Studio (SSMS) MongoDB Compass Redis Desktop Manager (RDM)

开源工具和技术

Mongo DB 作为持久存储 Redis Cache 作为临时存储 RabbitMQ 作为消息代理 EasyNetQ 作为 RabbitMQ 客户端 NCrontab 用于基于时间的调度 .NET Core IHostedService 作为后台服务

WebApi端点

在"Publisher API"中实现的端点,用于将命令发布到消息队列:

  • 路由:"api/publish/statement" [HttpPost] - 触发后台进程的消息发布到队列。默认为上个月。
  • 路由:"api/publish/statement/{month}" [HttpPost] - 触发后台进程的消息发布到队列。
  • 路由:"api/publish/statement/{month}/accountnumbers" [HttpPost] - 触发后台进程的消息发布到队列,用于给定的账户号码列表。

在"Statement API"中实现的端点,用于访问账户报表:

  • 路由:"api/statement/{month}" [HttpGet] - 访问经过身份验证的用户给定月份的账户报表

通过API网关配置和可访问的端点,用于访问账户报表:

  • 路由:"statement/{month}" [HttpGet] - 访问经过身份验证的用户给定月份的账户报表。

解决方案结构

下图中突出显示的部分显示了示例中新添加的服务/组件。

组件间的交互

下图显示了后台服务中组件/对象之间的交互。

消息队列:后台服务"Publisher"和"Receiver"使用两个不同的队列。其中一个是"Trigger"队列。调度器的初始触发器/命令发送到"Trigger"队列,由"Receiver"服务处理。工作流中的第二个队列是"Statement"队列,它从"Trigger"处理器接收输入,并由"Statement"处理器处理。

消息类型:后台服务"Publisher"和"Receiver"理解类型为ICommand的消息,该消息在"Publish.Framework"中定义。定义了两种消息类型,用于两个不同的队列,"TriggerMessage"和"StatementMessage"。

  • Publisher:通过调度器或在调用API端点时,定时将"Trigger"消息发送到"Trigger"队列。
  • Receiver:消费"Trigger"消息,并为用户账户列表准备"Statement"消息,并将"Statement"消息发布到下一个队列。然后"Receiver"服务消费"Statement"消息并调用处理器。
  • Processor:包含准备账户报表的逻辑。
  • 文档存储库:包含将文档保存到MongoDb的数据逻辑。

使用Cron表达式的计划后台任务

Cron表达式是一种格式,用于指定基于时间的任务执行计划。NCrontab是包含在"Publisher.Service"中的Nuget包,用于解析表达式并确定下一次运行。服务配置为在每个月的开始触发后台进程,生成上个月的账户报表。

微服务之间的通信

微服务需要相互通信,以便在发生更改时通知其他服务或获取依赖信息。在示例中,使用了同步和异步机制来建立微服务之间的通信。

基于消息的异步通信用于触发事件。这是点对点通信,有一个单一的接收者。这意味着当消息发布到队列时,有一个单一的接收者消费消息以进行处理。下图显示了"Publisher / Scheduler"和"Receiver"通过消息总线发生的异步通信。

后台服务"Receiver"通过Http请求与依赖服务(Identity和Transaction)通信,以获取后台处理的实际数据。

如何运行应用程序

按照中给出的相同说明运行应用程序。此外,新添加的服务(Publisher、Receiver和Statement API)也应该运行。

需要在本地环境或云中设置MongoDB和Redis Cache。然后,可以在"Receiver.Service"和"Statement.Service"的appsettings.json文件中更新MongoDB和Redis Cache连接设置。

对于数据库更改,请参考包含在此版本代码中的数据库项目,该项目有更新的脚本。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485