시스템 아키텍트System Architect

지리적으로 분리된 멀티 액티브 데이터 플랫폼을 설계하여 데이터 주권 준수를 보장하면서 전 세계의 분산 사용자에게 100ms 미만의 읽기 지연 시간을 유지하고 이질적인 클라우드 지역 간에 트랜잭션 무결성을 보장하는 설계를 구축하세요.

Hintsage AI 어시스턴트로 면접 통과
  • 질문에 대한 답변입니다.

질문의 역사

전 세계로 확장하는 기업은 GDPRCCPA와 같은 엄격한 데이터 거주 법률에 직면해 있습니다. 전통적인 모놀리식 데이터베이스는 데이터를 한 지역에 중앙집중화하여 주권을 위반하거나 높은 지연 시간을 초래합니다. 초기 분산 시스템은 액티브-패시브 복제를 사용했으나, 이는 단일 실패 지점을 생성하고 쓰기 지연 문제를 발생시킵니다. 현대 아키텍처는 EU, USAPAC의 사용자가 지역 데이터 제약을 존중하면서 로컬에서 쓸 수 있는 멀티 액티브 지역을 지원해야 합니다.

문제

핵심 문제는 CAP 정리의 트레이드오프입니다. 낮은 지연 시간과 분할 내성을 동시에 갖춘 강력한 일관성을 모든 지역에서 갖출 수는 없습니다. 또한, 데이터가 국경을 넘어 이동할 수 없을 때 지역 간의 외래 키 관계는 불가능해집니다. 지역 간 트랜잭션은 조정 중 PII가 유출되면 규정을 위반할 위험이 있습니다. 100ms 미만의 읽기를 유지하려면 캐시를 사용해야 하지만, 주권 경계를 넘는 캐시 무효화는 복잡합니다.

해결책

데이터베이스 네이티브 지리적 분할을 사용하는 셀 기반 아키텍처를 구현합니다(예: CockroachDB 또는 Google Cloud Spanner). region 열로 테이블을 분할하여 PII가 물리적 셀을 벗어나지 않도록 합니다. 비민감 메타데이터만 전 세계적으로 복제하기 위해 Apache Kafka를 통해 **Change Data Capture (CDC)**를 사용합니다. 지역 간 트랜잭션에 대해 Saga 패턴을 구현하여 분산 잠금을 피하는 지역 보상을 수행합니다. 읽기 중심 작업을 위해 Cache-Aside 패턴을 사용하여 엣지에 Redis 클러스터를 배포하고, 주권 경계를 넘는 캐시 조정을 피하기 위해 TTL 기반 무효화를 사용합니다.

  • 실제 상황

상황 맥락

글로벌 결제 프로세서가 독일싱가포르에서 런칭해야 했으며 미국 데이터 센터를 유지해야 했습니다. 규제 요구 사항에 따라 EU 사용자 거래 기록은 물리적으로 프랑크푸르트에 있어야 하며, APAC 데이터는 싱가포르에 있어야 했습니다. 그러나 국경 간 이체는 US 계좌에서 자금을 차감하고 같은 논리적 트랜잭션 내에서 EU 계좌에 입금해야 했으며, 모든 것이 균형 조회 시간을 100ms 이하로 유지해야 했습니다.

해결책 1: 지역 읽기 복제본을 갖춘 중앙 집중식 데이터베이스

이 접근법은 US-East에 기본 데이터베이스를 호스팅하고 EUAPAC에 읽기 복제본을 제공하여 간단한 일관성 모델과 복잡한 동기화 없이 명확한 ACID 보장을 제공합니다. 그러나 이는 데이터 주권 법칙을 위반하여 쓰기 트래픽이 US-East로 라우팅되어 EU PII미국 땅에 보존될 수 있으며, 싱가포르의 쓰기 작업은 200ms 이상의 지연이 발생하여 사용자 경험 요구 사항을 충족하지 못합니다. 이 아키텍처는 또한 US-East에 단일 실패 지점을 만들어 글로벌 결제 플랫폼에 부적합해집니다.

해결책 2: 완전히 격리된 지역 실로에 대한 야간 ETL

이 설계는 각 지역에서 독립 찾아결정적으로 PostgreSQL 클러스터를 운영하며 야간 유지 관리 창 동안 외부 이체를 처리하여 완벽한 규정 준수 격리와 간단한 지역 자율성을 보장합니다. 그러나 이 접근법은 실시간 국제 결제를 지원하지 않으며, 사용자 경험이 저하되고 배치 처리 중 조정 오류를 수정하기 어려워집니다. 추가적으로 이 아키텍처는 글로벌 계좌 잔액 집계를 지원할 수 없으며 상당한 지연으로 인해 현대 핀테크 플랫폼에 부적합해집니다.

해결책 3: Saga 오케스트레이션을 갖춘 지리적 분할 데이터베이스

