Elasticsearch를 처음 설치하다 보면 항상 보는 에러들이 몇 가지 있습니다.
1) root 계정으로 실행할 수 없으며
2) openfiles, max process 값을 수정해야하고
3) swappiness 값 설정 변경 요청도 있습니다.
그 중에 elasticsearch는 openfiles와 max process는 최소 65535로 설정하라며, 커널에서 해주는 기본 설정보다 큰 값을 요구하는데요,
오늘은 해당 파라미터가 정확히 어떤 것을 가르키는지 그리고 설정된 값 이상이 되면 어떤 일이 일어나는지 알아보겠습니다.
1. Max user processes
Max user processes의 의미는 하나의 계정에서 최대로 실행할 수 있는 process의 개수를 말합니다. OS에서의 확인은
# ulimit -a (sofe ulimit)
# ulimit -aH (hard ulimit)
위 명령으로 확인 가능합니다. (현재 제 서버의 설정 값은 아래와 같습니다.)
그럼 아래 테스트 코드를 통해 설정된 max user processes의 값을 넘기면 어떻게 되는지 확인해보겠습니다.
대략적인 코드의 내용은 HTTP 요청이 오면 비동기로 4천개의 Thread를 동시에 생성하고 20분간 유지하는 코드입니다.
그리고 실제로 Thread를 늘려보면,
그림처럼 ulimit -a 명령의 max user processes 결과와 같이 ec2-user 계정은 1024개까지 스레드를 생성한 후, OOM 에러 메세지를 발생하며 멈춰버리게 됩니다. (이 경우 ec2-user 계정에서는 쉘 명령어 입력 등 어떤 작업도 동작하지 않습니다.)
<리눅스에서는 스레드와 프로세스를 동일하게 봅니다.>
2. Open files
다음은 Open files입니다. 이 값은 프로세스가 가질 수 있는 최대 파일의 개수를 의미합니다.
리눅스는 모든 프로세스나 세션(소켓)들을 파일로 관리하기 때문에 이 값의 설정은 서버에서의 Connection연결 작업에 매우 중요한 내용이 됩니다.
(설정 값을 넘어가게 되면 리눅스에서 파일을 열 수 없어 프로세스 실행이나 Connection 연결이 안되기 때문!)
그럼 소켓을 open files 값 보다 많이 만들어 테스트를 해보겠습니다.
(1) Java 환경 TEST
- RestTemplate로 소켓 생성 요청을 보내고, 요청을 받은 서버에서 20분간 응답을 대기 시킵니다.
- 요청을 동시에 1100개를 보내 open files가 1024로 제한인 서버에 에러가 발생하면 테스트 성공입니다.
(기본적으로 java, spring 관련 file이 몇 개 오픈됩니다.)
아래는 테스트 코드 일부입니다.
그리고 동시에 요청을 보낼 API 요청 스크립트를 작성합니다.
쉘을 실행하여 테스트를 진행하면…
위 그림처럼 소켓이 1024개가 넘어도 에러 메시지 없이 동작하는 것을 볼 수 있습니다. 그럼 한번 더 스크립트를 실행해보겠습니다.
이제 에러가 발생했습니다. 파일은 딱 2048개 까지만 열린 것을 확인할 수 있는데요, openfiles의 값은 soft로 설정된 값이 아닌
그림처럼 Hard 옵션 값까지 file이 생성된다는 것을 알 수 있습니다.
그런데…! 알고 보니 java 환경에서는 hard 값을 따라가는게 맞지만 Python에서는 아니라고 합니다…
(2) Python 환경 TEST
위 처럼 파이썬 스크립트로 file을 임의로 열어봅니다. 1021개 까지는 파일이 문제없이 열리지만(stdin, stdout, stderr 표준 입/출력 3개 제외)
이후로 여는 파일에서는 Too many open files 에러가 발생합니다!
(3) Java와 Python 환경의 차이?
테스트 결과 Java는 hard 옵션까지 파일이 오픈되고 Python은 soft 값까지 오픈됨을 알 수 있었습니다. 그 이유를 찾기 위해 strace 명령을 통해 java 프로세스 동작을 추적해보면
위 그림처럼 java 프로세스가 시작됨과 동시에 prlimit64라는 함수가 rlim_cur=1024값을 rlim_max=2*1024(hard limit) 값까지 업데이트하는 로그가 찍혀있는 것을 볼 수 있었습니다.
그 이유는 설치된 JVM에서 MaxFDLimit 옵션을 통해 limit을 올려주었기 때문이라고 합니다! (기본적으로 활성화된 옵션)
즉, 리눅스 OS에서는 JDK 실행 시 커널에서 prlimit64 함수를 통해 자동으로 limit 사이즈를 증가시켜준다는 것을 알 수 있었습니다.
3. 정리
- (Linux 환경) JAVA에서 동시에 생성 가능한 쓰레드 수는 Max user processes를 따라간다.
- (Linux 환경) JAVA에서 소켓 통신(API나 모든 Connection)은 open files 옵션을 따라간다.
-> JAVA에서는 JDK 코드에서 자동으로 soft limit값은 hard limit값까지 업데이트 됨
-> Python은 soft limit 값에서 제한이 걸림
나의 개발 환경에 맞게, Max user processes와 open files의 적절한 값을 찾아 설정하는 것이 중요하겠습니다!
<참조>
'Operating System' 카테고리의 다른 글
SSL 통신과 인증서 검증 (0) | 2024.08.21 |
---|---|
[Kubernetes] Container Runtime (0) | 2022.01.26 |
[Linux] 메모리 재할당 (0) | 2022.01.10 |
[Linux] TCP KeepAlive에 대한 고찰 (0) | 2021.12.13 |