一次应用多次fgc原因的排查及解决
创始人
2024-02-17 16:36:46
0

应用多次fgc性能排查(一次抢购引起的性能问题)

大家好我是魔性的茶叶,今天分享一个项目jvm多次fgc的整个排查流程

上班后不久运维突然通知我们组,有一个应用在短时间内多次fgc,即将处于挂掉的状态。

首先我登录skywalking,观察应用整体状况

首先先交代下背景,该项目属于一个整合消息的项目,可以称之为消息中心,负责我们应用中的所有的推送,短信及公众号推送,消息都是通过业务方面投递到kakfa消费的方式,所以feign或者http调用的外部调用几乎没有

首先通过cpm(call per minute/每分钟服务被调用数)观察服务整体情况

我们可以看到在8.到8.07分这段时间有一个波峰,询问产品得知是有医院开启了抢购药品的业务(某些专科医院比如说皮肤病医院,会在一些特定时段,每天开启限制数量的药品抢购,这个抢购属于比较火爆的业务),所以这个流量峰值是正常的。流量一大,消息队列中的消息数量立刻就上来了:

那么我第一个想法,有没有可能是kafka消息堆积呢?应用的处理能力跟不上,导致消息大量堆积,带着这个问题,我去看一下skywalking监控的消费速度,打开Endpoint监控,观察slow endpoints:

可以看到最慢的kafka消费速率在234ms,对于一个需要调用第三方外部接口完成业务的消费来说,这个速度不可以说慢,甚至还可以说有点小快。没关系,只要是性能问题,那么总是有迹可循。我点开最高负载的服务实例查看gc次数:

可以看到在8.6分流量最高的这段时间fgc的次数达到了70次,这确实离谱,按照我的经验一个健康的应用甚至不应该一天fgc超过10次,这一分钟超过70次居然还没当场挂掉,简直可以称之为坚挺。我们再看看jvm线程数量:

waiting的线程在流量冲入后大量增加,几乎导致了oom,在流量波峰过去后线程数量又慢慢归于平稳

所以观察结论是大量被创建的线程导致的内存飙高,接下来就是需要观察线程快照找出罪魁祸首了

将线程堆栈导入fastthread.io/分析堆栈,我们查看线程数最多的相同线程组

这个明显是OkHttp使用不当导致的OkHttp链接池的异常增多,我第一个反应是联想到我们的fegin调用,feign底层可能使用了OkHttp导致OKHttp链接池创建异常。下一秒就把自己的推测推翻了,因为首先feign不可能有这么明显的问题,第二是上图中的“OkHttp api.tpns.tencent.com”我们并不是通过feign调用,而是直接通过sdk调用的(这个是tpns,腾讯的app推送)

那么,有没有可能是sdk的问题呢?

我们是这么调用腾讯的推送的:

//每次推送都会调用这段代码 
XingeApp xingeApp = new XingeApp.Builder().appId(androidAppId).secretKey(androidSecret).domainUrl(PREFIXURL).build();return xingeApp.pushApp(pushAppRequest);
复制代码

