前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RocketMQ与Dubbo相爱相杀引起的FullGC

RocketMQ与Dubbo相爱相杀引起的FullGC

作者头像
书唐瑞
发布2022-06-02 14:02:34
3450
发布2022-06-02 14:02:34
举报
文章被收录于专栏:Netty历险记

在日常后端开发中,部分业务都是接收MQ消息,在消费消息的过程中,会调用外部的Dubbo接口,根据接口返回数据,做一些业务逻辑处理.如下图

上面会涉及两类线程,一类是MQ线程,一类是Dubbo线程.

Dubbo接口调用超时也是经常会发生的事情,这篇文章中,我们模拟的情况是,让Dubbo接口调用超时,图中红线所示.然后一直向MQ消费者发送消息,我们观察线程和堆栈的变化.

代码语言:javascript
复制
仓库代码
https://github.com/infuq/MQ-Dubbo-FullGC

如果需要运行上述代码,还需要部署Zookeeper和RocketMQ环境.

工程结构如下图

Dubbo提供者的接口超时时间设置的是5s.如下图

而在提供者的实现方法中,让线程睡眠20秒,从而达到调用者调用接口超时目的.如下图

接下来按顺序启动它们

首先启动Dubbo提供者(DubboProvider类).

接着启动MQConsumer, 同时需要给它配置VM启动参数

代码语言:javascript
复制
-Xms90M -Xmx90M -XX:+PrintGCDetails

最后启动MQProducer, 它会一直发送消息.

所有的都启动完成之后, 借助JDK自带的jvisualvm.exe工具观察MQConsumer的堆栈信息.

观察MQConsumer的堆栈信息,会发现老年代会一直增长,当老年代快增长到顶端时,手动dump堆栈信息,用于接下来分析堆的情况.

同时观察MQConsumer的控制台, 会有FullGC产生,而且很多次.

大体流程就是上面描述. 发现的表象是老年代一直在增长,伴随着发生了FullGC,那么原因是什么?

通过MemoryAnalyzer来分析下之前dump的堆栈文件.

打开文件之后,点击Dominator_Tree.

继续点击

发现数量最多的是MessageClientExt这个类对象.它是和消息有关.

右击,选择with outgoing references

任意展开一个对象,查看body的内容就是MQProducer发送的消息体内容.

也就是说,随着MQProducer生产者一直发送消息, MQConsumer消费者的堆空间中存储着大量的未被消费的消息.

由于Dubbo接口调用超时,阻塞住了MQ消费消息的线程,而MQ生产者一直在生产消息,可消费消息的速度太慢(由于Dubbo调用超时间接导致),最终消息都被放在老年代堆空间中,引起频繁FullGC.

通过查看MQ源码

代码语言:javascript
复制
// 源码位置
org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService

存放消息的队列是一个无界队列,也就是说,只要消息生产者生产消息的速度比消费者消费消息的速度快很多很多,最终一定会发生FullGC,更严重发生OOM.至于消费者消费消息的速度为什么慢,比如上面的情况,调用Dubbo接口耗时太久等原因.这里要说一点的是,导致Dubbo接口耗时太久的重要一点是因为Dubbo中需要查询数据库耗时太久(慢SQL).

RocketMQ和Dubbo, 导致FullGC的原因以及造成FullGC的地方还有很多,接下来的文章也会一一列举出来.

针对这篇文章,也会抽个时间录播一个视频演示给大家看.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Netty历险记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档