웹 서버를 운영하다 보면 단순히 "접속이 된다"는 수준을 넘어, 하드웨어가 가진 잠재력을 100% 끌어내야 하는 시점이 온다.
특히 수만 명의 사용자가 동시에 접속하는 환경에서 Nginx는 단순한 웹 서버가 아니라, 운영체제의 커널 기능을 직접 제어하는 정교한 조율사 역할을 수행한다.
오늘은 Nginx의 심장인 마스터-워커 프로세스의 구조를 파악하고, 전송 효율을 극대화하기 위한 커널 수준의 네트워크 옵션들을 정리해 본다.
1. 주요 특징 및 핵심 로직: 프로세스 모델과 연결 공식

Nginx는 관리자 역할을 하는 '마스터 프로세스'와 실제 비즈니스 로직을 처리하는 '워커 프로세스'로 나뉘어 동작한다. 실제 성능을 결정짓는 핵심은 워커 프로세스의 설정과 운영체제 자원(File Descriptor)의 조화에 있다.
📌 리버스 프록시 환경의 동시 연결 공식
일반적인 웹 서버 모드와 달리 리버스 프록시 모드에서는 연결 수가 배로 필요하다는 점을 명심해야 한다.

- 이론적 최대 동시 연결: worker_processes × worker_connections
- 실무적 프록시 연결: (최대 동시 연결) / 2
- 이유: Nginx가 클라이언트로부터 연결을 하나 받고, 다시 백엔드 서버(Upstream)로 연결을 하나 더 맺어야 하므로 총 2개의 소켓이 사용되기 때문이다.
2. 상세 가이드 및 심층 분석
🔍 워커(Worker) 및 이벤트 설정
워커가 일하는 방식과 OS 레벨의 이벤트를 처리하는 방식을 정의한다.
| 설정 항목 | 설명 및 실무 활용 가이드 |
| worker_processes | 보통 auto로 설정하여 CPU 코어 수와 일치시킨다. |
| worker_connections | 한 워커당 처리할 동시 연결 수. ulimit -n으로 확인한 파일 디스크립터 수 내에서 설정해야 한다. |
| use | 이벤트 처리 방식. macOS는 kqueue, 리눅스는 epoll을 사용한다. |
| multi_accept | on으로 설정하면 워커가 한 번에 여러 연결을 수락한다. 대량 요청 시 효율적이다. |
🔍 네트워크 전송 최적화 (Zero-Copy & TCP Control)
Nginx가 파일을 읽어 네트워크로 보내는 과정을 커널 수준에서 최적화한다.

1. sendfile on (Zero-Copy)
파일 데이터를 커널 공간에서 유저 공간으로 복사하지 않고 바로 네트워크 카드로 보낸다. 이 과정을 통해 데이터 복사 횟수가 줄어들어 CPU 부하가 약 50% 이상 감소한다.
2. tcp_nopush와 tcp_nodelay의 조화
Nginx는 리눅스의 TCP_CORK(Nopush)와 TCP_NODELAY를 직접 제어하여 패킷 전송을 최적화한다.

