뒤로 보낼 서버 묶음. 분배·실패 판정·연결 재사용을 여기서 정한다.
upstream backend {
least_conn;
server 10.0.1.10:8080 max_fails=3 fail_timeout=10s;
server 10.0.1.11:8080 max_fails=3 fail_timeout=10s;
server 10.0.1.12:8080 backup; # 위가 다 죽으면 쓴다
keepalive 32;
}
분배 방식
- (기본) — 라운드로빈
- least_conn — 활성 연결이 가장 적은 곳으로
- 요청 처리 시간이 들쭉날쭉할 때 유리하다
- (라운드로빈은 느린 요청이 몰린 서버에도 계속 보낸다)
- ip_hash — 클라이언트 IP 해시 — 같은 사용자를 같은 서버로
- 세션이 서버에 있을 때 쓴다. 다만 서버가 늘거나 줄면
- 해시가 재배치돼 상당수가 다른 서버로 옮겨간다
- hash $key — 임의 키 기준. consistent 를 붙이면 재배치 폭이 준다
- weight=N — 서버 성능이 다를 때 비중을 준다
실패 판정
max_fails=3 fail_timeout=10s
- 10초 안에 3번 실패하면, 그 10초 동안 이 서버를 뺀다
오픈소스판에는 '능동' 헬스체크가 없다
- 주기적으로 찔러 보는 기능은 상용판(NGINX Plus)이다
- 오픈소스는 '실제 요청이 실패하는 것' 을 보고 판단한다
- 즉 죽은 서버로 가는 요청 몇 건은 실제로 실패한다
앞에 클라우드 LB 가 있다면 그쪽 헬스체크와 역할이 겹친다 어느 계층이 판정하는지를 정해 두지 않으면 제외·복구가 엇갈린다
keepalive 는 세 줄이 세트다
upstream backend {
server 10.0.1.10:8080;
keepalive 32; # 워커당 유지할 유휴 연결 수
}
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1; # ← keepalive 는 1.1 이 필요하다
proxy_set_header Connection ""; # ← 기본 'close' 를 지운다
}
아래 두 줄을 빠뜨리면 nginx 는 요청마다 새 TCP 연결을 만든다
- 매번 3-way 핸드셰이크
- 업스트림에 TIME_WAIT 소켓이 쌓인다
- 트래픽이 오르면 포트 고갈로 이어진다 (에페메랄 포트는 약 2.8만 개)
keepalive 만 쓰고 나머지를 빠뜨리는 것이 가장 흔한 미완성 설정이다 확인: ss -s 로 TIME_WAIT 수가 비정상적으로 크면 의심
keepalive 값은 어떻게 잡나
keepalive 는 '워커당' 유지할 유휴 연결 수다
-
실제 유휴 연결 ≈ worker_processes × keepalive
-
너무 작으면 — 연결을 자주 새로 만든다 (의미가 반감)
-
너무 크면 — 백엔드가 유휴 연결을 잔뜩 들고 있게 된다
- 백엔드의 maxConnections 를 잠식한다
백엔드 수용량과 함께 정한다 — 앞단만 보고 키우면 뒤가 마른다
커넥션 수는 앞뒤를 함께 계산한다
nginx 워커 4개 · upstream keepalive 32
- 유휴 연결 최대 4 × 32 = 128
백엔드가 3대면 각각 약 43개의 유휴 연결을 받는다 백엔드 maxConnections 가 8192 라면 여유롭지만, nginx 를 20대로 늘리면 4 × 32 × 20 = 2,560 이 된다
- 앞단을 늘리면 뒤의 연결 수가 곱으로 늘어난다
- 스케일아웃 계획에 이 곱셈을 반드시 넣는다
재시도가 부하를 증폭한다
proxy_next_upstream 이 켜져 있으면 실패 시 다음 서버로 넘긴다
백엔드가 전반적으로 아플 때 요청 1건 → 서버 A 실패 → B 실패 → C 실패 = 실제 부하 3배
| proxy_next_upstream_tries 2; | # 시도 횟수 제한 | |
|---|---|---|
| proxy_next_upstream_timeout 5s; | # 전체 시간 제한 |
제한을 두지 않으면 '조금 아픈 상태' 가 '완전히 죽은 상태' 로 넘어간다
면접 함정
- ❌ "nginx가 주기적으로 헬스체크한다" → 오픈소스판은 실제 요청 실패로 판단한다.
- ❌ "ip_hash면 세션이 안전하다" → 서버 증감 시 재배치된다. 세션은 외부에 두는 편이 낫다.