Table of Contents
内存泄漏
采用sharding-jdbc分库分表后,执行自动化测试脚本,总是遇到响应超时。查看测试环境服务器发现已经内存崩溃。
由于jvm启动参数已经设置了 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath,下载jvm dump文件: heap_hprof_200617_155545.bin。
这里使用Java性能分析工具jprofiler11,执行命令: \jprofiler11\bin\jpanalyze.exe heap_hprof_200617_155545.bin ,解析dump bin文件,在本地目录生成 heap_hprof_200617_155545.hprof。
点击 jprofiler11,选择Open a snapshot 加载dump文件,选择hprof文件。如下:
打开hprof文件文件后,依次打开Heap Walker->Current Object->Biggest Objects
可以看到mysql查询结果加起来占用了 460M的内存。
由于服务器堆内存总共也就1G,加上其他占用,一个查询超过了可用堆内存,造成内存泄漏。
选中造成内存泄漏的内存大对象,右键打开界面,选择 Merged incoming references
sharding-jdbc执行结果合并
以前不会内存泄漏,基于sharding-jdbc分库分表后才频繁出现。
打开大内存对象Reference试图后,我们重点关注sharding-jdbc相关类。
最终定位到:org.apache.shardingsphere.sharding.merge.dql.iterator.IteratorStreamMergedResult
根据后台日志,自动化脚本触发了一些非分片键查询,只有非分片键作为查询条件会产生跨分片查询,跨分片查询的原理是:通过线程池并发请求到所有符合路由规则的目标分表,然后对所有结果进行归并。
sql简化如下。由于items_type非分片键,sharding-jdbc首先并行查询出所有满足条件的结果集,然后调用遍历结果集归并。
SELECT
*
FROM
sku
WHERE
items_type = 4
ORDER BY
ctime DESC
归并原理如下:
并行查询加sharding-jdbc中间层的结果归并,占用内存大大超过分库分表前。
解决方法
原来的查询方法从全量查询更改为分页查询。
适当调大最大堆内存: -Xms2G -Xmx2G。
基于hibernat validator框架结合javax.validation.constraints.Min等注解,对输入参数增加校验,在java应用层拦截调非法请求。