rabbitmq 流量控制

前言

在TCP传输中,接收端每次通过ACK确认消息,告诉发送端哪些序号的消息已经成功接收到并且在ACK中指定当前接收端接收缓冲区的大小,这样发送端发送的数据大小不能超过此大小,必要时(例如:由于发送端数据发送过快,导致接收端接收缓冲区窗口缩小,如果这时发送缓冲区已满)则阻塞发送端的应用程序write方法。如同TCP滑动窗口流量控制机制一样,rabbitmq也支持流量控制,当broker出现内存或磁盘资源等达到设置的阈值时,则会触发rabbitmq流量控制机制,阻塞消息生产端的connection,阻止生产者继续向broker发送消息,直到内存和磁盘资源不足警告解除,才会解除对connection的阻塞,从而实现流量控制机制。

基于内存流控

rabbitmq服务在启动时,会检测服务器安装内存。默认情况下,如果rabbitmq服务使用内存达到服务器安装内存的40%时,则会引发内存警告,触发broker的流量控制机制,阻塞正在发生消息的connection。一旦内存警告消除之后(由于borker将消息置换到disk或投递给消费者,释放占用的内存),broker将恢复正常,停止对生产端connection的阻塞。

rabbitmq默认的内存阈值是机身内存的40%,但并不意味着broker只能使用机身内存的40%,而是说当内存使用达到机身内存的40%时会触发流量控制,在最坏的情况下,Erlang的垃圾收集器可以使用两倍的内存量(默认情况下是80%的RAM),强烈建议操作系统启用swap或page file功能。

内存阈值vm_memory_high_watermark设置

[{rabbit, [{vm_memory_high_watermark, 0.4}]}].

或者可以通过设置节点使用RAM的绝对限制来调整存储器阈值,以下示例将阈值设置为1073741824字节(1024 MB)

[{rabbit, [{vm_memory_high_watermark, {absolute, 1073741824}}]}].

或者指定单位(kB, kiB, MB, MiB, GB, GiB等):

[{rabbit, [{vm_memory_high_watermark, {absolute, "1024MiB"}}]}].

在rabbitmq运行时动态改变阈值:

./rabbitmqctl set_vm_memory_high_watermark 0.4
./rabbitmqctl set_vm_memory_high_watermark absolute 1073741824

rabbitmq服务在启动的时候,会在RABBITMQ_NODENAME.log文件中打印当前服务的内存阈值限制值:

=INFO REPORT==== 29-Oct-2009::15:43:27 ===
Memory limit set to 2048MB.

置换比例vm_memory_high_watermark_paging_ratio设置

在broker达到内存阈值阻塞消息生产者之前,broker会试图将queue中的消息(包括持久消息和非持久消息)置换到磁盘上,当然对于持久消息是已经落地到磁盘的,但是需要释放其占用的内存空间。默认情况下是vm_memory_high_watermark的50%,也就是机身安装内存的20%的时候,broker开始试图将queue中的消息置换到磁盘上以释放占用的内存空间,这个值是可以通过调整vm_memory_high_watermark_paging_ratio进行设置的。

[{rabbit, [{vm_memory_high_watermark_paging_ratio, 0.75},
{vm_memory_high_watermark, 0.4}]}].

上面的这段配置表示:当broker内存使用达到机身内存的30%时,开始触发将queue中的消息置换到磁盘,当内存使用达到机身内存40%时,则会触发流量控制,阻塞消息生产端connection。我们可以将vm_memory_high_watermark_paging_ratio的值设置成大于1.0,这样queue中的消息将不会被置换到磁盘,直到达到vm_memory_high_watermark阈值,触发流控。

Limited Address Space

当在64位操作系统下,运行32位的Erlang VM时,rabbitmq服务能自动检测到并打印类似如下的日志

=WARNING REPORT==== 19-Dec-2013::11:27:13 ===
Only 2048MB of 12037MB memory usable due to limited address space.
Crashes due to memory exhaustion are possible - see
http://www.rabbitmq.com/memory.html#address-space

rabbitmq内存报警功能并不完善。虽然可以通过阻塞生产端connnection停止发布消息来控制进一步的内存使用,但是很有可能其他操作会继续增加内存使用。通常当这种情况发生时,物理内存耗尽,操作系统将开始交换。但是当使用Limited Address Space运行时,运行超过限制会导致VM崩溃。因此,强烈建议在64位操作系统下使用64位的Erlang VM,避免出现Limited Address Space。

基于磁盘流控

当服务器可用磁盘空间下降到设置的阈值时,同样也会触发broker的流量控制。在rabbitmq服务启动时会打印类似如下的配置信息:

=INFO REPORT==== 23-Jun-2012::14:52:41 ===
Disk free limit set to 953MB

当rabbitmq运行在集群模式下,磁盘警报是集群范围内的。如果其中一个节点出现磁盘警告,则会触发集群中所有节点的流量控制,阻塞所有节点上的生产者connection。rabbitmq将定期检查磁盘可用空间的大小,检查的频率与上次检查时磁盘可用空间量有关。通常每10秒检查一次磁盘空间,但随着接近限制,频率会增加。当非常接近极限时,RabbitMQ将每秒检查频率为10次,这可能对系统负载有一些影响。

磁盘阈值disk_free_limit设置

[{rabbit, [{disk_free_limit, 1000000000}]}].

或指定单位(kB, kiB, MB, MiB, GB, GiB等):

[{rabbit, [{disk_free_limit, "1GB"}]}].

除此之外,我们可以将磁盘阈值设置成相对于机身安装内存的大小比例,例如下面配置文件将磁盘阈值设置为与机器上的RAM大小相同:

[{rabbit, [{disk_free_limit, {mem_relative, 1.0}}]}].

在rabbitmq运行时动态改变阈值:

./rabbitmqctl set_disk_free_limit 1000000000
./rabbitmqctl set_disk_free_limit mem_relative 1.0

参考链接

  1. http://www.rabbitmq.com/memory.html
  2. http://www.rabbitmq.com/disk-alarms.html
  3. https://www.rabbitmq.com/alarms.html
  4. http://www.rabbitmq.com/flow-control.html
  5. http://www.rabbitmq.com/blog/2014/04/14/finding-bottlenecks-with-rabbitmq-3-3/