서비스가 멈추는 순간, 사용자의 신뢰도 함께 멈춥니다. 안정성은 기술적 요구사항이 아니라 사용자와의 약속입니다.
원칙 1: 실패를 전제로 설계하라
완벽한 시스템은 존재하지 않습니다. 중요한 것은 실패하지 않는 시스템이 아니라, 실패해도 복구할 수 있는 시스템입니다.
// 재시도 패턴의 기본 구현
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
delay: number = 1000
): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn()
} catch (error) {
if (attempt === maxRetries) throw error
await new Promise(r => setTimeout(r, delay * attempt))
}
}
throw new Error('Unreachable')
}
지수 백오프(exponential backoff)를 적용한 재시도는 가장 기본적이면서도 효과적인 복원 전략입니다.
원칙 2: 경계를 명확히 하라
시스템 간의 경계가 모호하면 하나의 장애가 전체로 번집니다. **격벽 패턴(Bulkhead Pattern)**은 이를 방지합니다.
- 서비스 간 통신에 타임아웃을 설정합니다
- 서킷 브레이커로 장애 전파를 차단합니다
- 각 서비스는 독립적으로 배포하고 롤백할 수 있어야 합니다
원칙 3: 관측 가능하게 만들어라
문제를 해결하려면 먼저 문제를 볼 수 있어야 합니다.
- 로그: 무엇이 일어났는가
- 메트릭: 얼마나 일어났는가
- 트레이스: 어떤 경로로 일어났는가
이 세 가지를 갖추면 대부분의 장애를 신속하게 진단할 수 있습니다.
원칙 4: 점진적으로 변화하라
한 번에 모든 것을 바꾸는 빅뱅 배포는 가장 위험한 배포입니다. 카나리 배포, 블루-그린 배포 등을 통해 변화의 영향 범위를 통제해야 합니다.
안정성은 화려한 기술 스택이 아닌, 올바른 원칙의 일관된 적용에서 나옵니다. 기본에 충실한 설계가 결국 사용자에게 가장 큰 가치를 제공합니다.