단일 장애 지점(SPOF : Single Point of Failure)
시스템 내에서 단 하나의 장애로 전체 시스템이 중단될 수 있는 구성 요소
ex) API 서버가 한 대뿐이라면 해당 서버가 OOM(Out Of Memory) 또는 네트워크 장애로 다운-> 전체 서비스가 중단
서버 이중화로 SPOF 제거하기
- 여러 대의 서버에 동일한 애플리케이션을 배포하고, 앞단에 로드 밸런서를 배치해 트래픽을 분산
- 하나의 서버가 고장 나더라도 나머지 서버가 요청을 처리할 수 있어 고가용성(High Availability, HA) 을 확보할 수 있음
이중화 시 점검해야 할 항목과 상세 설명
임계 구역(Critical Section) & 동시성 문제
- 임계 구역이란?
- 여러 스레드나 프로세스가 동시에 접근하면 안 되는 공유 자원을 사용하는 코드 영역
// 단일 서버의 동기화 예시 - synchronized
public class Counter {
private int count = 0;
// 동기화 처리
public synchronized void increment() {
count++;
}
}
- JVM 내부의 메모리 락을 사용하기 때문에 위 코드는 하나의 서버 내에서만 유효
- ⚠️문제점: 이중화 시 서버 간 동기화 불가
- 이중화된 환경에서는 서로 다른 서버(JVM) 간에 메모리를 공유하지 않기 때문에,
- synchronized 또는 ReentrantLock 같은 방식은 동시성 문제를 해결하지 못합니다.
- ✅ 해결: Redisson + Redis를 이용한 분산 락
- Redisson은 Redis 기반의 분산 락 라이브러리로, 서버 간 락을 공유할 수 있습니다.
@Autowired
private RedissonClient redissonClient;
public void updateStock() {
RLock lock = redissonClient.getLock("lock:stock"); // Redis에 분산 락 생성
try {
// 락을 시도 (최대 5초 대기, 락은 10초간 유지)
if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
// 임계 구역
// 예: 상품 재고 차감
System.out.println("Lock acquired, updating stock...");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 락 해제
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
세션 기반 인증의 무의미함 (서버 이중화 시)
기본적으로 로그인 시 사용자 정보를 서버 메모리에 저장하고, 이후 요청마다 JSESSIONID쿠키로 식별하는 방식
- ⚠️문제점: 서버별로 세션 정보가 분산됨
- 서버 A에서 로그인한 사용자가 이후 Server B에 요청을 보내면, 서버 B는 해당 세션을 알 수 없기 때문에 인증 실패가 발생
[Client] -- (login) --> [Server A]
[Server A] -- creates session --> stores in memory
[Client] -- (요청) --> [Server B] ❌ → 세션 정보 없음 → 인증 실패
| 방법 |
설명 |
| 1. Sticky Session (IP 기반 고정) |
같은 사용자의 요청을 항상 동일 서버로 라우팅 |
| 2. 세션 클러스터링 |
Redis와 같은 외부 저장소에 세션 공유 |
| 3. JWT - 토큰 기반 인증 (추천) |
서버가 세션 저장하지 않고, JWT로 사용자 상태 유지 |
- JWT 인증 예시
- JWT는 클라이언트에 모든 인증 정보를 담아 보내므로, 서버 간 상태 공유가 필요 X → 이중화된 환경에 적합
// 토큰 생성
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1시간
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
로그 수집 및 모니터링
- ⚠️ 문제점: 서버 이중화 시, 각 서버에 로그와 메트릭이 흩어져 있어서 모니터링과 디버깅이 어려워짐
- ✅ 해결 방안
- 로그 통합 수집: ELK Stack (Elasticsearch + Logstash + Kibana)
- 메트릭 수집: Prometheus + Grafana
로드 밸런싱 알고리즘
- ⚠️문제점: 로드 밸런서가 부하를 고르게 분산하지 못하면, 특정 서버에 트래픽이 몰려 SPOF가 재발할 수 있음
- ✅ 알고리즘 예시 (Nginx)
upstream backend {
least_conn; # 최소 연결 수 기반 분산
server backend1.example.com;
server backend2.example.com;
}
무중단 배포
- 문제점: 서버 수가 늘어나면 배포 시 서버마다 상태가 다를 수 있고, 운영 중 버전 불일치 문제가 발생할 수 있음
- 해결방안:
- Canary 배포
- 새 버전을 먼저 일부 사용자에게만 배포하여 테스트하고, 문제가 없으면 점진적으로 전체 사용자에게 확대하는 방식
- Blue-Green 배포: 전체 트래픽을 점진적으로 전환
- 현재 운영 중인 시스템(Blue)과 별도 새로운 버전(Green)을 두고, 배포 시점에 트래픽을 한 번에 Green으로 미리 배포
- 검증 후, 로드밸런서의 트래픽을 green으로 전환
- 장애 발생 시 즉시 이전 버전(Blue)으로 전환 가능
# 예시 (Nginx 설정 전환)
# Blue
upstream backend {
server blue.example.com;
}
# 전환 시
upstream backend {
server green.example.com;
}
- Kubernetes Rolling Update
- Kubernetes 기본 배포 전략으로, 기존 버전을 점진적으로 교체하는 방식
- 기존 파드를 하나씩 종료하고 새 버전으로 교체
- 항상 일정 수의 파드가 살아 있어 무중단 유지
- 설정을 통해 교체 속도 및 동시 갯수 제어 가능
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 동시에 내려갈 수 있는 파드 수
maxSurge: 1 # 동시에 새로 올라갈 수 있는 파드 수