【问题标题】:Message broker vs. database and monitoring消息代理与数据库和监控
【发布时间】:2018-06-14 09:50:08
【问题描述】:

我的问题与这个问题有一些相似之处: Why do we need message brokers like RabbitMQ over a database like PostgreSQL?

在我目前的(半专业)项目中,我还需要决定是否选择数据库、基于消息代理的(例如使用 RabbitMQ),甚至是完全不同的解决方案。

让我们想象两个工具,工具 A 和工具 B。 每当工具 A 运行并完成时,可能工具 B 需要做一些事情。工具 A 的执行需要一些时间(> 60 秒),而且工具 B 通常无事可做。工具A 为工具 B 提供了一些元数据,因此工具 B 知道该做什么。

基于消息的解决方案:建立一个工具 B 正在消费的消息队列。如果工具 A 已执行并且工具 B 应该运行,工具 A 会向工具 B 接收的队列发布一条消息(包括元数据),以便工具 B 使用消息中的元数据运行。 p>

数据库解决方案:每当工具 A 运行时,它都会添加一条数据库记录,例如时间戳、元数据和状态“正在运行”。如果工具 A 已执行并且工具 B 应该运行,它会将 DB 记录状态更新为“NEXT_TOOL_B”。工具 B 不断地在数据库中查询具有“NEXT_TOOL_B”状态的记录。万一它发现了什么,工具 B 将使用数据库记录中的元数据运行。

虽然我知道数据库解决方案的缺点,例如来自工具 B 的不断轮询,我错过了它在基于消息的解决方案中的一个功能:

每当使用第 3 个工具时,就说工具 C,例如一个控制面板用户界面,想知道当前状态,也可以随时查询数据库,如果工具A仍在工作,它会找到“正在运行”状态。在消息解决方案中,我真的看不到“监控”状态的方法,除非完成消息将在队列中。

所以我的问题是,您能想出使用消息或任何其他无需轮询的方式来实现此目的的方法吗?

【问题讨论】:

  • 我不确定你为什么反对这两个工具。消息队列可以帮助您编写松耦合的应用程序(或应用程序组件)和数据库来保存状态。您需要获取一个状态,从数据库中获取它。您需要使您的组件进行通信,使用消息队列。如果由于管理开销而不想要两者,则必须做出选择并接受缺点。因此,这是软件工程社区的问题,而不是 stackoverflow。
  • 有几篇文章,例如this one,其中消息队列比数据库更适合工具间通信。当然,像锁定这样的数据库提到的缺点在很大程度上取决于应用程序的规模。最后,作为一名控制工程师而不是软件开发人员,我希望得到像你这样的反馈,我可能想要一个混合解决方案,而不是使用一个或另一个,而是两者兼而有之。
  • 假设您想将工具 A 扩展为 10 个实例,将工具 B 扩展为 10 个实例。您如何确保工具 A 中的任务只处理一次?所有 10 个都将轮询数据库,第一个找到就绪任务的人必须锁定任务表并在持有锁的同时对其进行更新......不是很好。虽然一些工具 A 实例想要编写一个新任务,但等待并且失败了......您可能已经丢失了数据......而使用消息队列 - 您只有所有 10-100 个(没关系)工具实例B 坐在一个工作队列上,只有一个实例会收到消息。

标签: database rabbitmq message-queue


【解决方案1】:

免责声明:我是cluster-tasks-service - CTS 的作者,建议使用其他相关工具来考虑解决方案或其他模式。

问题是,从一般架构的角度来看,您所描述的功能似乎需要两种类型的解决方案:

  • 工具 B 作为工具 A 完成的工作的结果而执行的部分是事件驱动流程中的经典。消息通常在这方面更有效,但请继续阅读...
  • 您希望对流进行一些状态观察/监视的部分肯定需要保持状态(嗯,是的,甚至不在内存中,或者至少在分布式内存中,因为您稍后会想要一个集群等)

