【Spring Boot】 MQ消息确认 🔥

1,257 阅读3分钟

消息的确认类型

1)channel.basicAck(deliveryTag, multiple);

consumer处理成功后,通知broker删除队列中的消息,如果设置multiple=true,表示支持批量确认机制以减少网络流量。

例如:有值为5,6,7,8 deliveryTag的投递

  • 如果此时channel.basicAck(8, true);则表示前面未确认的5,6,7投递也一起确认处理完毕。
  • 如果此时channel.basicAck(8, false);则仅表示deliveryTag=8的消息已经成功处理。

2)channel.basicNack(deliveryTag, multiple, requeue);

consumer处理失败后,例如:有值为5,6,7,8 deliveryTag的投递。

  • 如果channel.basicNack(8, true, true);表示deliveryTag=8之前未确认的消息都处理失败且将这些消息重新放回队列中。
  • 如果channel.basicNack(8, true, false);表示deliveryTag=8之前未确认的消息都处理失败且将这些消息直接丢弃。
  • 如果channel.basicNack(8, false, true);表示deliveryTag=8的消息处理失败且将该消息重新放回队列。
  • 如果channel.basicNack(8, false, false);表示deliveryTag=8的消息处理失败且将该消息直接丢弃。

3)channel.basicReject(deliveryTag, requeue);

相比channel.basicNack,除了没有multiple批量确认机制之外,其他语义完全一样。

  • 如果channel.basicReject(8, true);表示deliveryTag=8的消息处理失败且将该消息重新放回队列。
  • 如果channel.basicReject(8, false);表示deliveryTag=8的消息处理失败且将该消息直接丢弃。

易发问题

  1. 没有及时ack,或者程序出现bug,所有的消息将被存在unacked中,消耗内存
  2. 忘记了ack,后果很严重。当Consumer退出时,Message会重新分发消费。然后RabbitMQ会占用越来越多的内存,由于RabbitMQ会长时间运行,因此这个“内存泄漏”是致命的。
  3. 如果使用BasicNack,将消费失败的消息重新塞进队列的头部,则会造成死循环。

规矩

  1. 在消费者端一定要进行ack,或者是nack,可以放在try方法块的finally中执行。
  2. 可以对消费者的异常状态进行捕捉,根据异常类型选择ack,或者nack抛弃消息,nack再次尝试。
  3. 对于nack的再次尝试,是进入到队列头的。如果一直是失败的状态,将会造成阻塞。所以最好是专门投递到“死信队列”,
  4. 解决nack造成的消息循环循环消费,请为队列设置“回退队列”,设置回退队列和阀值,如设置队列为q1,阀值为2,则在rollback两次后将消息转入q1。
  5. 解决nack造成的消息循环循环消费,如处理失败无影响的话可以直接丢弃。

死信队列

进入死信队列的情况

  1. 消息被(basic.reject() or basic.nack()) and requeue = false,即消息被消费者拒绝签收,并且重新入队为false
  2. 消费者设置了自动ACK,当重复投递次数达到了设置的最大retry次数之后,消息也会投递到死信队列,但是内部的原理还是调用了nack/reject
  3. 消息过期,过了TTL存活时间。
  4. 队列设置了x-max-length最大消息数量且当前队列中的消息已经达到了这个数量,再次投递,消息将被挤掉,被挤掉的是最靠近被消费那一端的消息。

流程

  1. 有一个(n个)正常业务的Exchange,比如为user-exchange
  2. 有一个(n个)正常业务的Queue,比如为user-queue。(因为该队列需要绑定死信交换机,所以需要加俩参数:死信交换机:x-dead-letter-exchange,死信消息路由键:x-dead-letter-routing-key
  3. 进行正常业务的交换机和队列绑定。
  4. 定义一个死信交换机,比如为common-dead-letter-exchange
  5. 将正常业务的队列绑定到死信交换机(队列设置了x-dead-letter-exchange即会自动绑定)。
  6. 定义死信队列user-dead-letter-queue用于接收死信消息,绑定死信交换机。

自己画的图,极丑

PS:自己画的图,极丑