본문으로 건너뛰기

고가용성(HA) 아키텍처 설계

현대 서비스에서 장애는 피할 수 없는 현실입니다. 서버 하드웨어 결함, 소프트웨어 버그, 네트워크 단절, 데이터센터 정전 등 수많은 원인이 서비스 중단을 야기합니다. 고가용성(High Availability, HA)은 이러한 장애 상황에서도 서비스를 지속적으로 제공할 수 있도록 시스템을 설계하는 방법론입니다. 이 챕터에서는 HA 개념부터 SPOF 분석, 이중화 전략, 실제 스택 구성까지 체계적으로 다룹니다.

고가용성(High Availability)이란?​

고가용성은 시스템이 장애가 발생하더라도 서비스 중단 없이(또는 최소한의 중단으로) 계속 동작하는 능력을 의미합니다. 가용성(Availability)은 일반적으로 다음 공식으로 표현합니다.

가용성(%) = (서비스 가능 시간 / 전체 시간) × 100

예를 들어 연간 99.9% 가용성을 목표로 한다면 연간 허용 다운타임은 약 8.76시간입니다. 이 수치는 SLA(Service Level Agreement)로 명문화되어 서비스 제공자와 고객 간의 계약으로 관리됩니다.

가용성 목표별 허용 다운타임​

가용성 등급연간 다운타임월간 다운타임주간 다운타임일간 다운타임
99% (Two Nines)87.6시간7.3시간1.68시간14.4분
99.9% (Three Nines)8.76시간43.8분10.1분1.44분
99.99% (Four Nines)52.6분4.38분1.01분8.6초
99.999% (Five Nines)5.26분26.3초6.05초0.86초

대부분의 상용 서비스는 99.9%~99.99% 수준을 목표로 합니다. 금융, 의료 같은 미션 크리티컬 서비스는 99.999% (Five Nines)를 요구하기도 합니다. Five Nines를 달성하려면 연간 다운타임이 5분 남짓에 불과하므로 극도로 정교한 설계가 필요합니다.

다운타임의 비용​

서비스 중단은 단순한 불편함을 넘어 직접적인 비즈니스 손실로 이어집니다.

직접 비용: 매출 손실 (이커머스 플랫폼 1시간 장애 = 수억 원 손실), 위약금 지불 (SLA 위반), 복구 인건비

간접 비용: 브랜드 신뢰도 하락, 고객 이탈, 언론 보도로 인한 평판 손상, 규제 기관 제재

AWS는 2021년 대규모 장애로 수천 개의 서비스가 동시에 영향을 받았고, 메타의 2021년 6시간 장애는 약 6천억 원의 손실로 추정되었습니다. 이런 사례들이 HA 투자의 당위성을 증명합니다.

SPOF(Single Point of Failure) 분석​

SPOF는 해당 컴포넌트가 장애를 일으키면 전체 시스템이 중단되는 단일 장애점입니다. HA 설계의 핵심은 모든 SPOF를 식별하고 제거하는 것입니다.

웹 서버 레이어 SPOF​

단일 Nginx 서버만 운영하는 경우, Nginx 프로세스 크래시, 서버 하드웨어 고장, 네트워크 카드 불량 등이 발생하면 전체 트래픽이 차단됩니다.

[Before - SPOF 존재]
클라이언트 → Nginx(단일) → Tomcat

[After - SPOF 제거]
클라이언트 → VIP(Keepalived) → Nginx Master
→ Nginx Backup (대기)

WAS(Application Server) 레이어 SPOF​

Tomcat 단일 인스턴스 운영은 배포 시 서비스 중단, JVM OutOfMemoryError, 애플리케이션 버그로 인한 프로세스 종료 등으로 SPOF가 됩니다.

DB 레이어 SPOF​

DB는 가장 심각한 SPOF입니다. 데이터 무결성 요구사항 때문에 단순 이중화가 어렵고, 장애 시 데이터 손실 위험까지 있습니다.

[DB SPOF 해결 방법]
Primary DB ──(동기 복제)──▶ Standby DB
│
└── 장애 발생 시 Standby가 Primary로 승격

로드밸런서 레이어 SPOF​

로드밸런서 자체가 SPOF가 되는 아이러니한 상황을 방지하려면 로드밸런서도 이중화해야 합니다. Keepalived + VRRP를 이용해 VIP(Virtual IP)를 공유하는 방식이 표준적입니다.

