概述
之前我们折腾了RabbitMQ的搭建,RabbitMQ的集群。所以,很快我就在公司封装好并推广了消息队列的使用。我们因为仅使用发布订阅和点对点的模型,所以很简单而单纯,就用起来了,但是,我们很快发现了一个问题。因为刚开始,我没有配置日志,启动的时候直接用nohup启动的,日志直接看默认的文本。然后,我们的消费服务是有问题的,而我为了消息不丢失,设置了消息总是会重新投入到队列里,然后,因为一些bug,消息一直处理失败,于是很快日志就塞满了磁盘。虽然后来我配了日志的大小磁盘不会满了,但是,这个问题还是会很影响使用的。为了解决这个问题,我们提出了死信队列。
死信队列是什么
其实,在rabbitMQ中,叫死信交换器。我们需要一个队列订阅这个交换器来消费过来的消息,这个队列,叫做死信队列。
怎么用死信队列
其实,死信交换器就是一个普通的交换器,它具备交换器的一切特征,没任何特殊的地方。我们需要在定义队列的时候指定队列的死信交换器,如下:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "some.exchange.name");
channel.queueDeclare("myqueue", false, false, false, args);
那么,在消息死亡的时候,就会自动路由到这个交换器了。那么,消息什么时候会死亡呢?以下三种情况:
- 消息被拒绝(basic.reject/ basic.nack)并且requeue=false
- 消息TTL过期
- 队列达到最大长度
其中,最后一种情况我没有测试。第一种情况和第二种情况我测试了。是没有问题的。其实,到此,死信队列就搞定了,但是,我还趟了一个大坑,下面介绍。
交换器路由
什么坑呢?我开始的时候把交换器的类型设置成了direct,routingKey设置成了空字符串,然后,死活收不到消息。后来,我把direct改成了fanout,就收到了。至此,我确定了交换器就是普通的交换器,我的死信队列也是对的。
交换器路由规则如下:
- direct:只会路由到routingKey相同的队列中,如果有两个相同的,则复制分发。
- fanout:无视routingKey,分发到所有的订阅者中,这也是为什么改了之后就收到消息了。
- topic:根据表达式来路由routingKey,*表示任意一个字母,#表示任意多个字母。
- header:这个我们就不介绍了,根据官方说法,这个性能很低,而且可以用其它的来实现,所以总是不应该使用。
demo
请参考https://gitee.com/naturetrible/ntbrick.demo 中的rabbitmq-dlx项目
参考
- https://blog.youkuaiyun.com/qq_29778131/article/details/52536965
- https://blog.youkuaiyun.com/u013256816/article/details/54933065
- https://www.cnblogs.com/haoxinyue/archive/2012/09/28/2707041.html