- tcp_nopush on: sendfile이 켜져 있을 때만 작동한다. 패킷이 꽉 찰 때까지 기다렸다가 응답 헤더와 파일 내용을 한 번에 보낸다. 패킷 수를 줄여 오버헤드를 최소화한다.
- tcp_nodelay on: Nagle 알고리즘을 비활성화한다. 작은 패킷이라도 모으지 않고 즉시 전송하여 지연 시간(Latency)을 줄인다.
- 작동 순서: Nginx는 전송 중에는 nopush를 통해 데이터를 모으고, 전송이 완료되는 시점에 nopush를 끄고 tcp_nodelay를 활성화하여 남은 데이터를 즉시 밀어낸다.
🔍 연결 유지 및 전송 효율 (Keepalive & Gzip)
Keepalive 전략
- keepalive_timeout: 하나의 TCP 연결로 여러 요청을 처리할 수 있게 유지하는 시간이다. 서버 측 타임아웃이 클라이언트보다 짧으면 불필요한 재연결 비용이 발생하므로 적절한 튜닝이 필요하다.
Gzip 압축 전략
텍스트 파일 압축은 대역폭 절약에 큰 도움이 되지만, 이미 압축된 이미지나 바이너리 파일까지 압축하면 CPU만 낭비하게 된다.
- gzip_min_length: 설정된 크기(예: 1024) 이하의 작은 파일은 압축하지 않는다.
- gzip_proxied any: 리버스 프록시 환경에서 백엔드 응답을 압축할지 결정한다.
4. 완성된 성능 최적화 설정 (nginx.conf)'
# 전역 설정
worker_processes auto; # CPU 코어 수에 맞게 자동 설정
error_log /opt/homebrew/var/log/nginx/error.log warn;
pid /opt/homebrew/var/run/nginx.pid;
events {
worker_connections 1024; # 동시 연결 수 (ulimit -n 확인 필수)
use kqueue; # macOS 최적화 이벤트 처리 (리눅스는 epoll)
multi_accept on; # 워커가 한 번에 여러 연결을 수락
}
http {
include mime.types;
default_type application/octet-stream;
# [네트워크 전송 최적화]
sendfile on; # 제로 카피 사용 (OS 자원 직접 활용)
tcp_nopush on; # 패킷을 묶어서 한 번에 전송 (sendfile 필수)
tcp_nodelay on; # 지연 없는 즉각 전송 (Nagle 알고리즘 OFF)
# [연결 유지 설정]
keepalive_timeout 65;
keepalive_requests 100;
# [Gzip 압축 설정]
gzip on;
gzip_min_length 1024; # 1KB 미만은 압축 안 함
gzip_vary on; # 프록시 환경에서 캐시 효율 증대
gzip_proxied any; # 프록시 요청에 대해서도 압축 수행
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss;
server {
listen 8080;
server_name localhost;
# 정적 파일 서빙
location / {
root /opt/homebrew/var/www;
index index.html;
}
# 백엔드 API 중계 (리버스 프록시)
location /api {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
5. 실무 팁 및 주의사항
- 자원 한계 확인 (ulimit -n): worker_connections를 아무리 높여도 운영체제의 파일 디스크립터 제한이 낮으면 Too many open files 에러가 발생한다. 반드시 시스템 설정을 함께 체크해야 한다.
- Gzip의 효율: 이미지(PNG, JPG)나 이미 압축된 파일은 Gzip을 적용하면 오히려 CPU만 소모하고 파일 크기는 거의 줄어들지 않는다. gzip_types를 텍스트 기반 자산으로 한정하는 것이 핵심이다.
- Nopush와 Nodelay의 공존: 많은 이들이 두 옵션이 상충한다고 생각하지만, Nginx는 파일 바디를 보낼 때는 nopush를, 마지막 패킷을 보낼 때는 nodelay를 사용하는 식으로 지능적으로 교차 제어한다. 따라서 둘 다 on으로 두는 것이 가장 권장된다.
6. 마무리
Nginx 설정은 단순히 기능을 켜고 끄는 것이 아니라, 시스템 자원과 네트워크 대역폭 사이의 균형을 맞추는 정교한 설계 과정이다. 마스터-워커 프로세스의 연결 공식을 이해하여 동시 접속 효율을 잡고, 커널의 전송 옵션을 통해 데이터 복사 비용을 줄이는 것만으로도 서비스의 품질은 비약적으로 향상된다.
'Infra > Nginx' 카테고리의 다른 글
| [Nginx] 웹 서버 성능의 한계 돌파: Nginx 튜닝과 HTTP/2 멀티플렉싱 이해 (0) | 2026.04.29 |
|---|---|
| [Nginx] 리버스 프록시와 부하 분산 처리 (0) | 2026.04.27 |
| [Nginx] 라우팅과 정적 파일 서비스 (1) | 2026.04.26 |
| [Nginx] Nginx 설정 : 상속, 덮어쓰기 그리고 모듈화 전략 (0) | 2026.04.24 |
| [Nginx] 핵심 개념: Apache의 한계를 넘어 이벤트 기반 혁신으로 (1) | 2026.04.23 |