如何确保我的事件仅由我的应用程序的一个实例处理?

rem*_*rel 6 queue events channel redis

在我们的架构中,我们有一个 Redis 服务器,用于缓存和发布事件。

我的问题如下

  • 我有一条名为“CustomerUpdate”的消息
  • 我有 1 个应用程序正在收听此消息
  • 正在执行此应用程序的 3 个实例(服务器)以实现可扩展性
  • 1 个数据库实例正在运行
  • 此消息的处理程序之一将更新数据库
  • 其他一些处理程序将擦除内存缓存或对实例执行本地操作

是否有任何模式可以确保应用程序的每个实例都不会更新数据库?

kha*_*nou 5

您可以使用 redis 键/值作为拦截器。当实例收到来自订阅的消息时,在 redis 中执行 LUA 脚本以检查它的进程是否已经存在。

服务器从订阅接收消息使用 redis 脚本事务来检查是否已经存在此消息的锁(类似于 get receiveMessageId:XXX)。如果 value 已经以 false 退出,那么在服务器上什么都不做。如果该值不存在,则设置它并返回 true。然后您的服务器可以处理该消息。

由于 Redis 是单线程的,如果消息被其他服务器接收,所有其他服务器都会得到一个 false。

要删除此密钥,您可以设置足够大的 TTL 以避免从其他服务器获取消息。


nno*_*nog 0

我将设置一个或多个列表作为 CustomerUpdate 的可操作任务的队列。相反(或同时)发布 CustomerUpdate,您将LPUSH进入列表。每个列表元素的值将对更新的参数进行编码。

然后只需BRPOP在每个需要竞争作业的处理程序中循环使用即可。这是一个带有超时的阻塞 pop,专为此类用例而设计。 http://redis.io/commands/brpop

优点:没有键空间通知,许多作业处理程序可以在没有竞争的情况下弹出,可以将必要的任务分成单独的列表,以及BRPOP一次多个列表。

缺点:发布 CustomerUpdate 的任何内容都需要更改,并且可能需要进行多次更改LPUSHs、可能需要更改MULTI/EXEC或类似操作。如果您无法更改此方面,则需要另一个进程(不同的客户端)来订阅 CustomerUpdates 并推送作业。