我正在使用Spring Integration,Websocket和RabbitMQ服务器开发一个演示聊天应用程序。当我在单个服务器上执行应用程序时,它工作正常。
制作人发送的所有消息都由消费者接收。但是,当我在集群环境中运行它时,消息会在服务器上随机接收,而不是所有服务器都会收到。
我不知道我的代码是否有任何问题,或者是导致它的配置。
我试图通过记录器检查它。 Logger向我显示消息已成功发送,但并未由所有服务器接收,而是仅由一台服务器接收。
以下是我正在使用的类以及配置。
ChatController.java
@Controller
public class ChatController {
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping(value = "/", method = RequestMethod.GET)
public String viewApplication() {
return "index";
}
@Autowired
private AmqpTemplate reviewTemplate;
@MessageMapping(value = "/random")
public void sendDataUpdates(OutputMessage message) {
try {
System.out.println("<<<<<<< Sending Message <<<<<<<<<<" + message.getMessage() + " ID : " + message.getId());
sendMessages(message);
} catch (Exception ex) {
System.out.println("Exception ------>>>>>> " + ex);
}
}
private void sendMessages(OutputMessage msg) {
reviewTemplate.convertAndSend(msg);
}
}
RandomDataGenerator.java
@Component
public class RandomDataGenerator implements
ApplicationListener<BrokerAvailabilityEvent> {
private final MessageSendingOperations<String> messagingTemplate;
@Autowired
public RandomDataGenerator(
final MessageSendingOperations<String> messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@Override
public void onApplicationEvent(final BrokerAvailabilityEvent event) {
}
public void onMessage(GenericMessage<?> msg) {
try {
System.out.println("Message ====== >>>>> " + msg);
OutputMessage message = (OutputMessage) msg.getPayload();
this.messagingTemplate.convertAndSend(
"/data", message);
System.out.println("Message ====== >>>>> " + message.getMessage());
} catch (Exception ex) {
System.out.println("==================== " + ex);
}
finally {
}
}
}
web应用-config.xml中
<rabbit:annotation-driven />
<rabbit:admin id="rabbitAdmin" connection-factory="rabbitConnectionFactory" auto-startup="true" />
<rabbit:connection-factory id="rabbitConnectionFactory"
connection-timeout="5000" publisher-returns="true"
channel-cache-size="32" cache-mode="CHANNEL"
host="localhost" username="guest" password="guest" port="5672"
publisher-confirms="true" requested-heartbeat="5000" />
<rabbit:fanout-exchange name="reviewExchange" id="reviewExchange" durable="true">
<rabbit:bindings>
<rabbit:binding queue="reviewQueue"></rabbit:binding>
</rabbit:bindings>
</rabbit:fanout-exchange>
<rabbit:direct-exchange name="directExchange" id="directExchange" durable="true" />
<rabbit:template id="reviewTemplate" connection-factory="rabbitConnectionFactory"
encoding="UTF-8" exchange="reviewExchange" queue="reviewQueue"
routing-key="reviewKey" />
<rabbit:queue id="reviewQueue" name="reviewQueue" durable="true" />
<bean id="customMessageListener" class="de.kimrudolph.tutorials.utils.RandomDataGenerator" />
<int:publish-subscribe-channel id="reviewPubSubChannel" />
<amqp:outbound-channel-adapter channel="reviewPubSubChannel"
amqp-template="reviewTemplate" exchange-name="reviewExchange"/>
<int:channel id="reviewInboundChannel" />
<amqp:inbound-channel-adapter channel="reviewInboundChannel" queue-names="reviewQueue" connection-factory="rabbitConnectionFactory" />
<int:service-activator input-channel="reviewInboundChannel" id="reviewQueueServiceActivator" ref="customMessageListener" method="onMessage" />
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/random">
<websocket:sockjs />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/data" />
<websocket:client-inbound-channel>
<websocket:executor core-pool-size="200" keep-alive-seconds="300" max-pool-size="1000" queue-capacity="5000" />
</websocket:client-inbound-channel>
<websocket:client-outbound-channel>
<websocket:executor core-pool-size="200" keep-alive-seconds="300" max-pool-size="1000" queue-capacity="5000" />
</websocket:client-outbound-channel>
</websocket:message-broker>
代理服务器配置
worker.list=loadbalancer,status
worker.tomcat1.port=8003
worker.tomcat1.host=localhost
worker.tomcat1.type=ajp13
worker.tomcat2.port=8008
worker.tomcat2.host=localhost
worker.tomcat2.type=ajp13
worker.tomcat3.port=8013
worker.tomcat3.host=localhost
worker.tomcat3.type=ajp13
worker.tomcat1.lbfactor=1
worker.tomcat2.lbfactor=1
worker.tomcat3.lbfactor=1
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2,tomcat3
worker.loadbalancer.sticky_session=1
worker.status.type=status
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel error
JkMount /spring-mvc-websockets-master loadbalancer
JkMount /spring-mvc-websockets-master/* loadbalancer
JkMount /SpringChatExample loadbalancer
JkMount /SpringChatExample/* loadbalancer
下面是示例应用程序的链接,您可以测试并尝试导致问题的原因:
答案 0 :(得分:1)
这是正确的,因为只有单个消费者才能收到来自queue
的消息由于您的所有接收器应用程序都配置了相同的queue
,因此您的代理在binding
上只有一个fanout-exchange
。
为了实现这一点,当您为AnonymousQueue
定义提供id
时,可以继续使用<rabbit:queue>
。在这种情况下,您的fanout-exchange
将拥有与您拥有的群集成员一样多的绑定。
AnonymousQueue
具有auto-delete
优势。这意味着当您的集群成员停止队列并且其绑定将被删除时。
在这种情况下,您应该使用SpEL来配置queue-names
:
或生成随机queue name
并使用auto-delete="true"
:
<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost"/>
<rabbit:queue id="settingsReplyQueue" name="#inetAddress.toString()}"
auto-delete="true"/>
同样的SpEL钩子也适用于queue-names
。