시스템 아키텍트시스템 아키텍트

다중 테넌트 서버리스 워크플로우 오케스트레이션 플랫폼의 아키텍처 청사진을 작성하십시오. 이 플랫폼은 정확히 한 번의 의미론을 가진 수백만 개의 장기 실행 상태 프로세스를 실행할 수 있으며, 워크플로우 중복 없이 크로스 리전 활성-활성 장애 조치를 처리하고, 하위 초단위 지연 내에서 외부 비동기 이벤트를 상관시키면서 엄격한 테넌트 격리를 시행하고 공격적인 제로 스케일 경제를 유지해야 합니다.

Hintsage AI 어시스턴트로 면접 통과

질문에 대한 답변.

아키텍처는 이벤트 소싱 제어 평면을 통해 일시적인 컴퓨팅과 지속적인 상태를 분리하는 내구성 실행 패턴에 중심을 둡니다. 워크플로우 정의는 모든 상태 전환이 Apache Kafka(쓰기를 앞당기는 로그)에서 변경 불가능한 이벤트로 지속되는 결정론적 상태 머신으로 실행됩니다. 이를 통해 실패 시 결정론적 재생이 가능합니다. 컴퓨팅 계층은 테넌트별 VPC 및 IAM 경계를 가진 AWS Lambda 또는 Azure Functions를 활용하여 격리를 보장하고 콜드 스타트를 완화하기 위해 프로비전된 동시성 웜 풀을 이용합니다. 지역 간의 정확히 한 번의 의미론을 위해 시스템은 워크플로우 상태를 저장하기 위해 직렬화 가능한 기본 격리를 가진 CockroachDB를 사용하고, 별도의 코디네이터 서비스 없이 크로스 리전 일관성을 위해 Raft 합의를 사용합니다. 이벤트 상관관계는 계층적 접근 방식을 통해 하위 초단위 지연을 달성합니다: Redis 클러스터와 RedisJSON 인덱싱은 메모리에서 핫 이벤트 매칭을 처리하고, Elasticsearch는 역사적인 상관 관계 쿼리를 위한 콜드 스토리지를 제공합니다. Cloudflare Workers는 트래픽 급증을 흡수하기 위해 엣지 측 이벤트 버퍼링을 제공합니다.

실제 상황

블랙 프라이데이 2023 동안, SwiftCart(글로벌 전자상거래 플랫폼)는 50M 개의 동시 배송 워크플로우를 처리하는 동안 레거시 Step Functions 구현에서 치명적인 실패를 겪었습니다. us-east-1 지역에서 장애가 발생했을 때, us-west-2로의 장애 조치로 인해 워크플로우 상태 조정이 5분 TTL 창의 궁극적인 일관성에 의존하여 12,000건의 중복 배송이 발생했습니다. 동시에, 운송사 웹훅 이벤트는 30초의 상관관계 지연을 겪어 고객에게 실시간 추적 약속을 위반했고, $2M의 SLA 벌금을 초래했습니다.

해결책 A: EKS에서 Airflow를 사용하는 Kubernetes 기반 오케스트레이터

이 접근 방식은 Apache AirflowAmazon EKS에서 실행되고 PostgreSQL이 메타데이터 저장소로 사용됨으로써 전체 제어 및 성숙된 도구를 약속했습니다. 장점으로는 광범위한 플러그인 생태계 및 간단한 로컬 개발 환경이 있었습니다. 그러나 단점은 치명적이었습니다: 파드 스케줄링 지연은 평균 45초였고, 이로 인해 유휴 워크플로우는 거의 제로의 계산 비용을 발생해야 하는 요구를 위반했습니다. 게다가 PostgreSQL의 동기 복제를 지역 간에 유지하는 것은 모든 작업 상태 전환에 200ms를 추가했고, 내장된 정확히 한 번의 의미론이 부족하여 지역 장애 조치 중 복잡한 응용 프로그램 수준 잠금이 필요했으며 자주 교착 상태에 빠졌습니다.

해결책 B: Kafka 및 Lambda를 사용하는 순수 이벤트 구동 방식의 오케스트레이션

이 서버리스 네이티브 접근 방식은 중앙 오케스트레이터 없이 Lambda 함수가 이벤트에 반응하도록 Amazon MSK(Kafka)를 진실의 근원으로 사용했습니다. 장점으로는 실제 사용량 기반 경제와 로그 기반 지속성을 통한 자연스러운 복원력이 있었습니다. 그러나 정확히 한 번의 의미론을 구현하려면 DynamoDB(무효성을 위해) 및 Kafka를 아우르는 분산 트랜잭션이 필요하여 각 작업에 대해 500ms 이상의 지연이 발생했습니다. 또한, 장기 실행 프로세스(7일의 워크플로우에서 5일째)에 대한 워크플로우 상태를 재구성하려면 S3 아카이브에서 수백만 개의 이벤트를 재생해야 했고 이로 인해 복구 시간이 10분을 초과하여 실패가 발생할 때 "분산 스파게티"를 디버깅하는 것이 불가능했습니다.

해결책 C: 분할 상태 관리를 가진 내구성 실행 플랫폼

선택된 아키텍처는 일시적인 Lambda 워커와 지속적인 상태(지리적으로 분할된 테이블을 가진 CockroachDB)를 분리하는 사용자 정의 Temporal 영감을 받은 제어 평면을 구현했습니다. 일관된 해싱은 지역 데이터베이스 노드에 워크플로우 샤드를 분배하며, Redis Streams는 초밀리초 이벤트 상관관계 버퍼링을 제공합니다. 장점으로는 CockroachDB의 직렬화 가능한 트랜잭션을 통한 원주율 내구성, 디버깅을 위한 결정론적 재생, 그리고 비활성 워크플로우가 저렴한 S3 스냅샷에만 존재하는 진정한 제로 스케일이 있습니다. 단점으로는 서비스 검색을 위한 etcd 클러스터 유지의 복잡성과 대량 웨이크업 시나리오에서 떼려오는 소 떼를 방지하기 위한 정교한 캐싱 필요성이 있었습니다.

