java.net.SocketException:Too many open files 解决方案

472 阅读2分钟

1、查询原因

Linux对打开文件的数量有限制,使用如下命令查看到的最大文件数量是1024,命令如下:

ulimit -a

2、解决方案

一、第一步,修改配置

(1)方案一(临时方案)

使用命令修改可以打开的最大文件数,但是机器重启后,就会失效

ulimit -n 65535

(2)方案二

修改配置文件

在 /etc/security/limits.conf 文件的最后增加如下内容,重启机器即可。

# End of file
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535

(3)方案三

vim /etc/profile

加入一行:ulimit -n 65535

执行:source /etc/profile

再次查看:ulimit -a

二、查看应用进程的资源限制是否调整过来

1、查看当前进程的资源限制情况

cat /proc/进程Id/limits

image.png

如果没有调整过来可能要重启应用

再进行检查。

查看当前进程所打开的文件资源

lsof -p 进程Id | wc -l

image.png

2、如果不能重启应用,在 linux 中编辑/proc/pid/limits 文件

如果要修改core_file限制,可以输入

    prlimit --pid ${pid} --core=soft_limit:hard_limit

修改资源限制openfile

prlimit -p 30081 --nofile=10000:10500

prlimit 的帮助页面是:

Usage:
 prlimit [options] [-p PID]
 prlimit [options] COMMAND

General Options:
 -p, --pid <pid>        process id
 -o, --output <list>    define which output columns to use
     --noheadings       don't print headings
     --raw              use the raw output format
     --verbose          verbose output
 -h, --help             display this help and exit
 -V, --version          output version information and exit

Resources Options:
 -c, --core             maximum size of core files created
 -d, --data             maximum size of a process's data segment
 -e, --nice             maximum nice priority allowed to raise
 -f, --fsize            maximum size of files written by the process
 -i, --sigpending       maximum number of pending signals
 -l, --memlock          maximum size a process may lock into memory
 -m, --rss              maximum resident set size
 -n, --nofile           maximum number of open files
 -q, --msgqueue         maximum bytes in POSIX message queues
 -r, --rtprio           maximum real-time scheduling priority
 -s, --stack            maximum stack size
 -t, --cpu              maximum amount of CPU time in seconds
 -u, --nproc            maximum number of user processes
 -v, --as               size of virtual memory
 -x, --locks            maximum number of file locks
 -y, --rttime           CPU time in microseconds a process scheduled
                        under real-time scheduling

Available columns (for --output):
 DESCRIPTION  resource description
    RESOURCE  resource name
        SOFT  soft limit
        HARD  hard limit (ceiling)
       UNITS  units

For more details see prlimit(1).

3、理解ulimit

1、ulimit的管理的维度

理解ulimit,第一个疑问是限制的维度是什么。比如nofile设置为1024,是指当前用户总共只能打开1024个文件,还是单个shell会话进程只能打开1024个文件?** 实际上help ulimit里已经说清楚了:process,但我们可通过下面的方法程序验证:

下面通过一段java程序,打开800个文件:

@GetMapping("/ulimit")
public String testUlimit(int n) throws IOException {
    List<FileInputStream> fileList = new ArrayList<FileInputStream>();
    for(int i = 0; i< n; i++) {
        File temp = File.createTempFile("ulimit-test", ".txt");
        fileList.add(new FileInputStream(temp));
        System.out.println("file_seq=" + i + " " + temp.getAbsolutePath());
    }
    return "ok";
}

查看当前的 ulimit -n 的数字 1024

image.png

查看进程的资源限制

image.png

测试1:配置为1025个文件

curl http://127.0.0.1:8150/ulimit?n=1025

可以看出,的确是创建了 1025 个临时文件。

image.png

测试2:配置为4097个文件

curl http://127.0.0.1:8150/ulimit?n=4097

image.png

image.png

可以看出,打开的文件数为4067 的时候,就抛出了异常。

测试3:配置ulimit -n 为 65535 ,重启进程

  ulimit -n 65535
  java -jar ldemo-0.0.1-SNAPSHOT.jar

查看进程的资源限制

cat /proc/43980/limits

image.png

创建10000个临时文件 curl http://127.0.0.1:8150/ulimit?n=10000

image.png

测试4:先调小值,启动进程,再调大,发现进程资源限制未改变。 image.png

总结: ulimit 资源限制主要以当前进程的资源限制为主,直接调整 ulimit 值不会影响进程的资源限制,要重启进程才能生效。想要临时生效可以,进行 prlimit 对进程进行调整。

4、soft和hard的区分

  1. 无论何时,soft总是小于等于hard
  2. 无论是超过了soft还是hard,操作都会被拒绝。结合第一点,这句话等价于:超过了soft限制,操作会被拒绝。
  3. 一个process可以修改当前process的soft或hard。但修改需满足规则:
  • 修改后soft不能超过hard。也就是说soft增大时,不能超过hard;hard降低到比当前soft还小,那么soft也会随之降低。
  • 非root或root进程都可以将soft可以在[0-hard]的范围内任意增加或降低。
  • 非root进程可以降低hard,但不能增加hard。即nofile原来是1000,修改为了900,在修改为1000是不可能的。(这是一个单向的,有去无回的操作)
  • root进程可以任意修改hard值。

soft和hard在控制上其实并没有区别,都会限制资源的使用,但soft可以被进程在使用前自己修改

5、ulimit的修改与生效

知道ulimit很好,但更重要的是怎么修改,这是工作中常见的任务。

关于ulimit的生效,抓住几点即可:

  1. ulimit的值总是继承父进程的设置。
  2. ulimit命令可修改当前shell进程的设置。这也说明,为了保证下次生效,修改的地方要具有持久性(至少相当于目标进程而言),比如.bashrc,或进程的启动脚本)
  3. 从第2点也可以推出,运行中的进程,不受ulimit的修改影响。
  4. 增加hard值,只能通过root完成

6、其他

1、Java 自动将nofile的soft提升为hard上限

在研究的过程中,我发现java程序似乎不受nofile的soft值影响。查看进程的limits文件(/proc/$pid/limits),才发现nofile的soft被提升为和hard一样。经过全网搜索查询,发现JDK的实现中,会直接将nofile的soft先改成了和hard一样的值,可参考:How and when and where jvm change the max open files value of Linux?

2、file-max控制内核总共可以打开的文件数

除了ulimit控制外,/proc/sys/fs/file-max这个文件控制了系统内核可以打开的全部文件总数。所以,即便是ulimit里nofile设置为ulimited,也还是受限的。

3、ulimit常用选项

ulimit -a # 查看所有soft值
ulimit -Ha # 查看所有hard值
ulimit -Hn # 查看nofile的hard值
ulimit -Sn 1000 # 将nofile的soft值设置为1000
ulimit -n 1000 # 同时将nofiles的hard和soft值设置为1000

4、对于docker启动,这个限制会突破

image.png