在我们的架构中,我们有一个Redis服务器,用于缓存和发布事件。
我的问题如下
是否有任何模式可确保应用程序的每个实例都不更新数据库?
答案 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]);
优点:
答案 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/resque或https://github.com/seomoz/qless
或者如果你想自己做,请看一下这个作者对他们遵循的方法做出了很好解释的演示文稿:https://www.percona.com/news-and-events/percona-university-smart-data-raleigh/using-redis-reliable-work-queue
PS:虽然我的建议是为了这类东西得到像RabbitMQ这样的东西。