多线程处理数据及JVM调优经历

时间:2024-05-22 13:43:57

简介
  • 多线程
  • ETL
  • JVM调优
  • 内存分析工具MAT

一 、前言

  • 场景
    使用etl及多线程方式同步近3000KW条业务更改记录数据,不同种记录需请求不同平台接口获取详细数据并处理同步到相关数据表,有线程及各种错误日志记录及相关处理机制.

  • 预方案
    使用ETL定时处理,多线程分区处理业务数据,线程池管理各个线程(50个)处理固定数量的更改记录,一次请求固定数量更改记录,递归调用直到处理完.

  • 开始干,问题来了
    首先本地跑起来,一次请求5000个更改记录,多线程并发下,有小概率请求不到平台数据及http请求报错,玩不了了呀,赶紧把一次请求数降低到2000并对请求提供错误记录和重试机制,降低之后概率指数级下降,错误记录下来一天可能错误一次,重试10次完全足够,这条over,继续,每一条更改记录又要请求平台不同的数据接口,更容易出现上面网络承载啥啥引起的错误,大概5pcs/day,这些记录到另外详细请求错误记录中留到最后针对处理,感觉没啥问题了,手动开启etl,第一次第二次完美,第三次,
    Exception in thread “pool-1-thread-49” java.lang.OutOfMemoryError: GC overhead limit exceeded
    什么鬼,怎么剧本不对,开始查看问题(隐藏我不知所措,没见过此类问题),放一个伪图(这是中间一段也有问题的),一开始的找不到了),使用java自带工具jvisualvm.exe 连上我的开发环境,cpu90%.堆内存阶梯式上升,
    多线程处理数据及JVM调优经历

打开Xshell, ps -ef|grep tomcat,查看tomcat配置,现在没了,实际配置如下,
参数不友好,直接修改
多线程处理数据及JVM调优经历
多线程处理数据及JVM调优经历
添加修改了一些参数,意义参考:
jvm参数设置 分析
-Ddruid.registerToSysProperty=true
-XX:+CMSScavengeBeforeRemark
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=3
-XX:ParallelGCThreads=10
-Xmx4g -Xms2g -Xmn1024m -Xss256k
-XX:CMSInitiatingOccupancyFraction=70

改完重新跑,手动跑个五六次,没毛病,定时开启,每两小时

---------------- 省略一天---------------
第二天打开,打开线程记录表,我靠,线程异常,打开日志,又是out of memory
linux: top指令,如下伪图,当时cpu tomcat进程cpu直接100%,
多线程处理数据及JVM调优经历

top -Hp pid(假如是1799), 查看详细信息
找到cpu最高的pid转换为16进制格式 printf “%x\n” tid(假如是1899) 转换成了16进制3553,然后jstack 1799 |grep 3553 -A 30查看线程详细信息,
发现cpu占比最高的是VM Thread和Parallel GC Threads,
多线程处理数据及JVM调优经历不是业务错误出现死循环啥的,怀疑是内存泄露没有,不知道咋搞,无限百度,
心路历程:
Java进程占用cpu过高问题分析

JVM故障分析 jstack生成的Thread Dump日志线程状态

jstack与jmap分析一次线上故障

MAT下载地址
我用的主要命令:
top;
top -Hp pid;
jstack pid >> thread.txt 线程信息到文件
jstack pid |grep tid -A 30 具体某个pid下线程信息
jmap -histo pid 查看class的使用情况,可能泄露的某个类
jmap -histo pid | head -7 查看class的使用情况,容易超出,截取前7行看占比最高即可
jmap -histo 922 >> dump.txt class的使用情况到文件
jmap -dump:live,format=b,file=文件名称随便起.bin pid 当前目录下生成dump文件用mat工具分析

最后,生成dump文件之后,使用mat打开,呈现

多线程处理数据及JVM调优经历
数据库连接出现内存泄露,复看代码,感觉没问题,无法继续,但是有一点之前的数据库连接池是从没见过估计是网上copy的,于是乎换成druid连接池连接多个库,重写了最原始的jdbc过程,再用etl跑,问题解决,cpu正常,堆内存稳定,最后的最后再去看了原来的jdbc,statement对象没有关闭,无言的坑最为致命,还是杰克马靠谱

多线程处理数据及JVM调优经历


  • 其他小结:
    此次多线程任务遇到了其他很多小问题,比如高并发下innodb频繁插入新增间隙锁导致死锁的问题,没有构建良好组合索引导致数据量过大之后查询sql超慢问题,还有对线程处理记录相关问题,比如记录线程处理数量volatile问题,volatile在高并发下复合操作并不具备原子性导致一开始统计不精准,然后使用原子类AtomicLong,ThreadLocal也有深的理解等等等等,技术广度深度还是不足,太菜~,赶紧又拿出我的高性能mysql深入理解理解java虚拟机.非常推荐这两本书呀,纸质版的,边看边百度感觉慢慢技术深度会有沉淀,就到这里了~

  • THANKS