那些年我们踩过的RabbitMq的巨坑
前语:因为上次发帖貌似没有发对模块没有通过审核 重新发一次导语:
中间件在一套完整的系统架构体系中是不可或缺的,比如 nginx,redis,mq,mycat,es 等
消息队列:
消息队列在软件系统架构中,可解决异构系统中不同进程间的通信,也能用作同步、保证数据强一致性
问题等
如需详细了解 RabbitMq 的详细设计、原理。会在后文介绍,请持续关注
此文重点介绍 RabbitMq 在本次生产环境中的应用,包括引入、出现的问题以及解决方案
消息中间件的引入:
业务中有这样的一个场景: 根据用户自定的策略,去分析实时数据(实时数据有效期是2s)。理论上说的
实时是没有延迟的,但对应用程序来说,在有效期内,数据的刷新周期越短越好。这样无论是用户的体
验还是策略执行的精确性,都是最佳的。因此引入了消息中间件 RabbitMq 做数据广播。并建立了十个
生产者节点,系统稳定运行,用户体验良好
出现的问题:
某天消费节点突发性宕机,经排查的得知为OOM。查看 RabbiqMq 服务控制台
如图1
大量的消息积压在队列中,生产者抢占了mq服务内部大量的CPU资源,导致mq服务无法维护正常消费
者的channel!
1.在网络传输中,操作系统维护一个TCP连接的开销是非常昂贵的,在高并发场景中将会很容易使系
统达到瓶颈,引起雪崩问题
2.应用系统和Mq之间的连接验证通过后,会建立一个TCP连接。 channel 是建立在TCP上的虚拟连
接,每一个 channel 都有唯一的ID标记。生产/消费消息都是通过 channel 来完成。这样既满足性
能要求,又能确保每一个TCP连接的私密性。也可通过配置 Virtual host (虚拟路径)来隔离不同
的应用
已致于应用系统消费服务中和mq服务之间的TCP链接中断,随后不断进行 reset 重新尝试建立链接。
此时mq服务已无更多的资源去维护链接,链接一直失败(断续,比链接失败更消耗资源)再一直尝试,引
发应用系统中消费服务节点OOM而宕机
解决方案:
述我们分析了生产环境中mq服务相关的一些问题点和原因,这里总结一下
1.消息堆积
2.消费服务节点OOM宕机
消息堆积:
mq服务中,消息堆积有三个原因(含解决方案)
1.无消费者在线
1.1 启动消费者(这个不详细介绍)
2.消费速度跟不上生产速度
2.1 根据业务需求,可降低生产速率
2.2 消费线程默认是单线程消费,可自由配置消费个数、消费的线程数
这里是图二:
3.消息未确认
3.1 消息的确认机制,可分为有无ACK两种。有ACK效率低,但不会丢失消息;无ACK效率高,但
消息可能会丢失
这里是图三
消费服务节点OOM:
上文提及应用系统消费/生产服务节点和MQ服务建立了一个TCP连接,这个TCP连接在MQ服务上表示为
一个 Connection , channel 是基于 Connection 建立的(消费者channel即为上述的消费线程数)。在生
产者高并发push的场景下,一旦MQ服务没有足够的CPU资源去维护消费节点的 Connection ,
channel 也将无法保持正常的连接
这时消费服务节点就会不断去尝试重新建立连接,导致消息无法正常被消费,栈内存耗尽,引发消费服
务节点OOM,消息大量堆积在MQ服务的QUEUE中
分析完问题,现在咱们来聊聊解决方案:
1.设计应用系统时,必须要考虑到增量数据,尽可能的去架设无状态的服务节点
2.中间件的引用,无非是为异构系统间更方便和高性能的交互,绝不能演变成拖垮业务节点的隐患。
当单机无法承载并发量时候,可考虑横向拓展成集群,比如redis集群、mq集群、gateway集群、
mysql集群等等。
3.JVM耗内存众所周知,业界也并不是每一家公司都有阿里的物力和财力去针对JVM做深度的优化。
我们能做的只能去适配堆栈内存,找到适合自已系统业务的合适大小,并提高代码质量。
写在最后:只有经得起业务和流量验证的系统,才算是一个“完整”的系统。一切脱离业务的技术和架构,都是耍流氓
第一次发帖没什么经验,如果有违规的请删帖。如果没发对模块请管理员移动一下 勿删!
啊!再问一句大家 请问怎么在帖子中插入图片 摸了十几分钟没整明白怎么直接插入图片! 插入图片方法,在上传好图片后,点击图片就可以插入进帖子里了 {:1_925:}最近也在着手搭一个高并发场景的系统
:Dweeqw谢谢楼主帮忙踩坑,哈哈哈哈
不过话说,消费者的connection不应该是高优先级的,居然会被并发撑崩?不太明白rabbitmq的内存机制?
懵逼。集群我们这边前期应该是不会考虑的。
但是话说,去摸奖合适的内存分配更尴尬啊。。。
有没有类似于内存分配的优先级,把connection优先维护住啊?
啊啊啊啊,要疯! 很有用的东西 感觉有点奇怪
是消费者OOM了,消费者的连接重试 把自己连崩了?
prefetch是不是大了?
不太明白,因为我们的业务场景MQ主要用来削峰。
按照我们之前的设想,mq把峰维护到队列里,
消费者这边去队列里面取这些消息进行业务处理、并持久化。
如果是mq导致的内存紧张,应该已经无法再pub了吧,但是看情况,好像是队列依然再堆积。如果是我的话,我可能会去怀疑消费者的逻辑问题,接收的prefetch过大?还是有别的内存泄露?
因为还没有实践过,有什么错误,还请楼主不吝指出,谢谢。
想请问一下:
使用消费者的手动确认模式,能不能比较好的控制消费者的性能。(因为我们自己没有能力对mq这一块做优化,所以只能相信它能稳定可靠的提供高并发支持),然后我们这边消费者,根据自己的计算能力,去获取队列信息,完成削峰填谷,这种方式可行吗? 苏紫方璇 发表于 2019-8-21 09:25
插入图片方法,在上传好图片后,点击图片就可以插入进帖子里了
好的,下次发帖的时候试试 井右寺 发表于 2019-8-21 11:00
感觉有点奇怪
是消费者OOM了,消费者的连接重试 把自己连崩了?
prefetch是不是大了?
手动ACK可以采用批量确认机制。根据自己的计算能力是指的机器的性能还是指代码能承受的并发量?应该是可以的,去尝试一下。好多东西都是尝试出来的 去年夏天我还在 发表于 2019-8-21 18:52
手动ACK可以采用批量确认机制。根据自己的计算能力是指的机器的性能还是指代码能承受的并发量?应该是可 ...
代码性能应该是,预估的 假设 起20个worker来消费信息,那么 他们的性能 会有数据库、代码逻辑、计算性能综合决定。。。。。。这种想法,对吗?
到时候再试试吧
主要现在我们都还在 初步的架构设计阶段,不知道还有多少坑在前面等着呢 最近公司项目准备接入这个 这里先学习一下 这个很可以 {:1_921:}
页:
[1]
2