5. [최적화2] Nginx 및 WebSocket 서버 설정 최적화

2025. 1. 24. 18:14Test/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 코어 수를 자동으로 감지하여 각 코어당 하나의 워커 프로세스를 생성

왜 사용하는가?

  1. 멀티코어 활용 최적화
    • auto는 서버의 CPU 코어 수에 맞게 워커 프로세스를 자동으로 할당하여 모든 코어를 효율적으로 활용
    • 예: t2.micro는 단일 vCPU로 동작하므로, auto는 워커 프로세스를 1개로 설정
  2. 수동 설정 불필요
    • 워커 프로세스 수를 수동으로 지정하지 않아도 되므로, 환경 변화에 유연하게 대응
  3. 부하 분산
    • 여러 워커 프로세스가 클라이언트 요청을 병렬로 처리하여 응답 시간을 줄여 성능 향상

주의사항

  • 워커 프로세스의 수를 CPU 코어 수보다 높게 설정하면 성능이 저하 가능
  • t2.micro처럼 리소스가 제한된 환경에서는 auto가 1로 설정되므로 추가 조정이 필요하지 않음

설정 예시

worker_processes auto;  # CPU 코어 수에 따라 자동 설정

worker_connections: 1024

기능

  • worker_connections는 각 워커 프로세스가 동시에 처리할 수 있는 최대 연결 수를 설정
  • 기본적으로 한 워커 프로세스는 설정된 수만큼 동시 연결을 처리 가능

왜 사용하는가?

  1. 동시 연결 처리량 증가
    • WebSocket이나 HTTP 요청과 같은 동시 연결이 많은 경우, 충분한 연결 수를 설정해야 병목 현상이 발생하지 않음
    • 예: 1024는 워커 프로세스당 1024개의 동시 연결을 허용합니다. CPU 코어가 1개인 t2.micro에서는 총 1024개의 연결을 처리 가능
    • 1,024개의 연결은 안정성과 성능 간의 균형 유지(default 768 → 1024)
    • 총 연결 수 = worker_processes * worker_connections 이므로, 1 vCPU에서 최대 1,024개의 동시 연결을 처리 가능
    • 너무 높은 값 : 리소스 초과로 인해 CPU 및 메모리 부족 현상이 발생 가능
    • 너무 낮은 값 : 동시 연결 수가 제한되어 클라이언트가 연결 실패를 경험할 가능성 증가
  2. 실제 활용 사례
    • WebSocket 서버처럼 다수의 클라이언트가 지속적으로 연결을 유지하는 경우, 높은 연결 수 필요
  3. ulimit과 연관
    • 시스템의 파일 디스크립터 제한(ulimit)을 초과하지 않도록 조정필요
    • ulimit -n 명령으로 현재 파일 디스크립터 제한을 확인한 후, 필요에 따라 /etc/security/limits.conf에서 값을 증가

주의사항

  • 너무 높은 값으로 설정하면 메모리 사용량이 증가
  • t2.micro에서는 메모리가 제한적이므로 1024가 적절한 기본값

설정 예시

worker_connections 1024;  # 워커 프로세스당 최대 연결 수

epoll 활성화

기능

  • epoll은 Linux 환경에서 비동기 이벤트를 효율적으로 처리하기 위한 메커니즘
  • Nginx는 기본적으로 이벤트 모델로 selectpoll을 사용할 수 있지만, epoll은 대규모 동시 연결 처리에 최적화

왜 사용하는가?

  1. 고성능 이벤트 처리
    • WebSocket 서버처럼 동시 연결 수가 많은 환경에서 epoll은 비동기 이벤트 처리를 통해 성능을 극대화
    • epoll은 이벤트 기반으로 작동하므로, 새로운 데이터가 들어오거나 처리가 필요할 때만 작업을 수행
  2. CPU 자원 절약
    • selectpoll과 달리 모든 연결을 순차적으로 검사하지 않고, 이벤트가 발생한 연결만 처리하므로 CPU 사용량 감소
  3. 대규모 동시 연결 지원
    • epoll은 수천 개의 동시 연결을 효율적으로 관리할 수 있어 WebSocket 서버와 같은 환경에 적합

주의사항

  • epoll은 Linux에서만 작동. Windows 환경에서는 다른 이벤트 모델을 사용
  • epoll을 활성화하면 multi_accept on; 설정과 함께 사용하는 것이 좋음

multi_accept on

기능

  • 하나의 이벤트 루프에서 들어오는 모든 연결 요청을 한 번에 수락
  • 기본 동작: 기본적으로 Nginx는 각 연결 요청을 한 번에 하나씩 처리
  • 효과: multi_accept on;을 활성화하면, Nginx는 대기열에 있는 모든 연결 요청을 즉시 수락할

multi_accept on;을 사용하는가?

  1. 고성능 환경에 적합
    • 동시에 많은 연결 요청이 들어오는 환경(예: WebSocket 서버)에서 효율성을 극대화
    • 단일 연결 처리보다 대기열 전체를 한 번에 처리하면 응답 시간 감소
  2. 부하 테스트 및 실시간 서비스에 유리
    • 부하 테스트에서 동시 연결 수가 많을 경우, 빠른 수락을 통해 병목 현상 완화
    • WebSocket과 같은 실시간 연결이 중요한 애플리케이션에 특히 적합
  3. epoll과 시너지 효과
    • use epoll과 함께 사용하면, Linux의 비동기 이벤트 처리를 최대한 활용 가능
    • epoll은 대규모 동시 연결을 처리하는 데 최적화되어 있으므로, multi_accept on; 설정과 조합하면 더 높은 처리량을 제공