이 전략은 partition_key를 사용자 홈 지역에 매핑하여 지리적으로 분할된 테이블을 가진 CockroachDB를 배포하며, 지역 간 이체를 지역 트랜잭션으로 관리하기 위한 Temporal 워크플로를 구현합니다. 이 설계는 분할 제약을 통해 본래의 데이터 거주지를 강화하고 지역 노드에 고정된 리스 소유자를 통해 50ms 이하의 로컬 읽기를 달성하지만, 분산 SQL 전문 지식이 필요한 운영 복잡성을 도입합니다. 이 솔루션은 Kafka CDC 스트림을 통해 지역 간 메타데이터의 최종 일관성을 처리하고, saga 실행 중에는 TTL 기반의 대기 상태 가시성을 통해 임시 불일치를 관리합니다.

선택한 접근법

팀은 이 솔루션이 트랜잭션 의미나 파괴적인 데이터 마이그레이션을 요구하지 않으면서 준수 및 지연 시간 제약을 유일하게 만족한다고 판단하여 이를 선택했습니다. 그들은 CockroachDB REGIONAL BY ROW 테이블을 구성하여 EU 행을 프랑크푸르트 노드에 고정하고, 메타데이터 캐싱을 위해 5초 TTL를 가진 엣지 위치에 Redis 클러스터를 배포하여, 실패 시 자동 보상을 하는 Temporal saga를 통해 지역 간 이체를 오케스트레이션했습니다.

결과

시스템은 GDPR 감사에서 제로 국경 간 PII 유출로 통과하였으며, 50,000 건의 하루 지역 간 트랜잭션을 처리하며 99번째 백분위 읽기 지연 시간은 45ms였습니다. 고객 지원 팀은 지역적 중단 중에 일시적인 불일치를 해결하기 위해 API 엔드포인트를 통해 대기 중인 saga 상태를 조회할 수 있었습니다. 이 아키텍처는 이제 새로운 시장으로의 확장을 지원하며, 애플리케이션 변경 없이 단순히 CockroachDB 클러스터에 새로운 셀을 추가하면 됩니다.

  • 후보자들이 자주 놓치는 내용

데이터 주권 영역을 넘는 외래 키 관계에서 참조 무결성을 어떻게 유지합니까?

데이터가 물리적으로 자리를 벗어날 수 없을 때 지역 간 외래 키 제약을 데이터베이스 수준에서 강제할 수 없습니다. UUID 참조를 사용하고 Kafka에 게시하는 아웃박스 패턴을 통해 비동기 검증을 수행하여 응용 프로그램 수준 참조 무결성을 구현합니다. 소비자는 참조를 확인하고 인정을 게시하며, 타임아웃 이후 고아 감지를 수행합니다. 이 접근 방식은 준수를 위해 즉각적인 일관성을 희생하지만, 데이터 마이그레이션 없이 최종 무결성을 보장합니다.

지역에서 실패할 때 진행 중인 트랜잭션은 어떻게 됩니까?

Saga 패턴은 자동으로 실패를 처리하지 않으므로 idempotency를 위한 설계를 해야 하며, 지역마다 로컬로 보관된 idempotency 키를 Redis 또는 Etcd에 저장하여 재시도 시 중복 처리를 방지합니다. 만약 지역 B가 신용 작업 중에 실패하면, 조정 시간이 초과되어 지역 A에서 차감된 금액을 환불하는 보상 트랜잭션이 발생하며, PostgreSQL Advisory Locks 또는 ZooKeeper Distributed Locks를 활용하여 조정자를 통한 경쟁 조건을 방지합니다. 시스템은 고객 지원 개입을 위해 진행 중인 트랜잭션 상태를 API 엔드포인트를 통해 노출해야 하며, 부분 실패 상태는 쿼리 가능하고 해결할 수 있도록 유지해야 합니다.

다른 유지 관리 창이 있는 지리적으로 분할된 셀에서 무중단 스키마 마이그레이션을 어떻게 수행합니까?

Expand-Contract 패턴과 LaunchDarkly에서 관리하는 기능 플래그를 결합하여, 각 지역의 유지보수 창 동안 새로운 열 및 테이블과 같은 부가적인 DDL 변경을 배포하여 애플리케이션이 이전 버전과 호환되도록 합니다. 비동기적으로 데이터를 마이그레이션하기 위해 Debezium CDC 파이프라인을 사용한 다음, 스키마 전파 확인 후 기능 플래그를 통해 새로운 코드 경로를 활성화하여 어떤 지역도 오래된 데이터를 제공하지 않도록 보장합니다. 모든 지역이 마이그레이션 완료를 확인하기 전까지는 파괴적인 DDL (열 삭제)을 수행하지 않아야 하며, 각 셀 내에서 Blue-Green 배포를 활용하여 복제 지연이 임계치를 초과할 경우 즉시 롤백할 수 있습니다.