学生在校表现评语rabbitmq之消息应答,⼿动应答与⾃动应答
什么是消息应答
消费者完成⼀个任务可能需要⼀段时间,如果其中⼀个消费者处理⼀个长的任务并仅只完成了部分突然它挂掉了,会发⽣什么情况。RabbitMQ ⼀旦向消费者传递了⼀条消息,便⽴即将该消息标记为删除。在这种情况下,突然有个消费者挂掉了,我们将丢失正在处理的消息。以及后续发送给该消费这的消息,因为它⽆法接收到。为了保证消息在发送过程中不丢失,rabbitmq 引⼊消息应答机制,消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了。
消费者收到的每⼀条消息都必须进⾏确认。消息确认后,RabbitMQ才会从队列删除这条消息,RabbitMQ不会为未确认的消息设置超时时间,它判断此消息是否需要重新投递给消费者的唯⼀依据是消费该消息的消费者连接是否已经断开。这么设计的原因是RabbitMQ允许消费者消费⼀条消息的时间可以很久很久。
消息应答⽅式
RabbitMQ中消息的应答,共有两种⽅式:
⾃动应答
⼿动应答
⾃动应答
小孩子经常流鼻血是怎么回事
消费者在消费消息时,可以指定autoAck参数,当autoAck=true时,⼀旦消费者接收到了消息,就视为⾃动应答了消息。
RabbitMQ中声明消费者处理业务逻辑之前⾃动确认就已经完成了(推送Consume、消息拉取Ge都是如此),可由下⾯代码进⾏测试,如下:
上述代码我们采⽤了⾃动确认,并且在业务处理的最后⼿动抛出异常( 模拟出错 ),然后我们进⾏测试,发现重启消费者后不会再收到消息( 本来是应该再次接收到的,因为我们模拟出错了,这条消息应该算是消费失败的 ),说明该消息已经被消费者消费掉并确认了,RabbitMQ已经将其移除了,我们模拟出错了但是消息仍然被移除了 , 可以理解为消息丢失了 , ⾃动确认优点是快 , 缺点是有丢失消息的风险
⼿动应答
⼿动应答分为三种情况:
(1) ⼿动不确认
channel.basicNack(deliveryTag, fal, true);
澄字怎么读 basic.nack⽅法为不确认deliveryTag对应的消息,第⼆个参数是否应⽤于多消息(这个参数不细讲了 ,不建议使⽤ , 有丢失消息风险),第三个参数是否requeue,与ject区别就是同时⽀持多个消息,可以nack该消费者先前接收未ack的所有消息。nack后的消息也会被⾃⼰消费到。
(2) ⼿动拒绝张盛是什么电视剧
channel.basicReject(deliveryTag, true);
素颜美女照片
ject⽅法拒绝deliveryTag对应的消息,第⼆个参数是否requeue,true则重新⼊队列,否则丢弃或者进⼊死信队列。
该⽅法reject后,该消费者还是会消费到该条被reject的消息。
(3) ⼿动确认应答
从⼿动应答的介绍,我们发现在⾃动确认机制,如果消费者在处理消息的过程中,出了错,就没有什么办法重新处理这条消息,所以我们很多
时候,需要在消息处理成功后,再确认消息,这就需要⼿动确认。
当autoAck=fal时,RabbitMQ会等待消费者⼿动发回ack信号后 , 才从内存(和磁盘,如果是持久化消息的话)中移除消息。
采⽤消息确认机制后,只要令autoAck=fal,消费者就有⾜够的时间处理消息(任务),不⽤担⼼处理消息过程中消费者进程挂掉后消息丢失的问题,因为RabbitMQ会⼀直持有消息直到消费者⼿动调⽤channel.basicAck为⽌。
当autoAck=fal时,对于RabbitMQ服务器端⽽⾔,如果服务器端⼀直没有收到消费者的ack信号,
并且消费此消息的消费者已经断开连接,则服务器端会安排该消息重新进⼊队列,等待投递给下⼀个消费者(也可能还是原来的那个消费者)。
这⾥我们启动了⼿动确认后,就必须调⽤channel.basicAck⽅法进⾏确认,否则的话RabbitMQ会⼀直进⾏等待,当我们这个消费者关闭
后,RabbitMQ会将该条消息再发给对应的消费者进⾏消费,直到有消费者对该条消息进⾏消费并应答完成。
看到上述对消息的处理后,我们还发现⼀个问题,如果channel.basicAck收到确认前的代码有问题,会抛出异常⽆法进⾏⼿动确认怎么办,⼀般消费者也不会连接中断,那么该消息就⼀直⽆法被处理,连被其他消费者处理的机会都没有
我和书的故事
所以⼀般我们会进⾏try-catch处理,处理成功则⼿动确认,失败或有异常则拒绝。
下⾯是我觉得需要补充的⼏点:
1)上⾯的例⼦中有⼀点 ,我觉得⾮常重要 .
客服管家 "在⼿动应答的情况下 , 如果channel.basicAck收到确认前的代码有问题,会抛出异常,导致⽆法进
⾏⼿动确认,⼀般消费者也不会连接中断,那么该消息就⼀直⽆法被处理,连被其他消费者处理的机会都没有,所以⼀般我们会进⾏try-catch处理,处理成功则⼿动确认,失败或有异常则拒绝。"
这点我⾃⼰写了例⼦验证过的,确实是这样, 所以⼀定要进⾏try-catch处理 ,不然这个消费者就会卡住不动 ,神马操作都不做 ,也不会往后继续消费别的消息.
2) 我看完博客⼀直有疑问 , 在⼿动应答的情景中 , 如果程序都没有问题 , 但是我就是⼀直不确认 , 会发⽣什么事情,
老爷不要啊 结果就是如下图:
队列还是会被消费, 只是从ready状态转换成了 unacked状态 , ⽽且当前消费者 ,消费完这200个后,不会因为这200个处于unacked状态 , 就重复再把这200个再消费⼀边 , 但是如果重新打开⼀个新的消费者(或者重启当前消费者) , 这个新的消费者会把这200个unacked的再消费⼀遍 , 这个新消费者消费完这200个之后 , 也就停住脚步了 , 等待新的消息进来, 不会⼀遍⼜⼀遍的重复消费这200个
3)
⼿动确认模式,消息⼿动拒绝中如果requeue为true会重新放⼊队列,但是如果消费者在处理过程中⼀直抛出异常,会导致⼊队-》拒绝-》⼊队的循环,该怎么处理呢?
第⼀种⽅法是根据异常类型来选择是否重新放⼊队列。
第⼆种⽅法是先成功确认,然后通过channel.basicPublish()重新发布这个消息。重新发布的消息⽹上说会放到队列后⾯,进⽽不会影响已经进⼊队列的消息处理。
推荐⼀篇关于rabbitmq消息应答的特别有意思的博客