네트워크 레이어 SPOF​

스위치, NIC, 업링크 등 네트워크 장비도 SPOF가 될 수 있습니다. 본딩(NIC Bonding), 이중 스위치 구성, 다중 ISP 연결로 해결합니다.

Active-Active vs Active-Standby​

HA 구성 방식은 크게 두 가지 패턴으로 나뉩니다.

Active-Active​

모든 노드가 동시에 활성 상태로 트래픽을 처리합니다.

클라이언트
│
▼
로드밸런서
┌─┴─┐
▼ ▼
노드A 노드B ← 둘 다 실제 요청 처리

장점:

  • 리소스를 100% 활용 (Standby 서버 낭비 없음)
  • 수평 확장(Scale-Out)이 용이
  • 한 노드 장애 시 나머지 노드가 전체 트래픽 처리

단점:

  • 세션 공유 메커니즘 필요 (세션 클러스터링 또는 stateless 설계)
  • DB 쓰기 충돌 방지를 위한 동기화 로직 복잡
  • 설정 및 운영 복잡도 높음

적합한 시나리오: 무상태(Stateless) REST API 서버, 콘텐츠 서빙 서버, 읽기 전용 DB 레플리카

Active-Standby​

하나의 노드만 활성 상태로 트래픽을 처리하고, 나머지 노드는 대기 상태입니다.

클라이언트
│
▼
로드밸런서
┌─┴─┐
▼ │
노드A 노드B ← 대기 중, 장애 시 자동 승격
(Active) (Standby)

장점:

  • 구성 단순 (세션 공유 불필요)
  • 데이터 일관성 유지 용이
  • 검증된 패턴, 운영 이해도 높음

단점:

  • Standby 서버 리소스 낭비
  • 페일오버 시 짧은 서비스 중단 발생 (수 초~수십 초)
  • Standby 서버 장애를 놓치기 쉬움

적합한 시나리오: DB Primary-Standby, 상태 유지가 필요한 세션 기반 서버, 소규모 인프라

비교 요약표​

항목Active-ActiveActive-Standby
리소스 효율높음 (100% 활용)낮음 (Standby 낭비)
페일오버 속도즉각적수 초~수십 초
구성 복잡도높음낮음
세션 처리공유 스토리지 필요단순
비용추가 서버 없이 HA여분 서버 비용 발생
확장성우수제한적

HA 아키텍처 설계 원칙​

중복화(Redundancy)​

모든 단일 컴포넌트를 최소 2개 이상으로 구성합니다. N+1 원칙(필요한 수 + 1개 여분)이 기본이며, 중요 시스템은 N+2를 적용합니다.

N+1 원칙 예시:
- Nginx 서버 2대 (1대 장애 시 1대로 서비스)
- Tomcat 서버 3대 (1대 장애 시 2대로 서비스)
- DB 서버 2대 (Primary + Standby)

페일오버(Failover)​

장애 감지 후 자동으로 트래픽을 정상 서버로 전환하는 메커니즘입니다. 수동 페일오버(Manual Failover)는 MTTR(Mean Time To Recovery)이 길어 HA 목표 달성이 어렵습니다.

자동 페일오버 흐름:

  1. 헬스체크 실패 감지 (예: 3회 연속 실패)
  2. 해당 서버를 로드밸런서 풀에서 제거
  3. 백업 서버 활성화 (Standby → Active 승격)
  4. 알림 발송 (PagerDuty, Slack 등)
  5. 원인 분석 후 수동 복구

자동 복구(Auto Recovery)​

장애 서버를 자동으로 재시작하거나 교체하는 메커니즘입니다. systemd의 Restart=always, Kubernetes의 Pod 자동 재시작, AWS Auto Scaling의 인스턴스 교체 등이 대표적입니다.

# systemd 자동 재시작 설정 예시
[Service]
ExecStart=/opt/tomcat/bin/catalina.sh run
Restart=always
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3

그레이스풀 셧다운(Graceful Shutdown)​

장애나 배포 시 진행 중인 요청을 완료한 후 서버를 종료합니다. 갑작스러운 종료는 진행 중인 트랜잭션을 손상시킬 수 있습니다.

헬스체크 전략​

