一、现象
生产环境中,企微告警以下错误:
Channel shutdown: channel error; protocol method: #
method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED -
delivery acknowledgement on channel 4 timed out. Timeout value used: 1800000 ms.
This timeout value can be configured, see consumers doc guide to learn more,
class-id=0, method-id=0)
光看报警信息,应该是消费者消费方法时间过久,长时间没有进行 ack导致的超时。后面又陆续的报了几次警,在排查的时候,惊讶的发现了一个队列 XXX居然没有消费者了!
这就导致了此队列的消息积压,无法被消费!
原先此队列是存在 4个消费,出现 4次告警后,消费者全部被下掉了。
这是因为 RabbitMQ中的任务取出并执行,为防止任务执行期间出错,设置NO_ACK=FALSE标志,这样、一旦任务没有应答的话,相应的任务就会被RabbitMQ自动Re-Queue,避免丢失任务。然而、由于任务执行时间较长,通常需要五、六分钟,甚至更长;一旦一个任务被取出执行,该任务就从Ready状态更改成Unacked状态。
当这个任务执行完之后,程序将向RabbitMQ发送ACK消息确认,RabbitMQ在收到ACK消息后,会将该任务移出队列;然而、问题出在任务尚未执行完毕【执行时间太久】,RabbitMQ再等了一段时间【大约两三分钟】后,一直没有收到ACK确认消息,就将该任务自动Re-Queue了【点对点模式 也就是一发一接的模式,不适用发布/订阅这种广播模式】,也就是说、我们这里发生了死循环【任务永远也执行不完,因为会一直Re-Queue】。
MQ自动Reueue, 而消费者这边还在处理数据也就是说没有回复ACK. 心跳检测设置默认值60s, 当在两次错过的心跳之后,对等方被视为无法访问. 就会主动与消费者断开连接。
不建议去调整 ack超时参数 consumer_timeout,而是要想着从业务层面去优化,提升消费的性能,防止 ack超时!