可靠的Webhook调度系统

Reliable Webhook dispatching system

我很难为 webhook 调度系统找出可靠且可扩展的解决方案。

当前系统使用 RabbitMQ 和一个 webhook 队列(我们称之为 events),它们被消耗和调度。这个系统用了一段时间,但现在有几个问题:

所以,问题是 - 是否有更好的 way/system 用于此目的?也许我缺少一个非常简单的解决方案,可以让一个用户不干扰另一个用户?

提前致谢!

您可以尝试几个 rabbitmq 功能来缓解您的问题(无需完全删除它):

  • 使用 public random exchange 将事件拆分到多个队列中。它将减轻事件的大量峰值并将工作分派给多个消费者。

  • 为您的队列设置一些 TTL policies。这样,如果处理速度不够快,Rabbitmq 可能会将事件重新发布到另一组队列(例如,通过另一个私有随机交换)。

您可能有多个事件“周期”,配置不同(即周期数和每个周期的 TTL 值)。您的第一个周期会尽可能地处理新事件,在随机交换下通过多个队列减少峰值。如果它不能足够快地处理事件,事件将移动到另一个具有专用队列和消费者的周期。

这样,您可以确保新事件有更好的变化,以便快速处理,因为它们总是在第一个周期发布(而不是在另一个用户的一堆旧事件之后)。

如果您需要订单,很遗憾,您需要依赖用户输入。

但是在 Kafka 的世界里,有几件事要在这里提一下;

  • 您可以使用 Transactions 实现 exactly-once 交付,这允许您构建与常规 AMQP 类似的系统。
  • Kafka 支持按键分区。这允许您保持相同键的处理顺序(在您的情况下为 userId)。
  • 可以通过调整所有生产者、服务器和消费者端(批量大小、飞行请求等。有关更多参数,请参阅 Kafka documentation)来提高吞吐量。
  • Kafka 支持消息压缩,它可以减少网络流量并提高吞吐量(对于像 LZ4 这样的快速压缩算法,只是消耗更多 CPU 的能力)。

分区在你的场景中是最重要的。您可以增加分区以同时处理更多消息。您的消费者可以与同一消费者组中的分区一样多。即使您在达到分区数后进行扩展,您的新消费者也将无法读取并且他们将保持未分配状态。

与常规的 AMQP 服务不同,Kafka 在您阅读消息后不会删除消息,只是标记 consumer-gorup-id 的偏移量。这允许您同时做几件事。就像在单独的进程中计算实时用户数一样。

所以,我不确定这是否是解决此问题的正确方法,但这是我想出的方法。

先决条件:具有重复数据删除插件的 RabbitMQ

所以我的解决方案包括:

  • g:events 队列 - 我们称它为 parent 队列。该队列将包含需要处理的所有 child 个队列的名称。可能它可以用其他一些机制代替(比如 Redis sorted Set 之类的),但是你必须自己实现 ack 逻辑。
  • g:events:<url> - 有 child 个队列。每个队列仅包含需要发送到 url.
  • 的事件

当post将 webhook 负载发送到 RabbitMQ 时,您 post 将实际数据发送到 child 队列,然后另外 post child 队列到 parent 队列。重复数据删除插件不允许相同的 child 队列被 post 编辑两次,这意味着只有一个消费者可以接收该 child 队列进行处理。

你们所有的消费者都在消费parent队列,收到一条消息后,他们开始消费消息中指定的child队列。在 child 队列为空后,您确认 parent 消息并继续。

此方法可以非常精细地控制允许处理哪些 child 队列。如果某些 child 队列花费了太多时间,只需 ack parent 消息并将相同的数据重新发布到 parent 队列的末尾。

我知道这可能不是最有效的方法(不断 posting 到 parent 队列也有一些开销),但它就是这样。