실전 고수 팁 — 아키텍처 설계와 장애 대응 패턴
이론을 넘어 실무에서 마주치는 아키텍처 결정 상황과 장애 포인트를 정리합니다.
실무 아키텍처 패턴 3가지
패턴 1: 단일 서버 (개발·소규모)
[인터넷]
│
[단일 서버]
├─ Nginx (80/443 포트)
└─ Tomcat (8080 포트, 외부 차단)
- 가장 단순한 구성
- 서버 1대로 웹서버와 WAS 동시 운영
- 개발 환경, ** 트래픽이 낮은 소규모 서비스**에 적합
- Nginx가 정적 파일 처리 + Tomcat 프록시 역할 수행
- 단점: SPOF(Single Point of Failure) — 서버 1대가 죽으면 서비스 전체 중단
패턴 2: 웹서버·WAS 분리 (일반 운영)
[인터넷]
│
[웹서버 서버] — Nginx (공인 IP)
│ └─ 정적 파일 처리
│ └─ SSL Termination
│
[WAS 서버] — Tomcat (사설 IP, 외부 직접 접근 불가)
└─ 비즈니스 로직
└─ DB 연결
- 웹서버와 WAS를 물리적으로 다른 서버에 분리
- WAS 서버의 포트를 방화벽으로 외부 차단 → 보안 강화
- Nginx 서버가 죽어도 WAS는 살아있고, WAS가 죽어도 503 에러 페이지만 보임
- 중소 서비스 운영 표준
패턴 3: 로드밸런서 + WAS 클러스터 (고가용성)
[인터넷]
│
[로드밸런서] — AWS ALB / Nginx / HAProxy
│
├─ [WAS 서버 1] — Tomcat
├─ [WAS 서버 2] — Tomcat
└─ [WAS 서버 3] — Tomcat
[데이터베이스 클러스터]
├─ Primary DB
└─ Replica DB (읽기 분산)
- WAS 인스턴스를 여러 대 운영하여 수평 확장(Scale Out)
- 1대 WAS가 죽어도 나머지 WAS가 서비스 지속
- 고트래픽 서비스, 무중단 배포 필수 환경 에 적합
- 세션 관리 전략(Sticky Session, Redis 세션) 별도 필요
자주 발생하는 장애 포인트와 해결책
장애 1: Tomcat 직접 노출로 인한 보안 사고
증상: Tomcat 기본 포트(8080)가 인터넷에 직접 노출됨
# 잘못된 구성 — 누구나 Tomcat에 직접 접근 가능
curl http://your-server:8080/manager/html
→ Tomcat Manager 페이지 노출
해결책:
# 방화벽에서 8080 포트 외부 차단 (iptables 예시)
iptables -A INPUT -p tcp --dport 8080 -s 127.0.0.1 -j ACCEPT # localhost 허용
iptables -A INPUT -p tcp --dport 8080 -j DROP # 나머지 차단
# AWS Security Group이라면
# 8080 포트: Source = Nginx 서버 IP만 허용
장애 2: 웹서버·WAS 간 타임아웃 불일치
증상: 느린 API 요청(20초 이상)에서 Nginx가 먼저 연결을 끊어 버려 클라이언트에 502 Bad Gateway 에러가 발생
원인: Nginx의 proxy_read_timeout 기본값(60초)이 실제 WAS 처리 시간보다 짧을 때
# 잘못된 설정 (기본값만 사용)
location /api/ {
proxy_pass http://tomcat;
# proxy_read_timeout 기본값 60초
}
해결책:
# 파일 업로드, 대용량 처리 등 느린 엔드포인트에 타임아웃 늘리기
location /api/upload {
proxy_pass http://tomcat;
proxy_connect_timeout 10s; # Tomcat에 연결 최대 대기
proxy_send_timeout 300s; # 요청 전송 최대 대기
proxy_read_timeout 300s; # Tomcat 응답 최대 대기
}
장애 3: 정적 파일을 WAS가 처리하여 성능 저하
증상: Tomcat 스레드가 이미지·JS 파일 요청으로 포화되어 API 응답 지연 발생
[현상] Tomcat maxThreads=200 상태에서
- 이미지 요청 180개가 스레드 점유
- 실제 API 요청 처리 가능 스레드: 20개만 남음
→ API 응답 지연 및 큐 대기 급증
해결책: Nginx에서 정적 파일을 직접 처리
server {
root /var/www/myapp;
# 정적 파일은 Nginx가 직접 처리 (Tomcat에 전달 안 함)
location ~* \.(html|css|js|png|jpg|gif|ico|woff2|pdf)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
# 나머지만 Tomcat으로 프록시
location / {
proxy_pass http://127.0.0.1:8080;
}
}
장애 4: WAS 재시작 시 순간적 503 에러
증상: Tomcat 배포 재시작 시 수십 초간 사용자에게 503 에러가 노출됨
해결책: Nginx에서 에러 발생 시 대기 또는 에러 페이지 처리
upstream tomcat_backend {
server 127.0.0.1:8080;
# Tomcat 응답 없으면 다음 서버로 시도 (클러스터 환경)
# server 127.0.0.1:8081 backup;
}
server {
location / {
proxy_pass http://tomcat_backend;
# 연결 오류 시 커스텀 에러 페이지 표시
proxy_intercept_errors on;
error_page 502 503 504 /maintenance.html;
}
# 점검 안내 페이지 (정적 파일로 즉시 반환)
location = /maintenance.html {
root /var/www/maintenance;
internal;
}
}
아키텍처 선택 체크리스트
신규 서비스 아키텍처를 설계할 때 아래 질문에 답하며 구성을 결정하세요.
□ 예상 DAU(일일 활성 사용자)는 얼마인가?
- 10만 이하: 단일 서버 또는 Nginx+Tomcat 분리
- 10만~100만: 로드밸런서 + WAS 2~3대
- 100만 이상: 오토스케일링, CDN 필수
□ 정적 파일 비중이 높은가?
- 높음: Nginx가 정적 파일 직접 서빙 + CDN 연동
- 낮음(API Only): Nginx를 리버스 프록시로만 활용
□ 무중단 배포가 필요한가?
- 필요: WAS 2대 이상 + 로드밸런서 + Rolling 배포
- 불필요: 단순 재시작 배포 가능
□ 세션 관리 방식은?
- Sticky Session: 간단하지만 특정 WAS 장애 시 세션 유실
- Redis 세션 공유: 복잡하지만 안정적
□ 예산·운영 인력은?
- 소규모팀: 관리형 서비스(AWS ALB, Cloud Run) 활용
- 운영 여력 있음: 직접 Nginx + Tomcat 클러스터 구성
핵심 요약
| 상황 | 권장 아키텍처 |
|---|---|
| 개발·테스트 | Tomcat 단독 또는 Nginx+Tomcat 단일 서버 |
| 소규모 운영 | Nginx + Tomcat 분리 (서버 2대) |
| 중규모 이상 | Nginx 로드밸런서 + Tomcat 클러스터 |
| WAS 보호 | 방화벽에서 Tomcat 포트 외부 차단 필수 |
| 성능 최적화 | 정적 파일은 반드시 Nginx에서 처리 |