我想说基于数据库的队列将是一个解决方案。基于数据库的队列肯定比非基于数据库的方法具有更低的吞吐量。但是,它会给您带来一些好处,例如:

  • 保证持久性,不会丢失任何任务/消息,除非发生真正的灾难,然后队列是最少的问题
  • 智能任务管理通过数据库同步,无需复杂的系统拓扑、主/从问题、故障转移等
  • 获得这样的队列作为嵌入式解决方案要容易得多 - 与单独的 Redis/Rabbit/Kafka 安装/服务相比,运营成本非常低

CTS 而言 - 这是一个基于 DB 的集群感知任务分发和管理系统(由消费应用程序提供并运行嵌入式),您的问题可以通过将工具 B 作为工具 A 排队的任务运行来解决使用所有相关数据结束其流程。 同时,工具 C 可以使用CTS 的 API 来检查任务的状态,并根据需要进行可视化。

【讨论】:

    【解决方案2】:

    您可以让队列的生产者和消费者更新 NoSQL 数据库或 RDBMS 中的表。这将允许您在任何给定时间查看请求的状态。它还可以让您利用推送消息而无需轮询。

    【讨论】:

      【解决方案3】:

      问题中描述的场景是一个系统,它由多个不同的部分组成,它们共同工作以实现一个功能。在这种情况下,您拥有三个不同的进程{A,B,C},以及一个数据库和可选的消息队列。所有系统,作为其存在目的的一部分,接受一个或多个输入,执行一些过程,并产生一个或多个输出。在您的情况下,您想要的输出之一是系统的状态及其处理,这并不是一件完全不合理的事情。

      队列还是数据库?

      现在,回到你的问题。为什么使用消息队列而不是数据库?两者都是系统的相似组件,因为它们执行一些存储容量。您可能会在冰箱制造厂问同样的问题 - 什么时候在装配线上使用货架而不是仓库更有意义?

      数据库就像仓库——它们被设计用来容纳许多不同的东西,并保持它们相对整齐。一个好的仓库可以让用户快速找到仓库里的东西,避免丢失零件和材料。如果它进入,它可以很容易地回来,但不是立即。

      另一方面,消息队列就像装配线中靠近操作员站的货架。先前操作的零件在那里堆积,等待运行站的人消耗。这些架子的设计目的是容纳少量相同的东西——就像软件系统中的消息队列一样。它们离工人很近,所以当下一个零件准备好工作时,可以很快地取回它(而不是去仓库,这可能需要几分钟或更长时间)。此外,工人可以立即看到货架上的物品 - 如果货架是空的,工人可能会休息一下,等待它再次堆积一两件。

      最后,如果工厂的某个部分严重过度生产(我们不喜欢这种情况发生,因为它表示浪费),那么货架就会被压得喘不过气来,过剩的产品就需要放入仓库。信不信由你,这种情况在工厂中一直发生 - 有时车站会短暂停机,而仓库则充当长期缓冲。

      何时使用其中一种?

      所以 - 回到问题。当您期望您的消息生产通常与消息的消费相匹配并且您需要检索速度时,您可以使用消息队列。您不会期望事情会在队列中停留很长时间。软件队列系统(例如 RabbitMq)还执行一些非常具体的功能 - 例如确保作业仅由一个处理器处理,并且如果第一个处理器出现故障,它可以被另一个处理器拾取。

      另一方面,您可以将数据库用于需要跨多个处理步骤保持状态的事物。您的工作状态是应该存储在数据库中的完美示例。继续工厂类比 - 将其视为在每个步骤完成时发送回生产计划员的报告。生产计划员会将其保存在数据库中。

      当队列可能已满,或者当数据在一个作业步骤和另一个作业步骤之间丢失至关重要时,您还需要使用数据库。例如,制造厂通常会将其成品存放在仓库中,等待发货给客户。使用数据库来满足应用程序中的所有长期(超过几秒钟)存储需求。

      底线

      大多数可扩展的软件系统都需要队列和数据库,关键是知道何时使用它们。

      希望这有一定的意义。

      【讨论】:

        猜你喜欢
        • 2010-10-13
        • 2021-01-28
        • 2011-10-05
        • 2017-03-02
        • 1970-01-01
        • 2018-05-06
        • 2011-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多