为什么要流控?
流控主要是为了防止生产者生产消息速度过快,超过 Broker 可以处理的速度。这时需要暂时限制生产者的生产速度,让 Broker 的处理能够跟上生产速度。
当RabbitMQ发布消息速度快于消费速度或者系统资源不足时,RabbitMQ将降低或阻断发布消息速度,以免服务器资源饱满而宕机,可以通过rabbitmqctl和web管理页面查看连接的状态为flow,当服务器资源不足时,连接会被blocked。连接被流控后和正常使用没有什么区别,体现可网络带宽不足情况一样。这个流控不需要配置RabbitMQ默认处理流控。
Erlang进程之间不共享内存,每个进程都有自己的进程邮箱,进程间只通过消息来通信。Erlang没有对进程邮箱的大小进行限制,所以当有大量消息持续发往某个进程时,会导致该进程邮箱过大,最终内存溢出并崩溃。如果没有流控,可能会导致内部进程邮箱的大小很快达到内存阈值。
流控情况
1.内存控制
RabbitMQ会在启动时检测机器的物理内存数值。根据vm_memory_high_watermark
参数指定的百分比,进行控制。
默认参数vm_memory_high_watermark
的值为0.4,,当RabbitMQ使用的内存超过40%时,系统会阻塞所有连接。一旦警报解除(消息被消费者取走,或者消息被写到硬盘中),系统重新恢复工作。
可修改配置文件或通过命令 rabbitmqctl set_vm_memory_high_watermark fraction
动态配置。
root@sunday:~# rabbitmqctl environment | grep vm_memory_high_watermark
{vm_memory_high_watermark,0.4},
{vm_memory_high_watermark_paging_ratio,0.5}]},
可通过下列命令动态设置
rabbitmqctl set_vm_memory_high_watermark 0.3
查看内存报警日志
在日志中可以找到内存限制的相关信息 例如 :/var/log/rabbitmq/
=INFO REPORT==== 28-Apr-2015::14:11:16 ===
Memory limit set to 3804MB of 7609MB total.12345
当vm_memory_high_watermark为0时,不再有内存警报。并且所有的消息发布都将停止。这个方法可用来,如果要禁止消息发布的情况。
2.硬盘控制
当RabbitMQ的磁盘空闲空间小于50M(默认),生产者将被BLOCK,并且阻塞信息发布前,会尝试把内存中的信息输出到磁盘上。持久化信息和非持久化信息都将被写到磁盘(持 久化信息一进入队列就会被写到磁盘)。
如果采用集群模式,磁盘节点空闲空间小于50M将导致其他节点的生产者都被block。
可以通过disk_free_limit
来对进行配置。
如果磁盘的预设值为50%,内存预设值默认是0.4,那么就是当内存使用量达到20%时,队列信息会被写到磁盘上。
可以通过设置 vm_memory_high_watermark_paging_ratio 0.5
(默认值为0.5)来改变写入磁盘的策略,
root@sunday:~# rabbitmqctl eval 'application:get_all_env(rabbit).' | grep vm_memory_high_watermark_paging_
{vm_memory_high_watermark_paging_ratio,0.5},
建议vm_memory_high_watermark
不超过50%
不建议修改rabbitmqctl set_vm_memory_high_watermark 数值
3.消息积压
在RabbitMQ中,消息可能被存储在多个不同的队列,消息越早被消费,那么消息经过的队列层次越少,则平均每个消息处理的开销就越小。但若发布消息的速率过快,RabbitMQ来不及处理,这些消息就可能进入很深层次的队列,大大增加平均每个消息的处理开销,进一步使得处理新消息和发送旧消息的能力减弱,更多的消息会进入很深的队列,循环往复,整个系统的性能就会极大的降低。另外若接收消息的速率过快还会实现某些进程的mailbox过大,可能会产生很严重的后果。为此,RabbitMQ设计了一套流控机制。
RabbitMQ 使用了一种基于 credit 的算法来 限制 message 被 publish 的速率 。Publisher 只有在其从某个 queue 的 全部镜像处收到 credit 之后才被允许继续 publish 。在这个上下文中,Credit 意味着对 publish 行为的允许。如果存在没能成功发送出 credit 的 slaves ,则将导致 publisher 停止 publish 动作。Publisher 会一直保持停止的状态,直到所有 slave 都成功发送了 credit 或者直到剩余的 node 都认为某 slave 已经从 cluster 中断开了。Erlang 会周期性地发送 tick 到所有的 node 上来检测是否出现连接断开。 tick 的间隔时间可以通过配置 net_ticktime 的值来控制。
参考
https://www.centosdoc.com/system/92.html https://juejin.cn/post/7059377011344703496 https://www.rabbitmq.com/flow-control.html https://blog.rabbitmq.com/posts/2014/04/finding-bottlenecks-with-rabbitmq-3-3/ https://blog.rabbitmq.com/posts/2020/05/quorum-queues-and-flow-control-the-concepts/ https://www.rabbitmq.com/monitoring.html