Temporal 또는 Netflix Conductor를 사용하여 중앙 집중식 Saga Orchestrator를 구현하고, 지속 가능한 워크플로 상태를 PostgreSQL에 유지하며 도메인 서비스와의 gRPC 통신을 수행합니다. 이 패턴은 비즈니스 제약 조건에 맞는 TTL 윈도우를 가진 Redis Cluster에 저장되는 아이템포턴시 키가 필요하며, Apache Kafka는 감사 추적 및 보상 트리거를 위한 이벤트 백본으로 사용됩니다. 각 사가 단계에는 Saga State Machine 패턴을 사용하여 역작업을 실행하는 보상 트랜잭션이 포함되어야 하며, 클러스트 조정을 위해 etcd 또는 ZooKeeper에서 명시적인 상태(PENDING, SUCCEEDED, COMPENSATING, COMPENSATED)가 추적됩니다.
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ API Gateway │────▶│ Temporal │────▶│ Inventory │
└─────────────────┘ │ Orchestrator│ │ Service │
└──────────────┘ └─────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌─────────────────┐
│ PostgreSQL │ │ PostgreSQL │
│ State Store │ │ (Compensation │
└──────────────┘ │ Logic) │
└─────────────────┘
글로벌 호텔 예약 플랫폼은 세 가지 서로 다른 Kubernetes 클러스터 간의 객실 예약, 결제 처리 및 로열티 포인트 업데이트를 조정할 때 연쇄적으로 실패하는 문제에 직면했습니다. 그들의 레거시 구현은 REST API를 통한 **Two-Phase Commit (2PC)**를 사용하여, 결제 게이트웨이가 10초를 초과하는 지연이 발생하는 피크 트래픽 동안 광범위한 교착 상태를 초래했습니다.
팀은 각 서비스가 공유 버스에 도메인 이벤트를 게시하는 Choreography-Based Saga를 평가했습니다. 이 접근 방식은 단일 실패 지점을 제거하고 인프라 비용을 40% 절감했습니다. 그러나 복잡한 다중 객실 예약이 성공했는지 여부를 판단하기 위해 17개의 마이크로서비스에서 로그를 쿼리해야 하는 심각한 가시성 문제를 야기했습니다. 암묵적 종속성 때문에 일관된 타임아웃 정책을 시행하는 것이 불가능했으며, 프로덕션 문제를 디버깅하는 것은 여러 AWS CloudWatch 대시보드를 아우르는 법의학적 작업이 되었습니다.
그들은 AWS ECS에 배포된 사용자 정의 Node.js 코디네이터를 사용하여 Orchestrated Saga의 프로토타입을 만들었습니다. 이렇게 해서 비즈니스 로직을 중앙 집중화하고 통일된 Grafana 대시보드를 통한 모니터링을 단순화했습니다. 그러나 초기 구현은 워크플로 상태를 메모리만 저장하여 배포 중 코디네이터가 재시작될 때마다 재앙적인 데이터 손실이 발생하게 되었습니다. 30개의 트랜잭션이 알 수 없는 상태에 들어가 수동 데이터베이스 조정에 3일이 소요되었고, 이는 중복으로 청구된 고객으로 인해 막대한 수익 손실을 초래했습니다.
선택된 솔루션은 Cassandra 지속성을 가진 워크플로 엔진으로 Temporal을 배포하여 포드 재시작 및 AZ 실패 간의 상태 내구성을 보장했습니다. 아키텍처는 오케스트레이터와 도메인 서비스 간의 타입 안전 통신을 위해 Protobuf 스키마를 사용했으며, Redis Sentinel이 아이템포턴시 키를 관리했습니다. 결제 서비스가 us-east-1에서 지역적 중단에 직면했을 때, 사가는 200ms 이내에 객실 보유를 해제하고 로열티 포인트를 원자적으로 취소하는 보상 워크플로를 자동으로 트리거했습니다.
이 시스템은 이제 매일 50,000개의 복잡한 예약을 처리하며 99.99%의 일관성 보증을 제공하고, 네트워크 분할 동안에는 수동 개입이 필요하지 않습니다. 고장 탐지 평균 시간(MTTD)은 45분에서 8초로 감소했으며, 보상 지연은 p99에서 500ms 이하로 유지됩니다.
보상 트랜잭션 자체가 실패할 때 부분 보상 실패를 어떻게 처리합니까? 그로 인해 시스템이 일관되지 않은 상태에 남을 가능성이 있습니다.
Event Sourcing을 사용하여 모든 시도된 보상 작업을 Apache Kafka에 불변 이벤트로 기록하는 Compensation Audit Log를 구현합니다. 시스템은 자동 재시도가 필요한 일시적인 인프라 실패와 인간 개입이 필요한 비즈니스 논리 위반을 구분해야 합니다. 일시적인 문제의 경우, 복구 후 보상을 다시 처리하도록 RabbitMQ 또는 Amazon SQS의 **Dead Letter Queues (DLQ)**를 사용하여 떼 지어 몰리는 문제를 방지하기 위해 지터를 사용합니다. 이미 정산된 거래의 환불 시도와 같은 비즈니스 규칙 위반의 경우, 사가는 'COMPENSATION_FAILED' 상태로 들어가고 PagerDuty 알림을 트리거하며 커맨드 모델을 통해 집합 루트를 동결하는 CQRS 패턴을 적용합니다. 항상 데이터베이스 고유 제약 조건이나 Redis SETNX 작업을 사용하여 보상을 아이템포턴트로 설계해야 하며, 재시도가 부수효과를 발생하지 않도록 보장해야 합니다.
시간 결합 및 '현재 트랜잭션 상태는 무엇인가?' 쿼리를 응답하는 능력에 대한 오케스트레이션과 안무의 근본적인 아키텍처 차이는 무엇입니까?
Choreography는 Reactive Manifesto를 따르며, 서비스가 상류 또는 하류 참가자에 대한 지식 없이 이벤트에 반응하면서 시간적으로 분리됩니다. 그러나 복잡한 Distributed Tracing을 구축하지 않고는 사가 상태를 쿼리하는 능력을 희생합니다. 상태는 이벤트 로그에서 발생하며, ‘예약이 완료되었나요?’ 질문을 답하기 위해 CQRS 읽기 모델 투영이 필요합니다. Orchestration은 코디네이터와 작업자 간의 명시적인 시간 결합을 도입하며, 오케스트레이터가 다음 단계를 트리거하려면 사용 가능해야 하지만, 상태 저장소(PostgreSQL/CockroachDB)에서 단일 진실 출처를 제공합니다. 이는 즉각적인 상태 쿼리를 허용하지만 네트워크 종속성을 생성합니다. 중요한 통찰력은 안무가 모든 소비자에서 상태 머신을 구현해야 하는 반면, 오케스트레이션은 이 복잡성을 중앙 집중화해야 한다는 것입니다. 감사 가능성 및 규정을 요구하는 시스템(PCI-DSS)의 경우, 결합 비용에도 불구하고 오케스트레이션이 선호됩니다.
Kafka 소비자 재조정 또는 Kubernetes 포드 재시작 동안 적어도 한 번 전송 의미론을 사용할 때 중복 사가 실행을 어떻게 방지합니까?
Redis 또는 Memcached를 사용하여 처리된 메시지 ID를 저장하고, 중복 제거 창이 **Recovery Point Objective (RPO)**와 일치하도록 하는 Idempotent Consumer 패턴을 구현합니다. 사가 오케스트레이터가 명령을 수신할 때, 비즈니스 키(고객 ID + 예약 참조)와 해싱하여 결정론적 아이템포턴시 키를 생성한 후 부수효과를 수행합니다. 각 도메인 서비스는 이 키를 자신의 Idempotency Store와 비교하여 확인해야 하며, 이는 조합 키에 대한 고유 제약 조건을 가진 PostgreSQL 테이블로 구현하거나 메모리 효율적인 부정 조회를 위해 Redis의 Bloom Filters를 사용할 수 있습니다. 장기 실행 사가의 경우, etcd 버전 벡터를 통한 낙관적 잠금을 사용하여 분산 노드 전반에서 정확히 한 번 처리 의미론을 처리하는 Saga State Machines를 사용합니다. 이는 소비자 그룹이 배포 중 재조정될 때나 Kubernetes 라이브니스 프로브 재시작을 유발하는 네트워크 분할 시 중복 예약 시나리오를 방지합니다.