从 Hangfire 到 RabbitMQ:告别数据库轮询

Hangfire 非常适合小团队。你只需添加一个 NuGet 包并将其指向你的数据库,就能免费获得一个作业运行器(job runner)和一个仪表板(dashboard)。对于单一服务来说,它几乎是无可比拟的。

我在 SavePosty 中使用 Hangfire 来处理电子邮件、Webhooks 和内容获取。每个作业的工作方式都一样:它们每隔几秒钟就会轮询我的 Postgres 数据库,以检查是否有新任务。

我最终将所有内容都迁移到了 RabbitMQ。以下是我做出这一决定的原因以及我所失去的东西。

迁移原因:

  • 轮询负载随时间增长,而非随工作量增长。每个 Hangfire 作业都会按定时器访问你的数据库。即使没有任务,数据库也会保持忙碌。随着作业数量和轮询频率的增加,这种成本也会随之增长。
  • 模型过多。我应用的一部分已经在使用 RabbitMQ,而其余部分则在使用 Hangfire。这意味着需要两种不同的方式来管理后台任务。迁移到 RabbitMQ 统一了这一切。
  • 延迟。消息代理(broker)会在任务到达的瞬间将其推送。而 Hangfire 则需要等待下一次轮询。

权衡:

Hangfire 易于设置。它使用你现有的 SQL 表,并拥有出色的内置仪表板。

RabbitMQ 需要管理一个消息代理。它消耗的是 RAM 和网络资源,而不是数据库 CPU。你获得了更好的扩展性,但也增加了更多的运维开销。

如何安全迁移:

我保持业务逻辑完全不变。我构建了轻量级的消费者(consumers)作为“前门”。消费者接收消息并将其传递给现有的作业类(job class)。

我专注于两件事:

  • 重试一致性。我在 RabbitMQ 消费者中匹配了 Hangfire 的重试设置,以确保不会丢失消息。
  • Schema 安全性。我将旧列保持为可为空(nullable),以确保在部署期间不会破坏数据库。

我失去的东西:

最大的缺点是可见性。Hangfire 允许你点击一个失败的作业并查看具体发生了什么。RabbitMQ 会告诉你死信队列(Dead Letter Queue)中有多少消息,但它无法提供那种直观的、针对单个作业的视图。我现在依赖结构化日志,而不是仪表板。

我的建议:

如果满足以下条件,请继续使用 Hangfire:

  • 你运行的是单一服务。
  • 你有一个小团队。
  • 你需要一个易于调试的仪表板。

如果满足以下条件,请迁移到 RabbitMQ:

  • 你有多个服务。
  • 轮询带来的数据库负载很高。
  • 你想使用发布/订阅(pub/sub)模式。

决策取决于你的系统,而非单个作业。

Source: https://dev.to/gabrielleroux/from-hangfire-to-rabbitmq-killing-database-polling-in-a-net-app-4og4

Optional learning community: https://t.me/GyaanSetuAi