交换机模式
- fanout
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。 - direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。 - topic
前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但是key可以用模糊匹配。
死信队列
当消费者消费消息的时候,程序服务报错。有如下解决方式:
- 重试机制
在yml中配置重试次数,如果达到次数上限mq会删除该消息
rabbitmq:
host: 121.36.44.93
port: 5672
username: admin
password: admin
listener:
type: simple
simple:
retry:
max-attempts: 5
enabled: true
- 手动捕获异常,自动ack
- 手动捕获异常,手动ack,消息投递到死信队列
普通业务队列,绑定死信交换机
@Bean
public Queue systemQueue() {
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
args.put("x-dead-letter-exchange", BizEnum.Message.DLX_EXCHANGE.getType());
// x-dead-letter-routing-key 这里声明当前队列的死信路由key
args.put("x-dead-letter-routing-key", "deadLetter.system");
return QueueBuilder.durable(BizEnum.Message.SYSTEM_QUEUE.getType()).withArguments(args).build();
}
死信队列
@Bean
public Queue deadLetterQueue() {
return new Queue(BizEnum.Message.DLX_QUEUE.getType(), true, false, false, null);
}
死信交换机
@Bean
TopicExchange deadLetterExchange() {
return new TopicExchange(BizEnum.Message.DLX_EXCHANGE.getType(), true, false, null);
}
yml配置手动ack
spring:
rabbitmq:
host: 121.36.44.93
port: 5672
username: admin
password: admin
listener:
type: simple
simple:
default-requeue-rejected: false
acknowledge-mode: manual
业务队列监听
@RabbitListener(queues = {
"system-queue-ystc2"})
public void ystc(Message message, com.rabbitmq.client.Channel channel) throws IOException {
String msg = new String(message.getBody());
log.info("收到业务消息A:{}", msg);
boolean ack = false;
if (!ack) {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
} else {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
死信队列监听,可以将错误数据入库,或者不ack,后期再消费该队列数据
@RabbitListener(queues = {
"dlx-queue-ystc"})
@Transactional(rollbackFor = Exception.class)
public void dlMessage(Message message, Channel channel) throws IOException {
String msg = new String(message.getBody());
// 入库或者直接不ack
// channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}