대규모 분산 시스템에서 '일시적 실패(Transient Failure)'는 피할 수 없는 현실입니다. Netflix는 수천 개의 마이크로서비스를 전 세계에 배포하며, Spinnaker라는 오픈소스 지속적 전달(CD) 플랫폼을 핵심 엔진으로 사용해 왔습니다. 하지만 Spinnaker의 Clouddriver 서비스 내 복잡한 오케스트레이션 로직과 상태 관리의 한계로 인해, 클라우드 운영(Cloud Operation) 실패로 이어지는 배포가 약 4%에 달하는 문제에 직면했습니다. 이 글에서는 Netflix가 어떻게 Temporal이라는 Durable Execution 플랫폼을 도입하여 이 문제를 근본적으로 해결하고 배포 실패율을 4%에서 0.0001%로 극적으로 낮췄는지 그 여정을 살펴봅니다. 자세한 내용은 Netflix Tech Blog의 원문을 참고하세요.

Spinnaker Clouddriver의 아킬레스건
Spinnaker 내에서 Clouddriver는 클라우드 인프라 변경(예: 서버 그룹 생성/삭제)을 실행하는 역할을 담당했습니다. Orca(오케스트레이션 엔진)가 Clouddriver에 작업을 요청하면, Clouddriver는 이를 하위 작업(AtomicOperation)으로 분해하고 실행하는 복잡한 내부 프로세스를 가졌습니다. 이 구조에는 몇 가지 근본적인 문제점이 있었습니다.
- 복잡한 내부 오케스트레이션: Clouddriver는 작업 상태 추적, 재시도, 롤백(Saga 패턴)을 위한 자체적인 논리를 구현해야 했습니다. 이는 본질적인 목표(인프라 변경 실행)와는 무관한 '미분화된 부담(Undifferentiated Lifting)'이었습니다.
- 인스턴스-로컬 상태: 작업 실행 상태가 특정 Clouddriver 인스턴스의 메모리에 저장되어, 해당 인스턴스가 다운되면 진행 중인 작업 상태가 완전히 소실되었습니다.
- 긴밀한 결합(Tight Coupling): Orca는 Clouddriver의 특정 상태 폴링 API와 에러 처리 방식을 정확히 알고 있어야 했습니다.
이러한 복잡성 속에서도 네트워크 불안정, 클라우드 공급자 장애 등 '일시적 실패'에 대한 견고한 처리는 어려웠고, 결국 4%의 배포 실패율이라는 숫자로 나타났습니다.

Temporal의 패러다임 전환: '실패가 없는 것처럼' 코딩하기
Temporal은 Durable Execution을 제공하는 플랫폼입니다. 개발자는 비즈니스 로직을 Workflow(결정론적인 단계들의 집합)와 Activity(비결정론적 외부 작업, 예: API 호출)로 구성하기만 하면, Temporal 서버가 실행 상태를 지속적으로 저장하고 관리합니다. 워커(Worker) 프로세스가 죽어도, 30일을 sleep 중이어도, Temporal은 상태를 보존하고 다른 워커에서 작업을 이어갈 수 있습니다.
Temporal 마이그레이션 후 아키텍처:
- Orca는 Clouddriver에 직접 요청하는 대신, Temporal 클라이언트를 사용해
UntypedCloudOperationRunnerWorkflow를 실행 요청합니다. - Clouddriver 워커가 해당 Workflow 작업을 받아, 페이로드를 해석하고 적절한
CloudOperationChild Workflow를 실행합니다. - Child Workflow는 실제 클라우드 공급자 API를 호출하는 Activity들을 실행합니다.
- Orca는 Temporal 클라이언트를 통해 Workflow 완료를 비동기적으로 기다립니다.
이 변화로 인해 Clouddriver는 더 이상 복잡한 오케스트레이션, 상태 관리, 재시도 로직을 직접 구현할 필요가 없어졌습니다. 모든 것은 Temporal 플랫폼이 책임지게 되었죠.

얻은 성과와 교훈
주요 성과:
- 배포 실패율: 4% → 0.0001% (약 40,000배 개선).
- 결합도 감소: Orca와 Clouddriver는 Temporal을 매개로 느슨하게 연결되었습니다.
- 상태 비저장성(Stateless): Clouddriver 인스턴스는 상태를 갖지 않게 되어 카우처럼 취급 가능해졌고, Chaos Monkey 적용도 가능해졌습니다.
- 가시성 향상: Temporal UI를 통해 프로덕션에서 실행 중인 Workflow를 실시간으로 디버깅하고 모니터링하기 쉬워졌습니다.
실전에서 얻은 교훈:
- 불필요한 Child Workflow는 피하라: 코드 조직화를 위해 Child Workflow를 사용하면 디버깅이 복잡해질 수 있습니다. 클래스 컴포지션을 고려하세요.
- 단일 인자 객체를 사용하라: Workflow/Activity 메서드 시그니처를 변경하면 장기 실행 Workflow를 깨뜨릴 수 있습니다. 모든 인자를 담은 하나의 직렬화 가능한 클래스를 사용하는 것이 안전합니다.
- 비즈니스 실패와 워크플로우 실패를 분리하라:
WorkflowResult와 같은 래퍼 타입을 사용해 비즈니스 로직의 실패를 워크플로우 실행 실패와 구분하면 에러 처리가 더 세밀해집니다.
Netflix는 이 성공적인 마이그레이션을 계기로 Temporal 사용이 급증했으며, 현재는 수백 가지의 다양한 유스 케이스에서 Temporal Cloud(SaaS)를 활용하고 있습니다. 복잡성 속에서 신뢰성을 확보해야 하는 모든 분산 시스템 설계자에게 귀중한 인사이트를 제공하는 사례입니다.