반응형

open files

  • open files는 파일을 열 수 있는(file descriptor를 생성할 수 있는) 최대값을 말함
  • ulimit 명령으로 확인할 수 있음
  • 파일 뿐만 아니라 소켓, 커넥션 생성시에도 file descriptor가 생성됨
  • 따라서 과도하게 커넥션이 생성됐는지 확인이 필요하면 해당 프로세스의 file descriptor가 많이 생성되었는지 확인하면 됨

현재의 open files 확인

ubuntu@ubuntu-server:~$ ulimit -a | grep files
open files                      (-n) 1024
ubuntu@ubuntu-server:~$ ulimit -aH | grep files
open files                      (-n) 1048576

테스트를 위해 open files 낮추기

sudo vi /etc/security/limits.conf
*               soft    nofile           1024
*               hard    nofile           4096

재접속 후 open files 다시 확인

ubuntu@ubuntu-server:~$ ulimit -a | grep files
open files                      (-n) 1024
ubuntu@ubuntu-server:~$ ulimit -aH | grep files
open files                      (-n) 4096

api-example.jar 생성

@RestController
public class TestController {
    @GetMapping("/api/makeConnections/{connectionCount}")
    public String makeConnections(@PathVariable("connectionCount") int connectionCount) {
        for (int i = 0; i < connectionCount; i++) {
            int index = i;
            new Thread(() -> {
                RestTemplate restTemplate = new RestTemplateBuilder()
                    .setConnectTimeout(Duration.ofMinutes(30))
                    .setReadTimeout(Duration.ofMinutes(30))
                    .build();

                String response = restTemplate.getForObject("http://localhost:8080/api/hang/" + index, String.class);
                System.out.println("response : " + response);
            }).start();
        }
        return "OK";
    }

    @GetMapping("/api/hang/{index}")
    public String hang(@PathVariable("index") int index) throws InterruptedException {
        System.out.println("hang : " + index);
        Thread.sleep(20 * 60 * 1000);

        return "hang : " + index;
    }
}

api-example.jar 실행

java -jar api-example.jar

api-example.jar에서 사용중인 file descriptor 수 확인

ubuntu@ubuntu-server:~$ jps
14566 Jps
14343 api-example.jar
ubuntu@ubuntu-server:~$ ls -l /proc/14343/fd | wc -l
17

open files보다 많은 커넥션 생성 유발해보기

  • connection 요청하는 컨트롤러와 요청을 받는 컨트롤러가 같은 서버에 있으므로 2100개의 커넥션 생설 요청시 4200개의 커넥션을 생성하게됨
curl localhost:8080/api/makeConnections/2100
2020-07-19 13:44:09.813 ERROR 16914 --- [o-8080-Acceptor] org.apache.tomcat.util.net.Acceptor      : Socket accept failed

java.io.IOException: Too many open files
	at java.base/sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) ~[na:na]
	at java.base/sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:533) ~[na:na]
	at java.base/sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:285) ~[na:na]
	at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:469) ~[tomcat-embed-core-9.0.36.jar!/:9.0.36]
	at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:71) ~[tomcat-embed-core-9.0.36.jar!/:9.0.36]
	at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:95) ~[tomcat-embed-core-9.0.36.jar!/:9.0.36]
	at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

file descriptor 수 다시 확인

  • open files가 soft type은 1024, hard type은 4096으로 설정되어 있음
  • 아래 내용을 확인해보면 hard type 값에 의해 제한된 것으로 보임
ubuntu@ubuntu-server:~$ ls -l /proc/14343/fd | wc -l
4097

java의 MaxFDLimit 설정 확인

ubuntu@ubuntu-server:~$ java -XX:+PrintFlagsFinal -version | grep MaxFDLimit
     bool MaxFDLimit                               = true                                      {product} {default}

결론

  • 위와 같은 오류 발생시 과도하게 커넥션이 생성되어있지 않은지 해당 프로세스의 file descriptor 수 확인
  • open files가 낮게 잡혀있지 않은지 ulimit 명령어로 확인
  • 너무 낮게 잡혀있을 경우 limits.conf 파일의 nofile 값을 적절하게 조절하여 이슈 해결

참고

반응형

+ Recent posts