背景
向友商采买数据,使用友商提供的sdk上传原始文件过去(串行),友商处理好会把结果文件下载链接返回回来
问题发现
向友商发送原始数据1.5h之后发现机器磁盘使用率增长明显不正常,于是开始查找原因;
- 排查发现日志文件增量明显没有那么大的体积
- 使用 du -h --max-depth=1 /home 命令查看没有发现异常
- 怀疑是下载到本地的原始文件没有删除导致,查看本地文件路径发现文件夹内没有文件
- 紧急拉运维同学查看后,lsof |grep deleted 发现存在45多个处于 deleted状态的删除文件进程卡在那里,定位到文件删除磁盘未释放
问题原因
这种java僵尸进程导致磁盘占用不断升高大概率是文件删除时文件流没有释放导致的。
排查到未关闭的文件流是引入了友商的SDK导致的,我们是以代码的方式引入的SDK,所以修复一下友商的SDK,重新发版断点重试就好了
容易忽视的文件流操作
友商的SDK中大部分文件流操作使用try with resource方式,都是会自动关闭流的,我们开始怀疑是不是同时存在try with resource以及手动关闭文件流方式,文件流关闭顺序导致文件流关闭失败,确认后发现并不是。(先释放try with resource内的文件流,再释放finally的文件流 )
最后发现有两行代码:
Files.lines(file).count();
Files.list(path).filter(Files::isRegularFile)
.filter(t -> t.toString().endsWith(".csv"))
.map(Path::toAbsolutePath)
.collect(Collectors.toList());
其中Files.lines方法和Files.list(path)方法都操作了文件流,但是没有释放
**注意:**Files.lines方法和Files.list(path)等Files类操作文件流的方法一定要关闭!!!