写个任务,翻车了 -- 记一次内存溢出排查

 关注公众号【1024个为什么】,及时接收最新推送文章! 

本文内容:

1、背景

2、技术方案

3、翻车了

||  背景

前段时间搞数据加密,需要把数据库中现有的某些列加密存储。

公司定的技术方案是由服务层做这项工作,不同的服务分配不同的秘钥,秘钥泄露也只会影响这一个服务,安全性更高。架构组提供加密算法包,各业务自己完成加解密的工作。

这其中有一项艰巨的任务,对历史数据的加密。由于不能在数据库层面批量处理,架构组也没有提供统一处理的方案,各业务只能自行解决。

我认为像这种和业务无关的事情,应该出一个通用的解决方案。一来可以减少各业务重复开发的工作量,二来也可以避免各业务试错成本。

||  技术方案

所以我在设计方案的时候,把上面说的都考虑了进去,做了一个通用的技术方案,支持试刷、重刷、校验功能。各业务整个流程都是一样的,不同的只是密钥、库表、字段信息,这些都放在了配置中心。

95d126495fa302101ead3a5ce4c5eb08.png

接下来就该由它完成这项艰巨的任务了。

我先用它把自己负责的几个服务的数据都刷完了,一切都很顺利,速度也能接受,20W/min,接着又刷了其他几个同事的数据,也很顺利。

||  翻车了

上面刷完的单表数据量都不大,最大的也不到 300W 。

在刷另一个同事的数据时,执行了大概 20 分钟左右,速度明显慢了下来,而且越来越慢,只能停了重试,重试现象依旧。

猜着可能是分页的问题,排查发现条件里的 id 用的就是主键 id,不应该慢啊。

又找同事一起研究了一下代码逻辑,也没看出什么问题。

继续重试,半小时左右的时候,报了内存溢出,所以只能先拿到内存快照才能分析什么原因了。

由于执行任务的机器没有加 gc、dump 相关的配置,把任务切到有配置的机器上执行。执行过程中,通过 gc 日志监控 full gc 情况,发现不到 10 分钟就触发 full gc 了,越来越频繁,直到刷屏。等内存溢出后,拿到 dump 文件。

说明一下:我们为了兼顾性能和故障可追溯,线上机器,只选了一台配置了 loggc、HeapDumpPath,因为只要程序有问题,每台机器都会有问题,有一台留痕就可以了。权限也有严格的控制,像 jstat 这种命令都是禁用的。

这里引申出一个面试题,有面试官会问怎么拿到 dump 文件,因为大部分同学工作中很少遇到这种场景。

有人说可以用 jvisualvm 的远程登录分析功能,这个吗,自己玩玩还行,千万不能用在线上,估计你也没有权限。

我这次任务的服务 JVM 配的是 1G 内存,生成的 dump 文件有 1.1G,压缩后 402M,算是比较小的。但是也不能直接从服务器直接下载,不仅速度慢,还会影响服务的带宽。因为大多服务都是内网之间的调用,这类机器的外网带宽很小的,就算允许你下载,没几个小时也下载不完。

说一下我司的流程,会先把文件转存到 FTP 服务器上,因为是内网,耗时可以忽略,再通过 FTP 服务器下载,这样既不影响服务,下载速度也很快。其实运维同学已经把这个流程已经集成在运维系统了,我们直接选择要下载的文件,系统就会自动转存并生成一个链接,点击链接就能下载。

接下来就是分析 dump 文件了。我用的是 IBM 的 HeapAnalyzer,直接通过 jar 包启动,需要注意的是要把启动内存设置大一点,默认的太小了,至少是 dump 文件大小的1.5 倍,否则还没等文件打开,软件就挂了。

打开文件后,一眼就看到问题原因了

8930e8af1cc65883fb4ded583b0c5208.png

没错,就是它了,PreparedStatement,直接找到代码,发现每次循环处理结束后,PreparedStatement 没有关闭,只是在最后任务结束的时候把 Connection 关闭了。

这是一个很低级的错误,犯错的原因是:

1、工作中几乎没有过手动 JDBC 的使用,手生了

2、还是对这部分的底层原理不清楚,脑子里就知道 Connection 要关闭,没意识到 PreparedStatement 也必须要关闭。

原因找到了,问题也随之解决,但脑子里却冒出了更多的问号。

为什么 PreparedStatement 需要关闭?

为什么导致内存溢出的不是 ResultSet, 它也没关闭啊?

MySQL 对 PreparedStatement 的数量就没限制吗,可以一直创建?

……

我们下期接着讨论。

最后再引申出一个面试题:发生内存溢出后,服务还能正常访问吗?

扯两句

到什么时候也不能丢了基本功啊

过度关注业务逻辑可能会导致思路跑偏

原创不易,如有收获,一键三连,感谢支持!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值