问题背景
多线程全量导入数据库数据到ES,15个线程,每个线程进来拿一个门店编码去数据库查询数据总量,然后按照每页8000数据量导入到ES。其中有一个门店编码下的数据量在57万多,在查询到50多页的时候,就没有继续翻页,此时top命令查看,java进程cpu一直超过百分之百。
问题排查一
1.top -Hp pid 查看java进程下的所有线程情况;
2.printf “%x\n” pid 将cpu高的线程转换成16进制;
3.jstack pid | grep “16进制pid”
此时报错
原因是/tmp/hsperfdata_root找不到这个线程号的文件。(这个可能跟tmp文件下的文件会被定时清理有关系)。
放弃。
(但是在其他博主下找到了别的方法,没有试过。方法如下)
问题排查二
1.此时进入/heapdump目录下,发现有一个dump文件,看docker启动命令,在内存超过2g时会生成dump文件。
2.tar -zcvf /applog/provider/logs/java.tar.gz java_pidxxx.hprof命令压缩文件,并下载到本地并解压
3.java -Xmx5g -jar ha457.jar启动IBM HeapAnalyzer工具,打开java_pidxxx.hprof文件。
4.发现有一个hibernate类占用内存超过百分之95。查询方法是用jpa来实现的,此时想到jpa的缓存问题。在同一事务中,jpa查询到的数据会缓存在本地。
5.为验证猜想,在每次查询之后调用getEntityManager.clear()方法清理缓存。打包上传到docker,启动全量导入,看日志翻页到70多页,cpu也没有过高,问题解决。
另外,还可以使用eclipse插件eclipse memory analyzer来打开文件dump文件,此时会生成.threads文件,打开之后,可以根据线程id找到类。