주의사항 및 한계

  1. CPU 사용량 증가
    • 모든 연결을 즉시 수락하기 때문에, CPU 사용량이 약간 증가
    • 특히 리소스가 제한적인 서버(t2.micro)에서는 성능을 면밀히 모니터링 필요
  2. 적합한 환경에서 사용
    • 트래픽이 낮거나 동시 연결 수가 적은 서버에서는 큰 효과를 보지 못할 수 있음
    • 이러한 환경에서는 오히려 리소스를 낭비할 가능성 존재

설정 방법

epoll과 multi_accept on;을 활성화한 Nginx 설정 예시

events {
    use epoll;            # Linux 환경에서 효율적인 비동기 이벤트 처리
    multi_accept on;      # 가능한 모든 연결을 즉시 수락
    worker_connections 1024; # 워커 프로세스당 최대 연결 수
}

최적화된 사용 사례

  1. WebSocket 서버
    • 실시간 데이터를 처리해야 하는 WebSocket 애플리케이션에 적합
    • 클라이언트가 지속적으로 연결을 유지하므로 빠르게 연결을 수락하는 것이 중요
  2. 부하 테스트 환경
    • 동시 연결 수를 테스트하고 병목 현상을 발견하는 데 유용

(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 상태에서도 연결을 유지하며 클라이언트 경험을 개선

proxy_send_timeout: 60s

  • 설명
    • 업스트림 서버로 데이터를 보낼 때의 최대 대기 시간 설정
  • 값 선정 이유
    • 대용량 데이터 전송
      • 메시지 크기가 크거나 네트워크 상태가 느린 경우 더 긴 시간 동안 데이터를 보낼 수 있도록 지원
    • 60초 설정
      • 안정적인 데이터 전송을 보장

keepalive_timeout: 75s

  • 설명
    • Nginx가 클라이언트와의 유휴 연결을 유지하는 최대 시간을 설정
  • 값 선정 이유:
    • WebSocket 연결 특성
      • 연결을 자주 닫으면 WebSocket 세션이 자주 재연결되며, 추가적인 오버헤드가 발생
    • 75초 설정
      • 너무 긴 값은 리소스 낭비를 초래할 수 있고, 너무 짧은 값은 불필요한 연결 해제 유발
      • 75초는 연결 유지와 자원 효율성을 모두 고려한 최적값
  • 적용 이유
    • 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 최적화의 장점

  1. 동시 연결 처리량 증가
    • worker_connectionsworker_processes 설정을 통해 더 많은 연결 처리 가능
  2. 연결 안정성 향상
    • 타임아웃 시간을 늘려 장기적인 WebSocket 연결 유지
  3. 리소스 효율성 개선
    • 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로 설정
  • epollmulti_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. 주요 개선점

  1. WebSocket 에러 감소
    • 변경 전 61건 → 변경 후 30건으로 50% 이상 감소
    • 이유: 타임아웃 설정을 늘려 서버가 과도한 연결 해제를 방지
  2. 응답 시간 안정화
    • 최대 응답 시간 감소: 68.5ms → 52.3ms
    • 평균 응답 시간 개선: 0.6ms → 0.4ms
    • 이유: epollmulti_accept를 통해 동시 연결 처리가 효율적으로 개선
  3. 세션 길이 증가
    • 평균 세션 길이가 약 75% 증가 (18183ms → 31692ms)
    • 이유: keepalive_timeout 설정이 연결을 유지하며 세션 효율성을 높임
  4. 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. 설정 변경의 의미

  1. proxy_connect_timeout 60s
    • 연결 설정 지연을 방지하기 위해 시간을 늘림
    • 네트워크 지연 환경에서 서버 연결 안정성을 향상
  2. proxy_read_timeout 60s, proxy_send_timeout 60s
    • 클라이언트/서버 간 메시지 전송 및 읽기 안정성 강화
    • WebSocket에서 긴 데이터 전송 시 연결 끊김 방지
  3. keepalive_timeout 75s
    • 세션 연결을 유지하여 클라이언트의 재접속 빈도를 줄임
    • 연결 유지로 인해 불필요한 자원 소비 감소
  4. worker_connections 1024
    • 동시 연결 수를 최대 1024로 설정해 서버 처리 용량 향상
  5. use epoll
    • Linux 전용 고성능 I/O 처리 메커니즘
    • 대규모 동시 연결 처리에 적합
  6. multi_accept on
    • 가능한 모든 연결을 즉시 수락하여 연결 처리 속도 증가

5. 결론

Nginx 설정 최적화를 통해

  • WebSocket 에러가 감소하고 응답 시간이 안정화
  • 클라이언트의 세션 유지 시간이 증가하며 사용자 경험이 개선
  • Nginx의 고성능 설정을 통해 서버의 처리 용량과 안정성을 대폭 향상
  • 조사를 통해 나름의 최적값을 설정했지만 운영시 환경과 사용자의 이용 패턴에 따라 최적값이 다를 수 있어 운영시 추가적 데이터 분석 필요
  • ulimit와 PAM 설정은 글이 길어져 다음 글에서 다룰 예정

Reference

Nginx