RabbitMQ 架构与 AngularJS/.NET Web API 应用程序相结合
Posted
技术标签:
【中文标题】RabbitMQ 架构与 AngularJS/.NET Web API 应用程序相结合【英文标题】:Architecture for RabbitMQ in tandem with AngularJS/.NET Web API application 【发布时间】:2016-05-13 20:22:42 【问题描述】:所以我有一个 SPA(单页应用程序),其中 AngularJS 作为前端,.NET Web API 作为后端(C#)。我需要根据某些用户操作生成 SQL Server Reporting Services (s-s-rS) 报告,即选择一些数据并按下按钮。这是我现有架构的粗略说明:
FRONT END BACK END s-s-rS Report
========== ========= ===========
**AngularJS Web page**-->**.NET Web API controller**-->**Intermediary class (passes arguments to report)** -->**Generate report and save to file**
这可行,但问题是在生成报告时,应用程序必须坐在那里等待它们完成,同时用户不能做任何事情。如果要创建许多报告,例如 100 多个,则可能需要一两分钟以上的时间,这对我来说是不可接受的。
这就是 RabbitMQ 的用武之地。我的想法是让 .NET Web API 控制器向服务器发送消息,一旦服务器接收到消息,就会对上面的中间类执行调用,从而生成报告,然后将响应发送回客户端,让他们知道报告已生成。我想我需要为此使用 RPC 场景,所以我在 RabbitMQ 网站上完成了相应的教程,看起来很简单。
但我不知道,这就是我的问题,是如何从 .NET Web API 应用程序启动客户端和服务器。坦率地说,我现在有点迷茫,因为这是我第一次真正体验任何类型的消息传递,我不太确定如何处理它,架构方面的。如果我能在脑海中详细了解整个事情是如何工作的,我可以从那里编写代码,但是在这一点上,我无法想象如何构建应用程序。
所以,问题:
如何从 .NET Web API 控制器启动 RabbitMQ 服务器和客户端?服务器和客户端应该是类库还是控制台应用程序,还是完全是其他东西?
我所设想的架构会起作用还是有更好的方法?
任何关于如何实现我想要完成的任务的一般性建议都将不胜感激。
【问题讨论】:
【参考方案1】:RabbitMQ 服务器不是从控制器启动的东西 - 它一直在运行。从控制器发送消息到rabbitmq 服务器。另一方面,另一个应用程序(Windows 服务、控制台应用程序,甚至 linux 上的单声道服务)监听这些消息并处理它们。 RabbitMQ 服务器只管理端点之间的消息发送。在您的情况下,处理来自您的控制器的消息的应用程序也始终在运行(使其成为 Windows 服务非常合理)。
这样的架构可以正常工作。不过,RabbitMQ 可能有点矫枉过正——它更适用于多服务器、高负载的场景。如果您的负载较低并且所有应用程序都在同一台服务器上 - 您可以使用其他工具(如hangfire.io、MSMQ,或者甚至只是在 Web 服务器进程中运行后台任务,正如另一个答案所建议的那样)。如果简单的工具可以完成您的工作 - 为什么不呢。
在生成报告时不要一直保持从客户端(浏览器)到服务器的连接。只需将任务放入兔子队列进行处理(或以其他方式开始生成报告)并返回。然后,如果工作完成,则从客户端定期轮询,或者(更好地)通过 websocket 连接通知客户端。这当然是在报告生成可能需要一些时间(比如说超过 30 秒)的情况下。
更新:更多关于整体架构的信息。
RabbitMQ 服务器作为 Windows 服务运行,与 Windows 一起启动。 当您收到通过 Web api 生成报告的请求时 - 您将 GenerateReport 消息与所需的所有信息一起发送,然后您返回(不等待生成报告)。如果您将报告存储在数据库中,那么它们是持久的 - 在数据库中创建关于报告请求的记录。否则 - 将有关待处理报告的信息保留在内存中(以便您知道目前正在生成 X 报告)。在理想情况下,您还可以通过 Web 套接字在客户端和服务器之间建立持久连接。如果是这种情况 - 您将实时通知用户报告生成状态。否则 - 用户将不得不不时轮询服务器。 另一边有你写的windows服务,也是和windows server一起启动的。它侦听 GenerateReport 消息并开始生成。可以有多个这样的服务,或者您可以在一个服务中拥有多个订阅 - 这将在多个服务之间平均分配工作量。在报告生成期间 - 发布 ReportProgress 消息。完成后 - 更新数据库中的报告(如果您保留它们)并发布 ReportDone 消息。 Web Api 服务中的后台线程会侦听此类消息。如果您有 websockets 连接 - 您只需将这些消息传递给客户端,以便他实时查看报告生成进度。否则 - 更新数据库或内存结构,以便下次客户端轮询报告状态时 - 你有一些东西要返回。 如果出现问题 - 没问题(如果您将报告保存在数据库中)。在启动时,如果有待处理的报告,您的生成服务将检查数据库并生成它们。如果客户端在报告生成期间断开连接(从网站) - 仍然没有问题,当他返回时报告将准备好并且可以从数据库提供服务。如果 web api 服务崩溃 - 仍然没有问题。【讨论】:
1. @Evk,您所描述的是否等同于远程过程调用(RPC)模式,其中有一个客户端和一个服务器,前者向后者发送消息,然后接收消息(带有结果)?这里有更详细的描述:rabbitmq.com/tutorials/tutorial-six-dotnet.html。 2.如果是这样,您所说的“另一个应用程序侦听这些消息并处理它们”是否对应于 RPC 模式中的客户端?此外,您说 RabbitMQ 服务器始终在运行,即使它不应该从控制器启动,也必须启动它。这是如何运作的?谁启动服务器?换句话说,假设我编写了服务器代码,就像上面 RabbitMQ 网站上的示例一样。在那之后我该怎么办?我假设我必须将它部署在某个地方并以某种方式对其进行配置,以便它始终运行。客户也有同样的问题。 @user452103 rabbit 只是一个或多个应用程序之间的消息总线(中介、代理)。在您的情况下,一个应用程序是您的 asp.net Web api 服务。另一个应用程序是生成报告的程序(例如 - 单独的控制台或 Windows 服务应用程序)。如果您使用 RPC 模式,应用程序 A(Web API)会向应用程序 B(Windows 服务)发送一条消息,要求生成报告。然后它等待,直到应用程序 B 将带有操作结果的消息发回。至于谁开始兔子。在 Windows 上,您可以将 rabbit 作为服务运行 - 然后它与 Windows 一起启动。 @user452103 还有一些事情。首先,因为您是 rabbit 新手 - 最好使用 rabbitmq api 的包装器(这个很好:easynetq.com)。它隐藏了很多关于 rabbitmq 的复杂事情,让你轻松完成工作。第二 - 在您的情况下最好不要使用 RPC 模式(请参阅我的回答中的第三点)。 感谢 easynetq 的建议。这看起来会很有用。至于模式,您是说 RPC 在我的情况下的一个缺点是它会一直连接客户端和服务器吗?如果不是 RPC,那么哪种模式会更好?也许是一个更简单的发送者-接收者模式,其中发送者发送一条消息(例如要生成一个报告),接收者接收它并调用报告生成 API?或者可能是一个工作队列,其中任务分布在多个工作人员之间?请记住,我可以有很多报告 (300-1000)。【参考方案2】:在切换到 RabbitMQ 之前,您是否尝试过使用 .Net 4.5 中引入的新 HostingEnvironment.QueueBackgroundWorkItem
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
return Task.Factory.StartNew(() =>
// Generate report and save to file
, cancellationToken);
);
【讨论】:
不,我没有。这是我第一次听说。它到底有什么作用? "安排一个可以在后台运行的任务,独立于任何请求。"和here's a blog post 提供更多详细信息。 听起来它有一些严重的限制。例如:“如果排队的项目太多以至于无法在 90 秒内完成,那么 ASP.NET 运行时将卸载 AppDomain,而无需等待工作项目完成。”这对我来说是一种破坏交易的方式,因为我可能会拥有如此多的报告,以至于它们很容易需要 90 多秒才能生成。以上是关于RabbitMQ 架构与 AngularJS/.NET Web API 应用程序相结合的主要内容,如果未能解决你的问题,请参考以下文章
RabbitMQ01_消息队列概述使用场景劣势架构图与主要概念Docker快速安装Rabbitmq角色分类
RabbitMQ01_消息队列概述使用场景劣势架构图与主要概念Docker快速安装Rabbitmq角色分类