OpenAI 장애로 9일 먹통된 운세 서비스를 Claude 전환으로 복구
목차
긴급하게 LLM 공급업체를 OpenAI에서 Anthropic Claude로 전환해야 했던 이유는 서비스 장애 때문이었다. 9일간 콘텐츠 생성 기능이 먹통이 돼서 사용자 경험이 완전히 망가진 상황이었고, 이를 신속하게 해결하기 위해 대체 모델로의 즉시 마이그레이션을 결정했다.
외부 의존성 장애에 대한 신속한 대응
처음에는 OpenAI API 쪽 문제인지, 우리 코드 쪽 문제인지 원인 파악에 시간을 썼다. API 레이트 제한, 토큰 초과, 네트워크 이슈 등 여러 가능성을 점검했지만, 결국 공급업체 쪽의 서비스 안정성 문제임을 확인했다. 이런 상황에서는 근본 원인 해결을 기다릴 여유가 없다. 9일간의 다운타임은 이미 서비스 신뢰도를 크게 떨어뜨린 상태였으니까.
결정을 내릴 때 팀과 빠르게 논의했다:
- 회복 시간: OpenAI 복구 예상 시간 불명확 vs. Claude 즉시 전환 가능
- 모델 호환성: Claude의 API 문서 검토 → 현재 prompt 패턴과 호환 가능성 높음
- 비용 영향: 두 모델 가격대가 비슷한 수준
- 리스크: 마이그레이션 중 새로운 버그 vs. 계속된 장애 중 선택
결국 빠른 복구가 가장 중요한 선택지라는 팀 합의가 나왔다.
코드 변경의 핵심 — 플러그형 아키텍처의 가치
scripts/generate-fortune.js 파일이 주요 변경점인데, 이건 우리가 평소에 provider 추상화를 잘 설계한 덕분에 가능했던 작업이다.
일반적으로 LLM 호출 코드를 작성할 때 공급업체 API를 직접 박아넣기 쉽다:
// ❌ 나쁜 패턴: 공급업체에 강하게 결합됨
const OpenAI = require('openai');
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function generateContent() {
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'fortune please' }],
});
return response.choices[0].message.content;
}
이렇게 작성하면 provider를 바꿀 때 코드 전체를 뜯어쓰게 된다. 우리는 다행히 미리 adapter 패턴을 적용했었다:
// ✅ 좋은 패턴: provider 추상화
const llmProvider = createLLMProvider(process.env.LLM_PROVIDER);
async function generateContent() {
const response = await llmProvider.generate({
prompt: 'fortune please',
model: 'default',
});
return response.content;
}
package.json에서는 openai 패키지를 anthropic 패키지로 교체하고, 환경 변수(LLM_PROVIDER=claude)만 바꾸면 됐다. 실제로는 더 복잡한 부분들(prompt 형식, 응답 파싱 로직, 에러 핸들링)도 손봐야 했지만, 구조 자체가 버팀목이 되어줬다.
학습한 점 — 외부 의존성을 다룰 때의 원칙들
이 사건을 통해 팀과 함께 정리한 원칙들:
| 항목 | 고려사항 |
|---|---|
| Provider 선택 | 단일 공급업체 의존도 최소화, 대체 옵션 사전 조사 |
| 코드 설계 | API 호출 로직을 추상화 계층으로 감싸기 |
| 모니터링 | API 응답 시간, 에러율 등을 별도 메트릭으로 추적 |
| 대응 계획 | 공급업체 장애 시 즉시 실행 가능한 Fallback 리스트 준비 |
| 테스트 | Mock provider로 핵심 로직 검증 (실제 API 비용 절감) |
특히 이 건에서 9일이 걸린 이유를 추적해보니, 단순히 API 교체 시간보다는 "이게 정말 우리 책임인지 확인하는 단계"에 시간이 많았다. 다음부터는 외부 의존성 장애 여부를 빠르게 판단하는 체크리스트를 만들어두기로 했다.
마이그레이션 후 안정화
Claude로 전환 후 콘텐츠 생성은 정상 작동했다. 다만 응답 형식 미묘한 차이(예: 문장 길이, 톤)가 있어서 post-processing 로직을 조정했고, 사용자 피드백도 수집했다. 아직까지 안정적으로 돌고 있다.
이 작업은 단순 버그 픽스가 아니라 시스템 복원력(resilience)을 다시 생각하게 된 계기였다. 우리는 코드만 잘 쓰는 게 아니라, 외부 서비스에 의존할 때 어떻게 graceful하게 대응할지까지 설계해야 한다는 걸 다시금 느꼈다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.