点开build方法发现是这样的

 public XingeApp build() {if (appId == null || secretKey == null) {throw new IllegalArgumentException("Please set appId and secret key.");}
​return new XingeApp(this);}
​
​
private XingeApp(Builder builder){if(builder.domainUrl != null){restapiV3.setDomainUrl(builder.domainUrl);}
​this.accessId = builder.appId;this.secretKey = builder.secretKey;this.isSignAuth = builder.useSignAuth;
​client = new OkHttpClient.Builder().proxy(builder.proxy).connectTimeout(builder.connectTimeOut, TimeUnit.SECONDS)//设置连接超时时间.readTimeout(builder.readTimeOut, TimeUnit.SECONDS)//设置读取超时时间.build();}
​
​
复制代码

可以看到这个new XingeApp(this)到后面是初始化了一个OkHttpClient的客户端,点进OkHttpClient的Builder方法是这样的:

public Builder() {dispatcher = new Dispatcher();protocols = DEFAULT_PROTOCOLS;connectionSpecs = DEFAULT_CONNECTION_SPECS;eventListenerFactory = EventListener.factory(EventListener.NONE);proxySelector = ProxySelector.getDefault();cookieJar = CookieJar.NO_COOKIES;socketFactory = SocketFactory.getDefault();hostnameVerifier = OkHostnameVerifier.INSTANCE;certificatePinner = CertificatePinner.DEFAULT;proxyAuthenticator = Authenticator.NONE;authenticator = Authenticator.NONE;//可以看到罪魁祸首就在这里connectionPool = new ConnectionPool();dns = Dns.SYSTEM;followSslRedirects = true;followRedirects = true;retryOnConnectionFailure = true;connectTimeout = 10_000;readTimeout = 10_000;writeTimeout = 10_000;pingInterval = 0;}
复制代码

于是真相大白,原来ConnectionPool对象是在这里new出来的

可以看到,每次new一个XingeApp就会new一个OkHttpClient,顺便new一个ConnectionPool。而每次推送的都会new一个XingeApp导致内存中有大量的ConnectionPool对象存在,直到堆满了进行一次fgc,又能回收掉很大部分的内存,因为大部分ConnectionPool在推送完成后以后都是没用的垃圾内存,推送又是海量的,所以导致内存一直满一直fgc但是又能一直抗住(因为每次fgc可以gc掉大部分内存)

那么怎么解决呢?

最简单的解决方式就是减少XingeApp实例的对象,因为没必要每次推送都去new一个对象出来,按理说只需要一个实例就够了,OkHttpConnectionPool也只需要一个,链接的复用和摧毁完全交给OkHttp就行。所以修改如下:

//伪代码 双重校验锁
public static XingeApp getAndroidXingeAppInstance(){if (androidXingeAppInstance !=null){return androidXingeAppInstance;}synchronized (TpnsPushLogicImpl.class) {if (androidXingeAppInstance !=null) {return androidXingeAppInstance;}androidXingeAppInstance = new XingeApp.Builder().appId(staticAndroidAppId).secretKey(staticAndroidSecret).domainUrl(PREFIXURL).build();return androidXingeAppInstance;}
}
​
public void pushMessage(){XingeApp xingeApp = getAndroidXingeAppInstance();xingeApp.pushMessage;
}
​
复制代码

升级后在推送高峰期重新查看skywalking仪表板:

可以明显看到线程数量降下来了,gc也只有ygc,说明很健康

重新打出该应用的线程快照,导入线程快照分析工具查看okHttpConnectionPool线程

可以看到现在应用内只有一条OkHttpConnection的线程,改造成功

相关内容

热门资讯

思想政治工作条例最新修订内容,... 思想政治工作条例最新修订内容,思想政治工作条例全文下载 思想政治工作条例最新修订,全文下载与深度解读...
CBA潜力赛为何打成“老将赛”... 计时钟归零,双方教练握手致意,观众开始退场,CBA联赛的正赛宣告结束。然而球场并未就此沉寂,替补席上...
“手术钻头断裂遗留患者体内”,... 12月21日,湖南祁阳市卫生健康局发布情况通报称,近日,有媒体报道祁阳市中医医院发生骨科手术钻头断裂...
代驾纠纷 代驾时撞伤行人、车辆发生故障…… 这些都和车主无关,应由代驾赔偿? 观点: 使用代驾服务并非将所有...
公司股东与妻子分居期间出轨女下... 近日据报道,宁夏永宁县人民法院一审查明公司股东李某乙在与妻子李某甲分居期间,与公司女员工马某某存在不...
动物学家、律师和创作者,Thi... 12月21日,以“一起·了不起”为主题的2025 ThinkPad黑FUN礼在京举办。活动现场,律师...
徐奇渊:扩内需与对外政策紧密相... 近日,中国海关总署发布了一组数据令人关注:2025年前11个月,我国货物贸易顺差达到1.08万亿美元...
46岁上海独居女子不幸离世,官... 居住在上海虹口区46岁的蒋女士因突发脑溢血于今年10月入院,远亲吴先生与其公司共同垫付了医药费,但她...
威海市汽车以旧换新补贴政策调整... 根据稳妥有序开展消费品以旧换新工作统一部署,经研究决定,对我市汽车以旧换新补贴政策进行调整。现将有关...