1、出现的异常:
org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.lang.RuntimeException: java.nio.file.FileSystemException: /tmp/under
tow.8010.1478329548365288688/undertow2121540793228791585upload: Too many open files
2、查看句柄数,修改句柄数:
大约在2022-03-18进行压测时出现的一个问题,就是在进行压力测试一段时间后,会不断的出现文件上传失败的问题,查看日志后出现的异常如上面所示。
问题出现后,第一时间在网上查找了相关文章,出现的解决方案不外呼添加open files的句柄数,
ulimit -a 查看句柄数
ulimit -n 65535 修改打开的句柄数
当然你系统重启后就又会变为1024了,那么怎么永久进行修改呢?
将ulimit 值添加到/etc/profile文件中(适用于有root权限登录的系统)
为了每次系统重新启动时,都可以获取更大的ulimit值,将ulimit 加入到/etc/profile 文件底部。
echo ulimit -n 65535 >>/etc/profile
source /etc/profile #加载修改后的profile
ulimit -n #显示65535,修改完毕!
到此为止,你以为大功告成了么,其实不然,突然发现自己再次登录进来的时候,ulimit的值还是1024,这是为什么呢? 用户登录的时候执行sh脚本的顺序:
/etc/profile.d/file
/etc/profile
/etc/bashrc
/mingjie/.bashrc
/mingjie/.bash_profile
由于ulimit -n的脚本命令加载在第二部分,用户登录时由于权限原因在第二步还不能完成ulimit的修改,所以ulimit的值还是系统默认的1024。所以想彻底改变这种问题,就必须做如下操作:修改/etc/security/limits.conf
里面有很详细的注释,比如
* soft nofile 2048
* hard nofile 32768
就可以将文件句柄限制统一改成软2048,硬32768
那么什么是软限制,什么是硬限制
硬限制是实际的限制,而软限制,是warnning限制,只会做出warning
这样就实实际际的增大了文件句柄数。
3、查看各个进程已经使用的句柄数:
(1)统计各进程打开句柄数:lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr
如图:
(2)统计各用户打开句柄数:lsof -n|awk '{print $3}'|sort|uniq -c|sort -nr
如图:
(3)统计各命令打开句柄数:lsof -n|awk '{print $1}'|sort|uniq -c|sort -nr
如图:
注:yum install lsof (出现lsof未找到命令时可使用该命令进行安装)
4、在测试的过程中排查使用lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr进行查看使用的句柄数,定位到哪一个进程,
在压测的过程中发现它的数值会稳步上升,当句柄数达到最大可用的句柄数时就会出现Too many open files的异常,
5、解决:
从上述2中我们可以发现我们对open files 的最大句柄数进行修改即可,
然而这种方法是治标不治本的,因为,随着压测的进行它句柄数总会达到这一个最大的值。
那么要怎么治本呢?
我们先从原因开始说起,出现句柄数一直上升的原因无外乎,“流”没有关闭。
所以对症下药,从我们进行的业务,是将文件上传到oss,
在上传时会用到springboot的
MultipartFile类进行文件的上传,然后转化为输入流上传到oss中,
file.getInputStream(),
然而我们使用了输入流后没有进行关闭导致句柄数一直在增加,最后抛出了异常。
修改:
try (InputStream in = file.getInputStream()) {
return putFile(bucketName, fileName, in);
} catch (IOException e) {
e.printStackTrace();
}
return null;
通过jdk7提供的try-with-resource即可自动关闭流。问题解决,之后测试发现句柄数能够保持在某一稳定的值上。
总结:涉及到“流”的地方,打开了一定要关闭,因为常规的测试根本无法测试到这种问题,当上线到生产时,随着业务的增长,
句柄数就会达到某一个最大值,从而导致异常的发现
参考文章: