之前我们给我们的系统加了一个使用SpringAOP+RabbitMQ+WebSocket进行实时消息通知功能(https://www.cnblogs.com/little-sheep/p/9934887.html)。在测试环境下没有问题,但上到生产环境后部分用户反映出现了丢消息的情况,针对这个问题我们进行了排查,发现,原本我们的系统是单机的,但用户在之前做了调整,在内外网服务器分别部署了系统,两个服务器都公用一个RabbitMQ。那么问题就来了。
之前生产者向Exchange生产消息,消费者从queue消费消息使用的是direct模式,通过routing-key保证生产的消息只有指定的消费者可消费。但当两台服务器共用一个MQ时即有了两个消费者连接同一个queue,此时rabbitmq并不是一个消息两个消费者都能消费,而是采用默认的轮询发送方式,A服务器收到消息1、3、5 。。。而B服务器收到2、4、6 。。。
这就出现了用户感觉的丢消息现象。所以我们考虑将通知改为广播形式即fanout。
RabbitMQ将消息中间件的实现分成了Exchange+Queue的形式,Exchange和Queue使用Binding;生产者向Exchange生产消息,消息根据指定的binding进入Queue,消费者从Queue取消息。Fanout模式如图:
一个消费者会对应一个queue,那么多个消费者要有多个queue。
修改后代码如下:
RabbitMQConfig.java
//声明exchange Connection connection = factory.createConnection(); Channel channel = connection.createChannel(false); //生产环境中有多个server,每个server都是一个消费者,对同一个消息都要进行处理。选用广播模式 channel.exchangeDeclare("exchange.websocket.msg", BuiltinExchangeType.FANOUT);