写点什么

记 服务 内存飙升压测 - 分析总结

作者:PCMD
  • 2022 年 1 月 28 日
  • 本文字数:1414 字

    阅读完需:约 5 分钟

记 服务 内存飙升压测 - 分析总结

“工欲善其事,必先利其器”


背景

我们经常会进行一些线上的压测,然后来分析一些问题,比如大内存的分析,cpu 飙升问题的排查,来定位引线上问题的原因,从而解决问题。


往往这些数据,很难从我们可见的一些监控项,来进行排查出来,这时候,就得通过一些工具,来进行排查分析总结,过程中避免不了线上的大型操作,比如 dump 、jrf 等操作,但命令慎用,因为会对线上造成一定的影响。

案例

就本次的压测情况,进行下分析 ,上周四,针对 服务进行了一次压测,在压测过程中发现,很容易打爆了 内存,如下图


基于当前的案例背景,来分析下,问题原因,以及如何进行排查的过程

过程

  1. 通过 cat 和 grafana 上监控看到了, 内从使用的飙升。

  2. 由于无法在线上直接进行 分析,就下载 dump 文件,进行本地的 内存分析。过了一定的事故现场,下载下来生成的 dump 文件不一定能恢复当时实际的 事故现场,单也能从一定程度上进行反应。


通过 jprofiler 对 dump 文件来进行一些分析,排查大内存 的占用是属于那些地方引起导致的

3. 通过 jprofiler 打开之后,堆内存 分析 如下图,发现大内存的调用 是大量的字符类型数组


4. 然后通过此刻大对象 的这个视图,可以看到,大部分内存占用 在哪里此刻可以排查到,大对象的占用,全都是 LogData 对象


  1. 针对 char[] 这个对象,展开之后看他的引用,如同下图,发现大批量的都是一些 返回值 & context 等上下文中的东西


此刻已经大部分明了其组成。


  1. 针对其中的几条,抽样 进行 查看

  2. 通过 show in graph 可以方便的定位出来最上层的引用,从而方便排查问题


如下图所示


通过对象的生成和引用关系,可以轻松的定位出来,,主要的问题出现在 2 个地方,


  • 一个是数据 trheadLocal 中 的 返回值 。

  • 还有一个是属于 LogData 中的 大对象。


此刻,问题已经清晰,绝大多的数的 大对象,来自于 LogHelper ,占整体的 61%


接着,在代码中定位查看 :在代码中 会持有一个 blockingQueue 队列,队列长度 10 w ,目前 已经改为了 1 万


会死循环的方式,针对队列汇总的日志数据,进行 日志的上报,此刻针对 流程中的节点日志出入参,进行上报,用来进行问题的排


通过日志的上报代码发现 ,是通过 http 的方式进行上报 Okhttp client 设置 超时时间 3s 然后一次 100 条,当 上报失败,会重试一次 ,2 次失败,则丢弃


总结

当时压测的时候,在大流量的情况下, 基本上把日志收集服务打垮了,此刻平均 6s 中 消费 100 条队列中的数据。消费速度远远赶不上 生成速度,所以大批量的信息,被持有在 内存中,无法释放,引起频繁的 GC 和 内存飙升。


大问题的分析出来之后,又对 一些细节问题记性分析:


  1. 为什么这个单条日志信息这么大针对大日志的问题,当晚压测已经有分析出来,我们针对节点 上下文中,部分会记性重复写数据进去,在其中一块的业务代码逻辑中会重写一个 list 对象如下图



  1. 为什么日志会这么多?捞取其中的一条 大日志,返现这一批中,会出现几条一样的 traceId 的数据,traceId 一致的数据,则以为这一次调用,不同的 processor 通过对比工具看来,2 个节点 ,具备一样的 input ,从而分析出,即使不同的节点,凡是写在 context 上下文中的对象,会无限制的膨胀。

  2. 通过组件的框架的代码,也验证了这一点,每次的 input 都会 序列化 当前的对象,并不是对象之间的引用


至此,得出结论: 我们的上下文有多大,有 n 个节点,那么日志就会膨胀 n 倍,内存中的持有,也会膨胀,可能还会导致由于数据包过大,而带来的上报异常


最后也反哺工具团队,进行部分代码的优化

发布于: 刚刚阅读数: 3
用户头像

PCMD

关注

我看青山多妩媚 2020.02.07 加入

还未添加个人简介

评论

发布
暂无评论
记 服务 内存飙升压测 - 分析总结