背景:前段时间,使用SpringBoot+easyexcel做了一个文件导入的功能。这个功能是给业务方导入黑名单的,使用频率比较低,大概一个月一次,但是逻辑复杂,涉及设备佣金结算,所以测试同学进行过严格的测试,导入时服务器各项参数正常。上线之后,业务方成功导入存量数据,但是过半个月左右,业务方再次导入新增数据时,出现服务器异常。
上篇博客记录过文件导入的实现技术,本篇博客主要记录一下排查问题全过程。
一、文件格式以及服务器检查
- 业务方在对接群中突然反馈,导入功能不可用,并且发了下面这个截图;
- 接到反馈以后,我首先让他们把需要导入的文件发给我看了一下,因为我怀疑是文件格式或者文件内容有问题,因为我们只支持xlsx\xls\csv格式的文件,并且对文件内容做了限制,我在测试、beta、生产环境分别做了尝试,都无法导入,也就是说三个环境同时出现异常;
- 这时,已经基本可以确定不是服务器挂掉或者是文件的问题;
二、排查日志
- 在我确定服务器和文件都没问题以后,我们去查看了服务器日志,发现日志有这样一行报错:The temporary upload location [/tmp/tomcat.135042057.80/work/Tomcat/localhost/ROOT] is not valid
- 知道错误日志以后,问题就简单了起来;
三、问题原因
- 在linux系统中,springboot应用服务在启动(java -jar 命令启动服务)的时候,会在操作系统的/tmp目录下生成一个tomcat*的文件目录,如下;
-
hsperfdata_root
-
tomcat.************.8080,(结尾为端口)
-
tomcat-docbase.*********.8080 ;
- 直接上传的文件先要转换成临时文件保存在这个文件夹下面;
- 由于临时/tmp目录下的文件,在长时间(10天)没有使用的情况下,就会被系统机制自动删除掉。所以如果这个临时文件长时间无人问津也就是这个导入功能长时间无人使用的话,就可能导致上面这个问题。
-
解释: /tmp文件夹的有自动cleanup机制,/tmp文件夹的文件10天未更新会被移除,/var/tmp文件夹的文件是30天。
四、解决方案
- 重启项目;
-
为了快速解决问题,让业务方可以使用功能,也是为了测试这个方法可不可用,我重启了beta环境服务器,果然导入功能恢复正常;
-
做为临时方案是可行的,但是没有从根本解决问题;
- 配置文件自定义临时文件路径;
-
server.tomcat.basedir=/home/dev/temp
-
重启项目生效 ;
-
如果启动项目的用户有权限在该目录下创建文件夹,则会自动创建;如果没有权限,需要手动创建 ;
- 配置类方式指定临时文件路径 ;
-
这个方法的本质其实是和配置文件一样的
@Configuration
public class MultipartConfig {
/**
* 文件上传临时路径
*/
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
String location = System.getProperty("user.dir") + "/dev/temp";
File tmpFile = new File(location);
if (!tmpFile.exists()) {
tmpFile.mkdirs();
}
factory.setLocation(location);
return factory.createMultipartConfig();
}
}
四、总结
总结:
1.导入文件本身是一个非常常见且简单的需求,但是因为之前没有做过,没有踩过这个坑,所以出现了这次线上事故,所以经验很重要,不要忽视任何一点细节;
2.导入文件其实是比较消耗内存的,操作不当很容易出现OOM,所以导入文件大小需要做好限制,导入技术选型也很重要;
3.直接使用SpringBoot导入会在服务器上创建临时文件夹,并且对服务器性能有影响,所以建议使用OSS等第三方文件存储服务器做文件暂存,减轻服务器压力;