测试过程中,执行命令rabbitmqctlset_vm_memory_high_watermark0,结果rabbitmq立即发出内存告警。执行命令rabbitmqstatus查看“{alarms,[memory]}”,观察rabbitmq日志:2020-04-1408:25:36.463[info]<0.272.0>Memoryhighwatermarksetto99MiB(104808243字节)的1999MiB(2096164864字节)总计2020-04-1408:25:36.464[信息]<0.272.0mark_high水印设置为vm_wamory。已用内存:140603392允许:1048082432020-04-1408:25:36.464[警告]<0.270.0>节点rabbit@rabbitmq上设置的内存资源限制警报。*********************************************************************在此警报清除之前,发布者将被阻止******************************************************************从mq控制台发布消息观察,消费者连接出现“阻塞”状态,但可以继续消费消息,执行PHPswoole脚本。观察:脚本不是涉及mq写操作的程序,可以正常访问和返回。从mq控制台看,连接出现“阻塞”状态,连接会因为没有心跳而关闭,不会一直挂掉。(这里有一个问题就是为什么不是3s就关闭一次呢?看一下9s的日志输出)。..b.mq写操作程序涉及的脚本无法正常访问返回。从mq控制台看,连接出现“blocked”状态。观察rabbitmq日志,有创建连接(accepting,connection),但是没有关闭连接的日志。因为内存告警,导致rabbitmq写操作阻塞。这只是阻塞等待,除非双端异常退出,否则不会关闭连接。swoole程序等待60s返回504(应该是使用nginx做反向代理时默认的超时时间),注意!这里虽然返回了504,但是worker还是处于“工作”状态,即swoole不会认为worker闲着,不会继续给它下发工作任务。随着请求的增加,这种情况会造成严重的影响。1、处于“阻塞”状态的连接会越来越多,会极大地消耗rabbitmq资源,达到阈值可能会导致整个mq崩溃。2、能正常工作的swooleworker越来越少,直到所有worker都忙,后续请求不再正常返回,相当于swoole服务挂了。执行命令rabbitmqctlset_vm_memory_high_watermark0.4即可清除告警。从mq控制台观察连接状态,将刚才“正在运行”的连接恢复到阻塞状态。mq写操作会继续,消息会正常写入。观察rabbitmq日志:#Memoryadjusted2020-04-1409:41:09.725[info]<0.272.0>Memoryhighwatermarksetto799MiB(838465945bytes)of1999MiB(2096164864bytes)total#Memoryalarmcleared2020-04-1409:41:09.728[信息]<0.272.0>vm_memory_high_watermark清除。内存使用:138969088允许:838465945#内存警告已清除2020-04-1409:41:09.729[警告]<0.270>节点rabbit@rabbitmq内存资源限制警报已清除#内存警报已清除2020-04-1409:41:09.731[warning]<0.270.0>memoryresourcelimitalarmclearedacrosscluster#刚刚出现的“blocked”状态被挂起启动的连接被关闭,可能是没有心跳。2020-04-1409:41:09.758[info]<0.16551.6>关闭AMQP连接<0.16551.6>(172.18.0.3:60212->172.18.0.2:5672,vhost:'/mqs',user:'guest')Conclusion当rabbitmq发出内存告警时,所有的producer连接都会被阻塞,出现`blocked`状态,禁止进一步发布消息。消费者连接出现阻塞状态,可以继续消费消息。rabbitmq连接阻塞问题相关因素内存告警vm_memory_high_watermark当mq运行占用内存达到配置的阈值时,系统会阻塞连接。配置值为vm_memory_high_watermark。默认值为0.4。即当rabbitmq使用的内存超过40%时,系统会阻塞连接。注意是mq进程可以使用的最大内存的百分比。比如32位系统单个进程最大内存使用量是2G,即使系统内存是10G,那么内存报警线就是2G*40%。解决方法:增大vm_memory_high_watermark的值,解决的方法快,但不是治标不治本。如果消息继续积压,内存使用量仍然会增加。根本的解决办法是平衡生产者和消费者,让消息队列尽可能不堆积,导致内存占用过大。配置方法:命令行:rabbitmqctlset_vm_memory_high_watermark0.4,在broker停止前生效。编辑配置文件:vm_memory_high_watermark.relative=0.4,一直生效。或者rabbitmqctlset_vm_memory_high_absolute1073741824vm_memory_high_watermark.absolute=1073741824/2024MB如果阈值设置为0,会立即发出内存警告,阻塞所有发布连接。集群告警:如果你使用的是rabbitmq集群,那么一个节点达到上限,所有节点都会阻塞连接。建议vm_memory_high_watermark不超过50%。vm_memory_high_watermark_paging_ratio配置分页阈值。在代理达到高水位线并阻塞发布者之前,它会尝试通过将队列内容分页到磁盘来释放内存。持久化消息和瞬态消息都会被pageout(即内存中的所有消息都输出到磁盘,包括持久化和非持久化。持久化消息一进入队列就会被写入磁盘)。=0.3开始分页,当内存使用量达到0.4时阻塞发布者。可以将vm_memory_high_watermark_paging_ratio设置为大于1。这种情况下,队列不会将内容分页到磁盘,如果造成内存警告,producer会像上面解释的那样被阻塞。磁盘警告当可用磁盘空间下降到配置值(默认为50M)时,将触发警告。一旦发出警告,所有生产者将被阻止以避免填满整个磁盘。当发生报警时,rabbitmq不仅会阻塞producer,还会阻止内存中的消息被分页到磁盘,避免磁盘耗尽。但这并不能完全阻止分页。因为在内存压力增大的情况下,会触及内存使用的阈值,这也会促使rabbitmq将消息分页到磁盘,从而进一步耗尽磁盘。磁盘警报也是集群范围的警报。如果一个节点低于配置值,所有节点将阻止传入消息。Rabbitmq会定期检查可用磁盘的大小,这与上次检查的空闲空间有关。一般情况下,如果可用磁盘空间没有达到配置值,每隔10秒检查一次。但如果接近配置值,频率会增加,可能每秒增加多次。disk_free_limit配置方法:编辑配置文件:disk_free_limit.absolute=1000000000(不带单位,默认byte)disk_free_limit.absolute=1GB(或带单位,KB,MB,GB)也可以设置可用磁盘空间和内存机器相关,本配置设置可用磁盘与内存大小相同(相对于内存)disk_free_limit.relative=1.0命令方法:rabbitmqctlset_disk_free_limit1GB当然,执行命令的方式会立即生效,一直持续到经纪人重新启动或停止。重启后生效,需要编辑配置文件。参考资料https://www.jianshu.com/p/f61e6f328d25https://cloud.tencent.com/developer/article/1454194写在最后是我在开发过程中遇到的一些问题,绝不是官方的不对的地方欢迎解释、指正和讨论,互相学习,互相提高才是目的。
