본문으로 건너뛰기

Worker 프로세스·스레드 튜닝: Nginx와 Apache 최적화

Nginx와 Apache의 worker 설정은 서버 자원을 얼마나 효율적으로 사용할지 결정합니다. CPU 코어 수, 메모리, 요청 특성에 맞게 조정하면 처리량을 크게 높일 수 있습니다.


Nginx Worker 아키텍처

Nginx는 비동기 이벤트 기반 아키텍처를 사용합니다. 각 worker 프로세스가 수천 개의 연결을 동시에 처리할 수 있어 스레드 기반인 Apache보다 메모리 효율이 높습니다.

                    ┌─────────────────────────────┐
클라이언트 연결 │ Master Process (root) │
────────────────▶ │ config reload, worker 관리 │
└──────────┬──────────────────┘
│ fork
┌────────────────┼────────────────┐
▼ ▼ ▼
Worker #1 Worker #2 Worker #3
(1 CPU core) (1 CPU core) (1 CPU core)
비동기 I/O 비동기 I/O 비동기 I/O
10,000+ 연결 10,000+ 연결 10,000+ 연결

Nginx worker 설정

# /etc/nginx/nginx.conf

# worker 프로세스 수: auto = CPU 코어 수만큼 자동 생성 (권장)
worker_processes auto;

# 특정 CPU에 worker 고정 (NUMA 아키텍처에서 L3 캐시 효율 향상)
# worker_cpu_affinity auto; # Nginx 1.9.10+

# worker당 최대 열린 파일 수 (OS 제한과 맞춤)
worker_rlimit_nofile 65535;

events {
# worker당 최대 동시 연결 수
# worker_processes × worker_connections = 최대 동시 클라이언트 수
worker_connections 4096;

# 이벤트 처리 방식: Linux는 epoll이 최적
use epoll;

# accept_mutex: 단일 worker가 accept 처리 (false = 모든 worker가 경쟁)
# 고트래픽: off (성능 향상), 저트래픽: on (CPU 절약)
accept_mutex off;

# 한 번에 여러 연결 수락
multi_accept on;
}

OS 파일 디스크립터 한도 설정

# 현재 한도 확인
ulimit -n # 소프트 한도
ulimit -Hn # 하드 한도

# /etc/security/limits.conf 에 추가
nginx soft nofile 65535
nginx hard nofile 65535
* soft nofile 65535
* hard nofile 65535

# systemd 서비스라면 /etc/systemd/system/nginx.service.d/override.conf
[Service]
LimitNOFILE=65535

sudo systemctl daemon-reload
sudo systemctl restart nginx

# /proc/sys/fs/file-max: 시스템 전체 파일 디스크립터 한도
echo 2097152 | sudo tee /proc/sys/fs/file-max
echo "fs.file-max = 2097152" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Apache MPM 선택과 설정

Apache는 Multi-Processing Module(MPM)에 따라 요청 처리 방식이 다릅니다.

MPM방식특징HTTP/2
Prefork프로세스PHP mod_php 호환, 메모리 多
Worker스레드메모리 효율, PHP 불안정제한적
Event비동기 스레드Keep-Alive 효율, 권장
# MPM 변경 (Prefork → Event)
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2

# PHP 사용 시: mod_php → php-fpm으로 전환 필요
sudo a2dismod php8.1
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.1-fpm

MPM Event 튜닝

# /etc/apache2/mods-available/mpm_event.conf

<IfModule mpm_event_module>
# 시작 시 생성할 서버 프로세스 수
StartServers 2

# 최소/최대 유휴 스레드 수
MinSpareThreads 25
MaxSpareThreads 75

# 프로세스당 스레드 수 (MaxRequestWorkers / ServerLimit)
ThreadsPerChild 25

# 전체 최대 요청 처리 스레드
# MaxRequestWorkers = ServerLimit × ThreadsPerChild
MaxRequestWorkers 400

# 최대 프로세스 수
ServerLimit 16

# 프로세스당 최대 요청 수 (이후 재생성)
MaxConnectionsPerChild 10000

# Keep-Alive 비동기 처리 스레드
AsyncRequestWorkerFactor 2
</IfModule>

서버 규모별 권장 설정

소형 서버 (2 CPU, 4GB RAM)

# Nginx
worker_processes 2;
worker_connections 2048;
# Apache MPM Event
MaxRequestWorkers 150
ThreadsPerChild 25
ServerLimit 6

중형 서버 (8 CPU, 16GB RAM)

# Nginx
worker_processes auto; # 8
worker_connections 4096;
# Apache MPM Event
MaxRequestWorkers 400
ThreadsPerChild 25
ServerLimit 16

대형 서버 (32 CPU, 64GB RAM)

# Nginx
worker_processes auto; # 32
worker_connections 16384;
worker_rlimit_nofile 65535;
# Apache MPM Event
MaxRequestWorkers 2000
ThreadsPerChild 50
ServerLimit 40

Worker 상태 모니터링

# Nginx status 페이지 활성화
server {
listen 127.0.0.1:8080;

location /nginx_status {
stub_status on;
access_log off;
}
}
curl http://127.0.0.1:8080/nginx_status
# Active connections: 150
# server accepts handled requests
# 1234567 1234567 3456789
# Reading: 3 Writing: 12 Waiting: 135
# ─────────────────────────────────────
# Waiting: 유휴 keepalive 연결 수
# Writing: 현재 응답 전송 중인 연결 수
# Reading: 요청 헤더 읽는 중인 연결 수
# Apache status 페이지
sudo a2enmod status

# /etc/apache2/conf-available/server-status.conf
<Location "/server-status">
SetHandler server-status
Require ip 127.0.0.1
</Location>

curl http://127.0.0.1/server-status?auto
# BusyWorkers: 25
# IdleWorkers: 175
# Scoreboard: ....W.W.....K......

프로세스 수 계산식

Nginx 최대 동시 처리 수:
= worker_processes × worker_connections
= 8 × 4096 = 32,768개 연결 가능

Apache 최대 동시 처리 수:
= ServerLimit × ThreadsPerChild
= 16 × 25 = 400개 요청 가능

Tomcat 최대 동시 처리 수:
= maxThreads (기본: 200)

Nginx/Apache가 Tomcat을 프록시하는 경우, Tomcat의 maxThreads가 병목이 되지 않도록 상위 서버의 worker 수와 균형을 맞춰야 합니다.