로드 밸런싱과 CDN 전략
로드 밸런서 설정, Cloudflare CDN, 풀 페이지 캐싱, 오브젝트 캐싱(Redis/Memcached), DB 복제를 마스터합니다.
고가용성 WordPress 인프라: 다운타임 0을 향한 여정
단일 서버의 한계와 스케일링의 필요성
단일 서버 WordPress 아키텍처는 트래픽 한계, 단일 장애점, 지역별 지연시간이라는 세 가지 근본적 문제를 가지고 있습니다. 일 방문자 10,000명을 넘기거나, WooCommerce에서 동시 주문이 증가하거나, 해외 사용자가 늘어나면 이 문제들이 동시에 나타납니다.
고가용성(HA) 인프라의 핵심 목표:
- 99.99% 업타임: 연간 다운타임 52분 이내 (일반 호스팅은 99.9% = 8.7시간)
- 글로벌 빠른 응답: 전 세계 어디서든 TTFB 200ms 이내
- 트래픽 급증 대응: 갑자기 트래픽이 10배 증가해도 서비스 유지
- 자동 장애 복구: 서버 하나가 다운되어도 사용자는 전혀 인식하지 못함
- 무중단 배포: 업데이트 시에도 서비스 중단 없음
엣지 서버 도시 수
DB 부하 감소
장애 전환 시간
서버 대역폭 비용
로드 밸런싱 아키텍처 설계
트래픽
CDN/WAF
로드 밸런서
(PHP-FPM)
+ Redis
Nginx 로드 밸런서 완전 설정
Nginx는 리버스 프록시 + 로드 밸런서로서 탁월한 성능을 발휘합니다. 적은 메모리로 수만 개의 동시 연결을 처리할 수 있으며, 다양한 로드 밸런싱 알고리즘을 지원합니다. 아래는 프로덕션 환경에서 사용하는 완전한 Nginx 로드 밸런서 설정입니다.
# ============================================
# Nginx 로드 밸런서 설정
# /etc/nginx/nginx.conf (로드 밸런서 서버)
# ============================================
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
# 기본 설정
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 64M;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 로그 설정
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$upstream_addr" '
'response_time=$upstream_response_time';
access_log /var/log/nginx/access.log main;
# Gzip 압축
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types text/plain text/css text/xml application/json
application/javascript application/xml text/javascript
application/x-font-ttf font/opentype image/svg+xml;
# ============================================
# 업스트림 서버 풀 정의
# ============================================
# WordPress 애플리케이션 서버 풀
upstream wordpress_backend {
# 로드 밸런싱 알고리즘
# round_robin (기본) - 순차적 분배
# least_conn - 가장 적은 연결 수의 서버로
# ip_hash - 같은 IP는 같은 서버로 (세션 유지)
least_conn;
# 서버 목록 (weight로 비중 조절 가능)
server 10.0.1.10:80 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.11:80 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.12:80 weight=2 max_fails=3 fail_timeout=30s;
# 백업 서버 (주 서버 모두 다운 시에만 사용)
server 10.0.1.20:80 backup;
# 헬스 체크 간격 설정 (Nginx Plus 또는 nginx_upstream_check_module)
# check interval=5000 rise=2 fall=3 timeout=3000 type=http;
# check_http_send "GET /wp-json/monitor/v1/health HTTP/1.0\r\nHost: example.com\r\n\r\n";
# check_http_expect_alive http_2xx;
# 커넥션 캐시 (킵얼라이브)
keepalive 32;
}
# ============================================
# 서버 블록 (프론트엔드)
# ============================================
server {
listen 80;
server_name example.com www.example.com;
# HTTPS 리다이렉트
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 설정
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 보안 헤더
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 정적 파일은 CDN에서 직접 서빙 (로드 밸런서에서도 캐시)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|mp4|webp|avif)$ {
proxy_pass http://wordpress_backend;
proxy_cache static_cache;
proxy_cache_valid 200 30d;
proxy_cache_key "$scheme$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
expires 30d;
}
# wp-admin 요청은 세션 유지 (ip_hash 효과)
location /wp-admin {
proxy_pass http://wordpress_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 관리자 세션 유지를 위한 쿠키 기반 스티키 세션
proxy_cookie_domain ~\.example\.com example.com;
}
# 일반 요청
location / {
proxy_pass http://wordpress_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
# 프록시 캐시 (비로그인 사용자만)
proxy_cache page_cache;
proxy_cache_valid 200 10m;
proxy_cache_bypass $http_cookie;
proxy_no_cache $http_cookie;
# 타임아웃
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 장애 시 다음 서버로 전환
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
}
# 헬스 체크 엔드포인트 (로드 밸런서 자체)
location /lb-health {
access_log off;
return 200 "OK";
}
}
# 프록시 캐시 영역 정의
proxy_cache_path /var/cache/nginx/page levels=1:2 keys_zone=page_cache:50m
max_size=1g inactive=60m use_temp_path=off;
proxy_cache_path /var/cache/nginx/static levels=1:2 keys_zone=static_cache:100m
max_size=5g inactive=7d use_temp_path=off;
}
| 로드 밸런싱 알고리즘 | 동작 방식 | 장점 | 적합한 상황 |
|---|---|---|---|
| Round Robin (기본) | 순차적으로 서버에 분배 | 간단, 균등 분배 | 서버 사양이 동일할 때 |
| Least Connections | 연결이 가장 적은 서버로 | 부하 불균형 방지 | 요청 처리 시간이 다양할 때 |
| IP Hash | 클라이언트 IP 기반 고정 | 세션 유지 보장 | 로그인 세션이 중요할 때 |
| Weighted | 가중치 기반 분배 | 서버 사양 차이 반영 | 서버 사양이 다를 때 |
| Random | 무작위 선택 | 편향 없는 분배 | 동일 사양, 스테이트리스 |
WordPress 로드 밸런싱의 핵심 과제: 세션과 파일 공유
WordPress를 로드 밸런싱할 때 반드시 해결해야 하는 두 가지 문제가 있습니다:
1. 세션 공유: 사용자가 서버 A에서 로그인한 후 서버 B로 분배되면 로그인 상태가 풀립니다. 해결책: Redis/Memcached에 세션을 저장하거나, IP Hash/스티키 세션을 사용하세요.
2. 파일 공유: 서버 A에 업로드된 이미지가 서버 B에는 없습니다. 해결책: NFS/GlusterFS로 공유 파일시스템을 구성하거나, S3 + CloudFront로 미디어를 외부 저장소에 보관하세요.
무료 가입하면 이어서 볼 수 있고, 강의를 완료할 때마다 XP와 레벨이 쌓입니다.