rabbitmq内置了插件。shovel和shovel_management,不需要再下载插件,只需要开启就行了。
在界面查看死信。
创建pro和consumer、配置、开启死信。
测试重试次数超过阈值的message是否进入dead queue。
如何把dead queue中的message重新加回正常的队列。
是dlq.
@enablebinding不是一定要放在consumer类上面哦,放在启动类上也行。放在其它的类上也会生效哦。
dlq的防伪标志,dlq-are you ok?
为什么在死信的listener中要将atomicInteger清0?
若消息正常消费,atomic设置为0。无论消息是否正常消费,aiomic都不会重置,而是不断递增。这对死信的实现有什么作用呢?
如果消息正常消费。
如果消费消息抛出异常。该消息会一直重试直至消息正常消费,也可以一直重试直到超过重试阈值,将消息添加到死信(不加入死信会一直循环往复的消费)。
aiomic的初始值是1,不是0,0%3 == 0
单机和联机的区别:单机,consumer throw a exception之后,message是不会入队的。不过可以设置retry的次数,这样的话,首次消费失败是不会抛出异常的,consumer会重新消费message,当消费的次数超过retry的次数时,才会抛出异常并停止运行。
retry(attemp)对应单机(当前cosumer消费),requeue对应联机,消费异常的message可以被其它节点的consumer消费,因为消息重新入队了。
auto-bind-dlq:项目初始化的时候,stream会在rabbitmq中添加一个死信队列,死信的名字是topic. dlq。
dlq-topic.dlq-group 是队列名称。 dlx和dlk代表这个队列可以往死信队列添加消息。
topicName.groupName,在界面中代表的就是队列的名称。dlq-topic.dlq-group就是队列名称,同时这个队列因为feature中有dlx和dlk,说明这个队列可以往死信队列发送message。
topicName.groupName.dlq代表死信队列,只有在配置中开启了auto-bind-dlq才会有。
两发标签,dlk和dlx,代表这个队列可以玩dlq转发message。配置项出错或者插件没有开启会导致没有标签。
retry=2,第一次消费出现异常,没关系,还有一次,第二次消费,没有异常,正常消费,故该消息不会转发到dlq,也就是说,在重试范围内,消息正常消费,是不会转发到dlq的。如果没有配置dlq,次数用完,还是没有正常消费,那就会停止哦。
ready代表没有被消费的message的次数。
move message 选择destination,消息会被转发到指定队列。该功能的前提是开启shovel插件。
如何找到正确的queue?名字就是按照topicName.groupName来找哦。
retry = 2,
atomic =1,过。retry所致
atomic = 2,throw exception,此时消息转发到dlq。
此时,将dlq的消息转发到原队列。
atomic = 3,过。余数为0所致。
就这样,结合重试、转发到dlq,转发到原队列的功能就实现了。
retry=2代表message最多会被消费两次,消费第二次的时候会抛出异常,第一次就算出现异常也不会抛而是继续消费。
atomic初始为1,调用一次get,就会increment一次。incrementAndGet()。
开始atomic = 1,尝试消费1次(retry-1 == 1),
第二次消费,ayomic == 2,余数为2,所以抛出异常。
第三次调用接口,atomic已经是3了(前面调用了就会自增。)
第二次调用接口的时候,居然两次消费都走的是异常的逻辑。
第三次实例逻辑流程说明:
atomic的初始值是1,incrementAndget是先自增再获取值。
第一次调用接口:
retry = 1,
atomic == 2,余数为2,消息消费失败,再来一次。
atomic == 3,余数为0,消息消费成功,结束。
第二次调用接口。
atomic == 4.余数为1,消息消费失败,再来一次。
atomic == 5,余数为2,消息消费失败,抛出异常,调用结束。此时消息被转发到dlq。
此时,在界面将消息转发到原队列。
atomic == 6,余数为0,消费成功,结束。
除了自动生成dlq,还可以指定某个队列为死信,或者指定routie key(路由key),都是可以实现的。
不是所有的中间件有死信。如果要用dlq,认准dlq哦。