5. [최적화2] Nginx 및 WebSocket 서버 설정 최적화
2025. 1. 24. 18:14ㆍTest/Artillery
728x90
1. 최적화가 필요한 이유
- 기본 설정의 한계: Nginx나 WebSocket 서버는 기본적으로 낮은 연결 제한과 짧은 타임아웃 값을 가짐
- 동시 연결 수가 많아질 경우 병목 현상 초래 가능
- 테스트 결과 분석
- WebSocket 에러 증가: 연결 타임아웃 또는 불완전한 메시지 전송이 원인일 수 있음
- 응답 시간 편차: 높은 P95/P99 응답 시간은 서버 자원의 과부하를 나타냄
2. 최적화 조치
(1) Nginx 연결 제한 및 이벤트 핸들링 최적화
Nginx가 동시에 처리할 수 있는 연결 수와 CPU 코어 활용도 설정
# Nginx 설정 파일 (예: /etc/nginx/nginx.conf)
worker_processes auto; # 사용 가능한 CPU 코어 수만큼 워커 생성 (t2.micro는 1개)
worker_connections 1024; # 워커당 최대 연결 수 설정
events {
use epoll; # Linux에서 효율적인 이벤트 처리
multi_accept on; # 한 번에 여러 연결을 수락
}
1. worker_processes: auto
기능
- worker_processes는 Nginx가 사용하는 워커 프로세스(Worker Process)의 수를 설정하는 옵션
auto
로 설정하면 Nginx는 사용 가능한 CPU 코어 수를 자동으로 감지하여 각 코어당 하나의 워커 프로세스를 생성
왜 사용하는가?
- 멀티코어 활용 최적화
auto
는 서버의 CPU 코어 수에 맞게 워커 프로세스를 자동으로 할당하여 모든 코어를 효율적으로 활용- 예: t2.micro는 단일 vCPU로 동작하므로,
auto
는 워커 프로세스를 1개로 설정
- 수동 설정 불필요
- 워커 프로세스 수를 수동으로 지정하지 않아도 되므로, 환경 변화에 유연하게 대응
- 부하 분산
- 여러 워커 프로세스가 클라이언트 요청을 병렬로 처리하여 응답 시간을 줄여 성능 향상
주의사항
- 워커 프로세스의 수를 CPU 코어 수보다 높게 설정하면 성능이 저하 가능
- t2.micro처럼 리소스가 제한된 환경에서는
auto
가 1로 설정되므로 추가 조정이 필요하지 않음
설정 예시
worker_processes auto; # CPU 코어 수에 따라 자동 설정
worker_connections: 1024
기능
- worker_connections는 각 워커 프로세스가 동시에 처리할 수 있는 최대 연결 수를 설정
- 기본적으로 한 워커 프로세스는 설정된 수만큼 동시 연결을 처리 가능
왜 사용하는가?
- 동시 연결 처리량 증가
- WebSocket이나 HTTP 요청과 같은 동시 연결이 많은 경우, 충분한 연결 수를 설정해야 병목 현상이 발생하지 않음
- 예:
1024
는 워커 프로세스당 1024개의 동시 연결을 허용합니다. CPU 코어가 1개인 t2.micro에서는 총 1024개의 연결을 처리 가능 - 1,024개의 연결은 안정성과 성능 간의 균형 유지(default 768 → 1024)
- 총 연결 수 =
worker_processes * worker_connections
이므로, 1 vCPU에서 최대 1,024개의 동시 연결을 처리 가능 - 너무 높은 값 : 리소스 초과로 인해 CPU 및 메모리 부족 현상이 발생 가능
- 너무 낮은 값 : 동시 연결 수가 제한되어 클라이언트가 연결 실패를 경험할 가능성 증가
- 실제 활용 사례
- WebSocket 서버처럼 다수의 클라이언트가 지속적으로 연결을 유지하는 경우, 높은 연결 수 필요
- ulimit과 연관
- 시스템의 파일 디스크립터 제한(ulimit)을 초과하지 않도록 조정필요
ulimit -n
명령으로 현재 파일 디스크립터 제한을 확인한 후, 필요에 따라/etc/security/limits.conf
에서 값을 증가
주의사항
- 너무 높은 값으로 설정하면 메모리 사용량이 증가
- t2.micro에서는 메모리가 제한적이므로
1024
가 적절한 기본값
설정 예시
worker_connections 1024; # 워커 프로세스당 최대 연결 수
epoll 활성화
기능
- epoll은 Linux 환경에서 비동기 이벤트를 효율적으로 처리하기 위한 메커니즘
- Nginx는 기본적으로 이벤트 모델로
select
나poll
을 사용할 수 있지만, epoll은 대규모 동시 연결 처리에 최적화
왜 사용하는가?
- 고성능 이벤트 처리
- WebSocket 서버처럼 동시 연결 수가 많은 환경에서 epoll은 비동기 이벤트 처리를 통해 성능을 극대화
- epoll은 이벤트 기반으로 작동하므로, 새로운 데이터가 들어오거나 처리가 필요할 때만 작업을 수행
- CPU 자원 절약
select
나poll
과 달리 모든 연결을 순차적으로 검사하지 않고, 이벤트가 발생한 연결만 처리하므로 CPU 사용량 감소
- 대규모 동시 연결 지원
- epoll은 수천 개의 동시 연결을 효율적으로 관리할 수 있어 WebSocket 서버와 같은 환경에 적합
주의사항
- epoll은 Linux에서만 작동. Windows 환경에서는 다른 이벤트 모델을 사용
- epoll을 활성화하면
multi_accept on;
설정과 함께 사용하는 것이 좋음
multi_accept on
기능
- 하나의 이벤트 루프에서 들어오는 모든 연결 요청을 한 번에 수락
- 기본 동작: 기본적으로 Nginx는 각 연결 요청을 한 번에 하나씩 처리
- 효과:
multi_accept on;
을 활성화하면, Nginx는 대기열에 있는 모든 연결 요청을 즉시 수락할
왜 multi_accept on;
을 사용하는가?
- 고성능 환경에 적합
- 동시에 많은 연결 요청이 들어오는 환경(예: WebSocket 서버)에서 효율성을 극대화
- 단일 연결 처리보다 대기열 전체를 한 번에 처리하면 응답 시간 감소
- 부하 테스트 및 실시간 서비스에 유리
- 부하 테스트에서 동시 연결 수가 많을 경우, 빠른 수락을 통해 병목 현상 완화
- WebSocket과 같은 실시간 연결이 중요한 애플리케이션에 특히 적합
- epoll과 시너지 효과
use epoll
과 함께 사용하면, Linux의 비동기 이벤트 처리를 최대한 활용 가능- epoll은 대규모 동시 연결을 처리하는 데 최적화되어 있으므로,
multi_accept on;
설정과 조합하면 더 높은 처리량을 제공
주의사항 및 한계
- CPU 사용량 증가
- 모든 연결을 즉시 수락하기 때문에, CPU 사용량이 약간 증가
- 특히 리소스가 제한적인 서버(t2.micro)에서는 성능을 면밀히 모니터링 필요
- 적합한 환경에서 사용
- 트래픽이 낮거나 동시 연결 수가 적은 서버에서는 큰 효과를 보지 못할 수 있음
- 이러한 환경에서는 오히려 리소스를 낭비할 가능성 존재
설정 방법
epoll과 multi_accept on;
을 활성화한 Nginx 설정 예시
events {
use epoll; # Linux 환경에서 효율적인 비동기 이벤트 처리
multi_accept on; # 가능한 모든 연결을 즉시 수락
worker_connections 1024; # 워커 프로세스당 최대 연결 수
}
최적화된 사용 사례
- WebSocket 서버
- 실시간 데이터를 처리해야 하는 WebSocket 애플리케이션에 적합
- 클라이언트가 지속적으로 연결을 유지하므로 빠르게 연결을 수락하는 것이 중요
- 부하 테스트 환경
- 동시 연결 수를 테스트하고 병목 현상을 발견하는 데 유용
(2) WebSocket 타임아웃 값 조정
기본 타임아웃 값은 짧아 장기 연결이 필요한 WebSocket에 부적합
# Nginx에서 WebSocket 타임아웃 설정
proxy_connect_timeout 60s; # 연결 시도 제한 시간 (기본값: 30초)
proxy_read_timeout 60s; # 클라이언트에서 메시지 읽기 제한 시간
proxy_send_timeout 60s; # 서버에서 메시지 전송 제한 시간
keepalive_timeout 75s; # 연결을 유지하는 시간
proxy_connect_timeout: 60s
- 설명
- Nginx가 업스트림 서버(예: WebSocket 백엔드)로 연결을 설정할 때 기다리는 최대 시간 설정
- 값 선정 이유
- 네트워크 지연
- 트래픽이 많거나 네트워크 대역폭이 낮은 상황에서 기본 값(보통 10초)이 너무 짧아 연결 실패가 빈번히 발생 가능
- 60초 설정
- 충분한 연결 시간을 보장하며, 지연 시간이 길어질 가능성이 있는 상황 대비
- 네트워크 지연
proxy_read_timeout: 60s
- 설명
- 업스트림 서버에서 데이터를 읽을 때의 최대 대기 시간 설정
- 값 선정 이유
- WebSocket 특성
- 실시간 앱에서 WebSocket은 메시지 교환 사이에 빈번히 idle 상태
- 60초 설정
- 짧은 타임아웃(예: 10초)은 불필요한 연결 종료 초래
- 60초는 idle 상태에서도 연결을 유지하며 클라이언트 경험을 개선
- WebSocket 특성
proxy_send_timeout: 60s
- 설명
- 업스트림 서버로 데이터를 보낼 때의 최대 대기 시간 설정
- 값 선정 이유
- 대용량 데이터 전송
- 메시지 크기가 크거나 네트워크 상태가 느린 경우 더 긴 시간 동안 데이터를 보낼 수 있도록 지원
- 60초 설정
- 안정적인 데이터 전송을 보장
- 대용량 데이터 전송
keepalive_timeout: 75s
- 설명
- Nginx가 클라이언트와의 유휴 연결을 유지하는 최대 시간을 설정
- 값 선정 이유:
- WebSocket 연결 특성
- 연결을 자주 닫으면 WebSocket 세션이 자주 재연결되며, 추가적인 오버헤드가 발생
- 75초 설정
- 너무 긴 값은 리소스 낭비를 초래할 수 있고, 너무 짧은 값은 불필요한 연결 해제 유발
- 75초는 연결 유지와 자원 효율성을 모두 고려한 최적값
- WebSocket 연결 특성
- 적용 이유
- WebSocket은 연결이 끊어지면 다시 연결해야 하므로 타임아웃을 늘려야 함
proxy_connect_timeout
은 클라이언트의 연결 시도가 실패하지 않도록 시간을 확보keepalive_timeout
은 재연결 없이 연결 유지
(3) Keep-Alive 활성화
WebSocket과 같은 지속적인 연결을 유지하기 위해 Keep-Alive를 활성화합니다.
http {
keepalive_timeout 75s; # Keep-Alive 연결 유지 시간
keepalive_requests 100; # 한 Keep-Alive 연결당 처리할 최대 요청 수
}
- 적용 이유:
- 클라이언트와의 지속적인 연결을 통해 재연결 오버헤드를 줄임.
- 서버와 클라이언트 간 효율적인 리소스 사용 가능.
3. Nginx와 WebSocket 최적화의 장점
- 동시 연결 처리량 증가
worker_connections
와worker_processes
설정을 통해 더 많은 연결 처리 가능
- 연결 안정성 향상
- 타임아웃 시간을 늘려 장기적인 WebSocket 연결 유지
- 리소스 효율성 개선
- Keep-Alive와 epoll 사용으로 서버 리소스 효율성을 극대화
5. 최적화된 설정 적용 요약
- Nginx 설정 파일 경로:
/etc/nginx/nginx.conf
- 적용 후 테스트
- PM2 및 WebSocket 서버와 함께 사용하여 성능 및 안정성 확인
- 로드 테스트를 통해 설정 값 미세 조정
4. 결과
1. Nginx 설정 변경 전후 성능 요약
Nginx의 WebSocket 및 Keep-Alive 설정을 최적화한 후 성능 변화가 관찰
주요 변경 사항
proxy_connect_timeout
,proxy_read_timeout
,proxy_send_timeout
: 타임아웃 값을 30초에서 60초로 증가keepalive_timeout
: 60초에서 75초로 증가worker_connections
: 1024로 설정epoll
및multi_accept
활성화: 대규모 동시 연결 처리 최적화
2. 설정 변경에 따른 성능 비교
항목 | 변경 전 결과 | 변경 후 결과 |
---|---|---|
총 처리 시간 | 3분 9초 | 3분 24초 |
WebSocket 에러 | 61건 | 30건 |
socketio.emit 요청 수 | 798 | 768 |
socketio.emit 속도 | 6/sec | 4/sec |
응답 시간 (ms) | ||
- 최소 | 0.1 | 0.1 |
- 최대 | 68.5 | 52.3 |
- 평균 | 0.6 | 0.4 |
- 95th 퍼센타일(p95) | 1.2 | 0.6 |
- 99th 퍼센타일(p99) | 3.5 | 1.3 |
vusers.failed | 132 | 162 |
세션 길이 (ms) | ||
- 최소 | 2327.7 | 4548.5 |
- 최대 | 37986.6 | 60109 |
- 평균 | 18183 | 31692 |
- 95th 퍼센타일(p95) | 36691.5 | 58122.9 |
- 99th 퍼센타일(p99) | 37432.7 | 59297.1 |
3. 주요 개선점
- WebSocket 에러 감소
- 변경 전 61건 → 변경 후 30건으로 50% 이상 감소
- 이유: 타임아웃 설정을 늘려 서버가 과도한 연결 해제를 방지
- 응답 시간 안정화
- 최대 응답 시간 감소: 68.5ms → 52.3ms
- 평균 응답 시간 개선: 0.6ms → 0.4ms
- 이유:
epoll
및multi_accept
를 통해 동시 연결 처리가 효율적으로 개선
- 세션 길이 증가
- 평균 세션 길이가 약 75% 증가 (18183ms → 31692ms)
- 이유:
keepalive_timeout
설정이 연결을 유지하며 세션 효율성을 높임
- CPU와 메모리 부하 안정화
- 변경 후 처리 시간이 소폭 증가했지만, Nginx가 효율적으로 부하를 분산
4. Nginx 최적화 설정
Nginx 설정 파일 (nginx.conf
)
events {
worker_connections 1024; # 동시 연결 수
use epoll; # Linux에서 효율적인 이벤트 처리
multi_accept on; # 모든 연결을 동시에 수락
}
http {
proxy_connect_timeout 60s; # 연결 시도 제한 시간
proxy_read_timeout 60s; # 메시지 읽기 제한 시간
proxy_send_timeout 60s; # 메시지 쓰기 제한 시간
keepalive_timeout 75s; # Keep-Alive 연결 유지 시간
}
5. 설정 변경의 의미
proxy_connect_timeout 60s
- 연결 설정 지연을 방지하기 위해 시간을 늘림
- 네트워크 지연 환경에서 서버 연결 안정성을 향상
proxy_read_timeout 60s
,proxy_send_timeout 60s
- 클라이언트/서버 간 메시지 전송 및 읽기 안정성 강화
- WebSocket에서 긴 데이터 전송 시 연결 끊김 방지
keepalive_timeout 75s
- 세션 연결을 유지하여 클라이언트의 재접속 빈도를 줄임
- 연결 유지로 인해 불필요한 자원 소비 감소
worker_connections 1024
- 동시 연결 수를 최대 1024로 설정해 서버 처리 용량 향상
use epoll
- Linux 전용 고성능 I/O 처리 메커니즘
- 대규모 동시 연결 처리에 적합
multi_accept on
- 가능한 모든 연결을 즉시 수락하여 연결 처리 속도 증가
5. 결론
Nginx 설정 최적화를 통해
- WebSocket 에러가 감소하고 응답 시간이 안정화
- 클라이언트의 세션 유지 시간이 증가하며 사용자 경험이 개선
- Nginx의 고성능 설정을 통해 서버의 처리 용량과 안정성을 대폭 향상
- 조사를 통해 나름의 최적값을 설정했지만 운영시 환경과 사용자의 이용 패턴에 따라 최적값이 다를 수 있어 운영시 추가적 데이터 분석 필요
- ulimit와 PAM 설정은 글이 길어져 다음 글에서 다룰 예정
Reference
'Test > Artillery' 카테고리의 다른 글
7. [최적화4] 불필요한 서비스 비활성화 및 최적화 결과 (0) | 2025.01.25 |
---|---|
6. [최적화3] ulimit와 PAM 설정을 통한 테스트 환경 최적화 (0) | 2025.01.24 |
4. [최적화 1] Node.js 프로세스 최적화 (0) | 2025.01.24 |
3. AWS EC2 t2.micro 환경에서 WebSocket 타임아웃 문제 (0) | 2025.01.16 |
2. Artillery를 활용한 Socket.IO 기반 채팅 서비스 부하 테스트: Local vs EC2 환경 성능 비교 및 분석 (0) | 2025.01.14 |