本文章主要介绍RabbitMQ的队列不能接收生产者发送过来的消息的几种场景:

1.rabbitmq上面堆积的没有ack的消息太多,导致超过了max-length的限制
2.rabbitmq上面的内存超过了限制,触发了流量控制
3.rabbitmq上面触发了太多的I/O磁盘操作,导致rabbitmq不能及时响应

场景 1: rabbitmq上面的消息堆积太多

对于rabbitmq的queue来说,是可以设置下面三个参数的,x-max-length,x-max-length-bytes, x-overflow。一旦x-max-length(这里是设置的queue最大容纳的消息数量),x-max-length-bytes(这里是queue中的消息数量与消息大小乘积的总量)超过了限制之后,就会根据x-overflow里面设置的模式开始处理,对于x-overflow有一个reject-publish模式,打开之后,生产者通过confrim生产的消息,在rabbitmq就会被拒绝,回复message unacked.

这几个参数的解释说明:

java rabbitmq 动态监听 rabbitmq 监听收不到消息_java

备注:这几个参数是可选的,默认不会被设置,默认值的话,这几个值是取决于rabbitmq这个机器的cpu,内存等的配置。


例子

java rabbitmq 动态监听 rabbitmq 监听收不到消息_java rabbitmq 动态监听_02

场景2: rabbitmq上面的内存超过了限制,触发流量控制,导致的失败

这个对应的是另外两个参数,vm_memory_high_watermark 和vm_memory_limit与流量控制相关的内存参数。

RabbitMQ会在启动和执行命令rabbitmqctl set_vm_memory_high_watermark 百分比的时候检测系统所安装的内存总量。默认情况,当RabbitMQ服务器使用超过40%的内存时,它会引起一个内存报警并且阻塞所有连接。一旦内存报警清除后(例如,由于RabbitMQ服务器将消息页交换到磁盘或者分发到客户端时)就会恢复正常服务了。

触发了这个内存超限之后,rabbitmq就会启动流量控制,对于流量控制,下面是三种不同的设置方法:


1.如果你在引起内存报警的时候尝试发送消息,在进行发送期间就会被阻塞了。
2.如果你想阻塞所有的发送者,你可以将该参数 vm_memory_high_watermark 设置为0。
3.如果你想禁止基于内存的流量控制,你可以将该参数vm_memory_high_watermark 设置为100。

流量控制介绍:

当达到内存阀值的时候(无论设置的是百分比,还是绝对值),RabbitMQ就会触发流量控制。即publishers会全部阻塞,直到解除报警才会恢复正常的publishers服务。触发了的流量控制之后,在rabbitmq的UI界面,可以看下面的这个指标:

java rabbitmq 动态监听 rabbitmq 监听收不到消息_nginx_03

备注:这个流量控制,只是对AMQP生效的,对HTPP协议发送的消息并不会进行流量控制。

对于流量控制的详细介绍可参考下面两篇文章:     

1.https://www.rabbitmq.com/blog/2015/10/06/new-credit-flow-settings-on-rabbitmq-3-5-5/
2.https://www.rabbitmq.com/blog/2014/04/14/finding-bottlenecks-with-rabbitmq-3-3/

场景3: rabbitmq上面触发了太多的I/O磁盘操作,导致rabbitmq不能及时响应

这个场景实际上有两种情况:1、一种是publisher采用confrim机制的时候,设置了mode为永久化(persistent)。

这种场景的时候,publisher接收到rabbitmq的ack必须是在rabbitmq写完硬盘之后,才将ack消息返回。一旦rabbitmq上面写硬盘的速度太慢,就会导致ack的返回超时,进而会导致publisher发送message到rabbitmq批量失败。

这种问题的定位办法比较简单,登录到rabbitmq的那台机器上面,查看对应的磁盘I/O的读写情况就可以了,一旦超过限制,跟它的关系就很大。

而针对这个场景的解决办法,其实没有太多办法,一个是增加磁盘的读写速度,换更高级的磁盘,一个是想办法把生产的消息从业务层面来减少消息生产速度。

2.另一种场景是rabbitmq上面堆积的消息过多,而queue的设置里面恰好设置了durable设置为true,也就是持久化队列到磁盘。

在rabbitmq上面的消息堆积过多的时候,内存不足的时候就会引起消息换出到磁盘,而频繁的写磁盘,会导致rabbitmq的服务变得很慢,进而会影响publisher的ack响应。

解决办法通常是下面三种:

1.进行流量控制。
2.增加prefetch的值,即一次发送多个消息给接收者,加快消息被消费掉的速度。
2.采用multiple ack,降低处理ack带来的开销。

参考资料:


欢迎关注公众号:灰子学技术

java rabbitmq 动态监听 rabbitmq 监听收不到消息_网络_04