管理 JMS 消息到多个服务器的传递
Manage delivery of JMS messages to multiple servers
我们的应用程序使用 Spring 引导和 JMS 消息与 Tibco。我们有两个生产服务器 运行 并同时处理消息。服务器正在监听同一个 queue。每个服务器有 10 个并发侦听器。我不希望两台服务器同时处理同一条消息。没有什么能阻止我们的 queue 有重复的消息,就像我们可以在 queue 中有消息 A 的两个副本。如果queue中的消息是:A,A,B,C,D,那么如果第一个A被传递到server1,第二个A被传递到server2,并且两个服务器同时处理A,那么它们是创建重复实体的机会。我想找到一种方法将所有 A 消息仅发送到一个服务器。我不能使用 Message Selector b/c 我们在两台服务器上有相同的代码库 运行。这就是我正在考虑的:
根据消息,在 headers 中设置属性。一旦消息被传送到 process() 方法,根据哪个服务器正在处理消息,要么丢弃,简单地 return 消息,要么处理消息并确认它。此解决方案的问题在于,由于我们需要动态找出哪个服务器正在处理消息,因此需要对服务器名称进行硬编码,这意味着如果服务器移动,代码就会中断!
其他可能有效的解决方案是“目标”字段。
https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/jms.html
Destinations, like ConnectionFactories, are JMS administered objects
that can be stored and retrieved in JNDI. When configuring a Spring
application context you can use the JNDI factory class
JndiObjectFactoryBean / to perform dependency
injection on your object’s references to JMS destinations.
这是我以前从未做过的事情。无论如何,配置它选择正确服务器以将消息路由到的目标?意思是,如果 message1 应该传送到 server1,那么它甚至不会传送到 server2 并保留在 queue 中直到 server1 使用它?
还有哪些其他方法可以实现这一点?
编辑:
我仍然不知道将某些消息仅发送到一台服务器进行处理的最佳方式是什么,但是,接受了使用数据库作为验证的响应,b/c这是我们考虑避免创建的处理数据时出现重复实体。
我认为使用 JMS 目标的想法是行不通的,因为 JMS 规范中没有任何内容可以保证目标和代理之间存在任何类型的 link。目的地只是提供者特定 queue/topic 名称的封装。
这里的底线是,您要么需要首先防止重复消息,要么有一些方法来协调消费者在他们被从队列中拉出后处理重复消息。我认为您可以使用数据库等外部系统来完成其中任何一项,例如:
- 生成消息时,请检查数据库中是否有消息已发送的指示。如果没有找到任何指示,则将记录写入数据库(将需要使用主键以防止重复)并发送消息。否则不要发送消息。
- 当使用消息时,检查数据库是否有消息正在(或已经)被使用的指示。如果没有找到任何指示,则将记录写入数据库(将需要使用主键来防止重复)并处理消息。否则只是确认消息而不处理它。
我建议 "post DB sync" 的替代方法。
保持服务器和侦听器不变,并广播所有+关于一个主题的已处理消息。刚刚上线的服务器,可以使用"durable subscribers"不错过任何消息。
如果您广播消息 A、B、C 等的每次处理开始和结束,并考虑添加一点暂停(以毫为单位),您应该避免冲突。这当然是主要风险。
我不清楚是否应该在消息处理的开始或结束时验证重复处理...这取决于您的需要。
如果整个想法不可接受,数据库验证可能是唯一的选择,但正如上面的评论所述,我担心扩展。
我们的应用程序使用 Spring 引导和 JMS 消息与 Tibco。我们有两个生产服务器 运行 并同时处理消息。服务器正在监听同一个 queue。每个服务器有 10 个并发侦听器。我不希望两台服务器同时处理同一条消息。没有什么能阻止我们的 queue 有重复的消息,就像我们可以在 queue 中有消息 A 的两个副本。如果queue中的消息是:A,A,B,C,D,那么如果第一个A被传递到server1,第二个A被传递到server2,并且两个服务器同时处理A,那么它们是创建重复实体的机会。我想找到一种方法将所有 A 消息仅发送到一个服务器。我不能使用 Message Selector b/c 我们在两台服务器上有相同的代码库 运行。这就是我正在考虑的:
根据消息,在 headers 中设置属性。一旦消息被传送到 process() 方法,根据哪个服务器正在处理消息,要么丢弃,简单地 return 消息,要么处理消息并确认它。此解决方案的问题在于,由于我们需要动态找出哪个服务器正在处理消息,因此需要对服务器名称进行硬编码,这意味着如果服务器移动,代码就会中断!
其他可能有效的解决方案是“目标”字段。
https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/jms.html
Destinations, like ConnectionFactories, are JMS administered objects that can be stored and retrieved in JNDI. When configuring a Spring application context you can use the JNDI factory class JndiObjectFactoryBean / to perform dependency injection on your object’s references to JMS destinations.
这是我以前从未做过的事情。无论如何,配置它选择正确服务器以将消息路由到的目标?意思是,如果 message1 应该传送到 server1,那么它甚至不会传送到 server2 并保留在 queue 中直到 server1 使用它?
还有哪些其他方法可以实现这一点?
编辑:
我仍然不知道将某些消息仅发送到一台服务器进行处理的最佳方式是什么,但是,接受了使用数据库作为验证的响应,b/c这是我们考虑避免创建的处理数据时出现重复实体。
我认为使用 JMS 目标的想法是行不通的,因为 JMS 规范中没有任何内容可以保证目标和代理之间存在任何类型的 link。目的地只是提供者特定 queue/topic 名称的封装。
这里的底线是,您要么需要首先防止重复消息,要么有一些方法来协调消费者在他们被从队列中拉出后处理重复消息。我认为您可以使用数据库等外部系统来完成其中任何一项,例如:
- 生成消息时,请检查数据库中是否有消息已发送的指示。如果没有找到任何指示,则将记录写入数据库(将需要使用主键以防止重复)并发送消息。否则不要发送消息。
- 当使用消息时,检查数据库是否有消息正在(或已经)被使用的指示。如果没有找到任何指示,则将记录写入数据库(将需要使用主键来防止重复)并处理消息。否则只是确认消息而不处理它。
我建议 "post DB sync" 的替代方法。
保持服务器和侦听器不变,并广播所有+关于一个主题的已处理消息。刚刚上线的服务器,可以使用"durable subscribers"不错过任何消息。
如果您广播消息 A、B、C 等的每次处理开始和结束,并考虑添加一点暂停(以毫为单位),您应该避免冲突。这当然是主要风险。
我不清楚是否应该在消息处理的开始或结束时验证重复处理...这取决于您的需要。
如果整个想法不可接受,数据库验证可能是唯一的选择,但正如上面的评论所述,我担心扩展。