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

时间:2016-07-25 13:55:23

标签: events redis queue channel

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

我的问题如下

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

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

4 个答案:

答案 0 :(得分:3)

您可以使用redis键/值作为阻止程序。当实例从redis中的subcription excute LUA脚本接收消息时,检查进程是否已存在。

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

由于Redis是单线程的,如果其他服务器发出消息,则所有其他服务器将获得false。

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

答案 1 :(得分:2)

一个更简单的想法

1)不是将您的事件发布到频道“CustomerUpdate”,而是将它们放入队列中,并使用唯一的通知程序通知其所处的行为类型

LPUSH CustomerUpdate type1$somework

这里type1可以发送电子邮件,db中的条目等等,而且有些工作是你需要处理的工作。

2)在你的应用程序逻辑中,使用阻塞rpop。

BRPOP CustomerUpdate

在您的应用程序逻辑中分割工作类型和工作。如果返回type1执行该操作,如果返回type2则执行该操作,依此类推。然后进行这项工作。

示例代码段:

String message = jedis.brpop("CustomerUpdate",1000);
if(message.startsWith("type1$"))
sendMail(message.split("$")[1]);
else if(message.startsWith("type2$"))
sendAck(message.split("$")[1]);

优点:

  • 无需键空间通知
  • 即使应用服务器关闭了你 可以在重新启动时在队列中完成工作,而在 pub / sub你无法获得已经发布的消息。
  • 即使redis停机几秒钟,您也可以在何时获取数据 持久性已启用
  • 简单的数据结构(只是一个队列)

答案 2 :(得分:0)

我将一个或多个列表设置为CustomerUpdate可操作任务的队列。取而代之(或同时)发布CustomerUpdate,您可以LPUSH到列表中。每个列表元素的值将编码更新的参数。

然后在每个需要争用作业的处理程序的循环中简单地使用BRPOP。这是一个具有超时的阻止弹出,专为此类用例而设计。 http://redis.io/commands/brpop

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

缺点:无论发布什么,CustomerUpdate都需要更改,并且可能需要多个LPUSHs,可能需要MULTI/EXEC或类似。如果您无法更改此方面,则需要其他流程(不同的客户端)来订阅CustomerUpdates,并推送作业。

答案 3 :(得分:0)

一种简单的方法,而不是在消息中发送事件数据,发送包含此类数据的列表的名称,然后消息的第一个接收者将在此列表上执行LPOP并且只有它会收到事件数据。

简而言之:

  • 您的客户订阅SUBSCRIBE CustomerUpdate
  • 发布商执行RPUSH CustomerUpdateList <data>; PUBLISH CustomerUpdate CustomerUpdateList
  • 所有客户端都会获得MESSAGE CustomerUpdate CustomerUpdateList,但只有第一个LPOP CustomerUpdateList才会收到<data>消息。

但是,从您在服务器中执行LPOP的那一刻起,邮件将被处理或将永久丢失。例如,如果连接在LPOP之后立即丢失,则消息将丢失。

在Redis中实施可靠的消息传递很难,因此您可以更好地了解以下项目:https://github.com/resque/resquehttps://github.com/seomoz/qless

或者如果你想自己做,请看一下这个作者对他们遵循的方法做出了很好解释的演示文稿:https://www.percona.com/news-and-events/percona-university-smart-data-raleigh/using-redis-reliable-work-queue

PS:虽然我的建议是为了这类东西得到像RabbitMQ这样的东西。