헬스체크는 HA 시스템의 핵심 신경망입니다. 잘못된 헬스체크 설정은 정상 서버를 제거하거나 장애 서버를 방치하는 결과를 낳습니다.

L4 헬스체크 (TCP 레벨)​

TCP 연결 성공 여부만 확인합니다. 빠르고 가벼우나 애플리케이션 실제 동작 여부는 확인 불가합니다.

# Nginx 스트림 모듈 TCP 헬스체크
upstream tomcat_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}

L7 헬스체크 (HTTP 레벨)​

실제 HTTP 요청을 보내 응답 코드와 내용을 검증합니다. 애플리케이션의 실제 상태를 정확하게 파악할 수 있습니다.

# Nginx upstream 헬스체크 (nginx_upstream_check_module)
upstream tomcat_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;

check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}

헬스체크 엔드포인트 설계​

// Spring Boot 헬스체크 컨트롤러
@RestController
public class HealthController {

@Autowired
private DataSource dataSource;

@GetMapping("/health")
public ResponseEntity<Map<String, String>> health() {
Map<String, String> status = new HashMap<>();
try {
// DB 연결 확인
dataSource.getConnection().isValid(1);
status.put("status", "UP");
status.put("db", "connected");
return ResponseEntity.ok(status);
} catch (Exception e) {
status.put("status", "DOWN");
status.put("db", "disconnected");
return ResponseEntity.status(503).body(status);
}
}
}

실제 HA 스택 예시​

Keepalived + Nginx + Tomcat + PostgreSQL HA 구성​

                    ┌─────────────────────────────────┐
│ VIP: 192.168.1.100 │
│ (Keepalived VRRP 관리) │
└────────────┬────────────────────┘
│
┌──────────────────┴──────────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Nginx Master │ │ Nginx Backup │
│ 192.168.1.10 │ │ 192.168.1.11 │
│ (VRRP Priority 100) │ │ (VRRP Priority 90) │
└──────────┬──────────┘ └─────────────────────┘
│ (장애 시 VIP 이전)
▼
┌──────────────────────────────────────────────┐
│ Nginx Upstream (로드밸런싱) │
└────────────┬─────────────────┬───────────────┘
▼ ▼
┌────────────────┐ ┌────────────────┐
│ Tomcat Node 1 │ │ Tomcat Node 2 │
│ 192.168.1.20 │ │ 192.168.1.21 │
│ :8080 │ │ :8080 │
└────────┬───────┘ └───────┬────────┘
└─────────┬─────────┘
▼
┌──────────────────────────────────────────────┐
│ PostgreSQL Primary-Standby │
│ Primary: 192.168.1.30 ──▶ Standby: 192.168.1.31 │
└──────────────────────────────────────────────┘

이 구성에서 각 레이어의 SPOF가 모두 제거됩니다. Nginx Master 장애 시 Keepalived가 VIP를 Backup으로 자동 이전하고, Tomcat 노드 장애 시 Nginx upstream에서 자동으로 제외하며, PostgreSQL Primary 장애 시 Standby가 Primary로 승격됩니다.

고가용성 설계 시 주의사항​

Split-Brain 문제: Active-Active 구성에서 네트워크 파티션 발생 시 양쪽 노드가 모두 자신이 Primary라고 판단하는 상황입니다. Quorum 기반 의사결정, Fencing 메커니즘으로 방지합니다.

Thundering Herd: 장애 복구 후 모든 요청이 한 번에 몰리는 현상입니다. 점진적 트래픽 전환, 캐시 워밍업으로 완화합니다.

운영 복잡도: HA 구성은 운영 복잡도를 높입니다. 팀의 역량과 서비스 규모에 맞는 수준을 선택하세요.

전문가 팁​

  • 가용성 수치보다 MTTR(복구 시간)을 줄이는 데 집중하세요. 장애는 반드시 발생합니다.
  • 카오스 엔지니어링(Chaos Engineering)으로 정기적으로 장애를 시뮬레이션하고 복구 절차를 검증하세요.
  • 헬스체크 엔드포인트는 외부 의존성(DB, 캐시) 연결 상태까지 포함해 설계하세요.
  • 자동 페일오버는 반드시 알림과 함께 구성해 운영팀이 인지할 수 있게 하세요.
  • SLA 수치보다 실제 사용자 경험 기반의 가용성 지표(합성 모니터링, RUM)를 추적하세요.