결과

SwiftCart는 1초 가시성 타임아웃이 있는 테넌트별 SQS 큐를 구현하여 이후 프라임 데이 이벤트 동안 45분 동안 us-west-2 장애에도 불구하고 제로 워크플로우 중복을 달성했습니다. 이벤트 상관관계 p95 지연은 Redis 엣지 캐싱을 통해 400ms로 감소했습니다. 인프라 비용은 항상 켜져 있는 EKS 접근 방식에 비해 70% 감소했으며, 85%의 워크플로우가 유휴 대기 기간 동안 오직 압축된 상태 스냅샷으로 S3에 존재하여 연간 $1.4M의 절감을 가져왔습니다.

후보자들이 자주 놓치는 점

네트워크 파편화가 발생할 동안 양쪽 리전이 동시에 이벤트를 처리할 때 워크플로우 상태 분기를 어떻게 방지합니까?

대부분의 후보자들은 DynamoDBCassandra마지막 쓰기 승리 의미론을 잘못 제안합니다. 이는 비즈니스 작업이 비교 가능하지 않기 때문에 워크플로우 오케스트레이션에 실패합니다(예: "주문 취소"와 "주문 배송"은 타임스탬프만으로 조정될 수 없습니다). 올바른 구현은 워크플로우 상태 메타데이터에 포함된 벡터 클락 또는 점 형태 버전 벡터를 사용합니다. 네트워크 파편화가 치유되면 시스템은 버전 벡터 비교를 통해 동시 분기를 감지하고 도메인별 병합 기능을 적용합니다. 조정할 수 없는 충돌(예: 동시에 배송 및 취소)이 발생할 경우 아키텍처는 사가 보상 패턴을 구현하여 나중에 발생한 작업이 이전 작업을 롤백하도록 하며 포괄적인 감사 로그를 유지합니다. 또는 CockroachDB의 기본 직렬화 격리는 파편화 중에 충돌하는 쓰기를 거부하여 완전히 분기를 방지하고, 조용한 데이터 손상을 방지하는 대신 기하급수적으로 백오프하여 명시적인 재시도 루프를 강제합니다.

v1.0에서 시작된 7일 장기 워크플로우가 v2.0을 배포하여 활동 의미가 변경되어야 할 때 워크플로우 코드 버전 관리는 어떻게 합니까?

후보자들은 내구성 실행의 근본 요구인 결정론적 재생 요구를 종종 간과합니다. 단순히 Lambda 함수 코드를 업데이트하면 진행 중인 워크플로우가 중단됩니다. 이는 충돌 후 상태를 재구성하는 데 사용되는 재생 논리가 원래 실행 경로와 분기되어 비결정론적인 예외를 초래합니다. 이 솔루션은 이벤트 소싱 마커를 통해 명시적 워크플로우 버전 관리를 구현합니다. v2.0을 배포할 때, 워커는 WebAssembly 샌드박스 또는 별도의 Docker 사이드카 내에서 v1.0과 v2.0 활동 구현을 동시에 지원해야 합니다. 워크플로우 상태는 각 이력 활동에 대해 실행된 코드 버전을 기록합니다. 재생 중에는 워커가 특정 이력 버전의 샌드박스를 로드하여 과거 단계를 결정론적으로 재실행할 수 있도록 보장하며, 새로운 워크플로우는 v2.0을 사용합니다. 최대 워크플로우 지속 시간(7일 및 24시간 안전 버퍼) 후에 v1.0 코드는 사용 정지될 수 있습니다. 이로 인해 모든 비하인드 호환 활동 서명이 무기한 유지되거나 Pact Contract Testing을 사용하여 버전 간의 행동 동등성을 검증해야 합니다.

사용자 코드에서 무한 루프 또는 메모리 누수가 있는 "독극물 알약" 워크플로우로부터 보호하면서 건강한 워크플로우에 대한 정확히 한 번 보장을 어떻게 유지합니까?

간단한 데드 레터 큐(DLQ)는 실제로 정확히 한 번 의미론을 위반합니다. 메시지를 DLQ로 이동하는 것은 원래 메시지를 확인해야 하므로 DLQ 쓰기가 실패하거나 소비자가 작업 중에 충돌할 경우 메시지 손실 위험이 발생합니다. 강력한 솔루션은 무효성을 가진 체크포인트와 함께 진행 추적을 활용합니다. 워커는 매 30초마다 심장 박동을 보내고, 비교 및 교환 작업을 사용하여 etcd 또는 CockroachDB에 진행 토큰을 작성합니다. 동일한 워크플로우 작업에 대해 워커가 세 번 연속으로 충돌하는 경우(데이터베이스에 저장된 실행 시도 카운터를 통해 감지됨) 작업은 "독극물"로 플래그가 지정되지만 큐에 남아 있으며 가시성 지연이 기하급수적으로 증가합니다(1분, 5분, 30분). 별도의 "외과적" 워커 풀은 향상된 관찰 가능성, 메모리 한계 및 상세한 OpenTelemetry 추적을 통해 실행을 시도합니다. 24시간의 지속적인 실패가 발생하면 워크플로우는 수동 운영자가 개입해야 하는 "중단" 상태로 전환됩니다. 이는 모든 상태 전환에서 CockroachDB의 MVCC 타임스탬프를 사용한 원자적 비교 및 교환 작업을 활용하므로 정확히 한 번 불변성을 유지합니다.