시스템 아키텍트System Architect

행성 규모의 실시간 프로그램 광고 교환 시스템을 설계하여 이질적인 수요 측 플랫폼 전반에서 100ms 미만의 경매 결정을 조율하고, 분산 잠금을 사용하지 않으면서 캠페인별 예산 집행을 강제하며, 요청 경로의 행동 지문을 통해 클릭 사기를 탐지하고, 불변 원장 항목을 통해 청구 불일치를 조정하며, GDPR 준수를 위해 지역 데이터 주권을 유지하는 방법은 무엇인가요?

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

질문에 대한 답변

질문의 역사

초기 광고 제공은 게시자가 수요 파트너를 순차적으로 우선시하는 정적 폭포 구성에 의존하여 지연 폭포와 수익 누수를 발생시켰습니다. 헤더 입찰(Header Bidding)OpenRTB 프로토콜로 전환하여 재고 접근이 민주화되었지만, 극단적인 엔지니어링 제약이 도입되었습니다: 경매는 페이지 포기를 방지하기 위해 100ms 이내에 완료되어야 하고, 예산 집행은 천 개의 엣지 노드 전반에서 초과 지출을 방지해야 하며, 사기 탐지는 네트워크 홉을 추가하지 않고 인라인에서 발생해야 합니다. 이 질문은 중앙 집중식 Apache Kafka 파이프라인을 대체할 수 있는 엣지 컴퓨팅 아키텍처의 필요성에서 발생했습니다.

문제

전통적인 아키텍처는 예산 카운터와 기능 저장소를 위해 중앙 집중식 PostgreSQL 또는 Redis 클러스터에 의존하여, 블랙 프라이데이와 같은 트래픽 급증 시 100ms SLA를 위반하는 지역 간 지연을 초래합니다. 예산 감소에 대한 단순 낙관적 잠금은 떼짓기 현상과 입찰 누락을 발생시키며, 비동기 사기 탐지는 봇이 탐지 신호가 발생하기 전에 캠페인 예산을 소진할 수 있도록 합니다. 게다가, DSPs(수요 측 플랫폼) 간 청구 조정은 노출 픽셀이 발사되지만 확인 메시지가 누락되는 네트워크 분할 문제로 인해 수익 누수 또는 중복 청구가 발생하여 광고주 신뢰를 해칩니다.

해결책

Envoy Proxy 사이드카와 WebAssembly 필터를 엣지 PoPs(Point of Presence)에 배포하여 최종 사용자로부터 10ms 이내에 경매 로직을 실행하도록 합니다. 예산 집행을 위해 Gossip 프로토콜이 포함된 Redis를 사용하여 CRDT(Conflict-free Replicated Data Type) 카운터를 구현하고, 엣지 노드가 로컬에서 입찰을 수락하면서 최종적으로 수렴을 통해 전역 예산 일관성을 보장합니다. 엣지 계층 내에서 TensorFlow Lite 모델을 내장하여 마우스 속도 패턴 및 탐색 엔트로피와 같은 행동 지문을 사용하여 실시간 봇 탐지를 수행합니다. 불변 감사 로그를 위해 Apache PulsarGeo-Replication, BookKeeper를 사용하여 정확히 한 번의 의미론을 보장합니다. GDPR 준수를 위해 K-익명성 검사 및 Anycast DNS를 통한 데이터 주거지 라우팅을 구현합니다.

실생활에서의 상황

2023 블랙 프라이데이 이벤트 동안, 우리의 플랫폼은 us-east-1에 있는 중앙 집중식 Redis 예산 저장소가 포화 상태가 되어 40배의 트래픽 급증을 경험했고, 이로 인해 12%의 경매가 시간 초과되었으며 $2M의 잠재적 수익 손실이 위협받았습니다. 엔지니어링 팀은 강력한 일관성을 유지하고 지연 위반을 감수할 것인지, 아니면 속도를 우선시하고 재앙적인 예산 초과 지출의 위험을 감수할 것인지에 대한 중요한 아키텍처 결정을 내려야 했습니다.

해결책 A: Redlock이 있는 Redis 클러스터

우리는 엄격한 예산 일관성을 유지하기 위해 5개의 독립적인 Redis 마스터 노드에 걸쳐 Redlock 알고리즘을 구현하는 것을 고려했습니다. 이 접근 방식은 이론적으로 각 감소에 대해 다수결이 필요하여 캠페인이 일일 한도를 초과하지 않도록 보장할 수 있습니다. 그러나 엣지 노드와 Redis 클러스터 간의 왕복 시간은 평균 35ms였고, 부하가 걸린 경우 잠금 경합으로 인해 8%의 요청이 여러 번 재시도되어 100ms SLA를 초과했습니다. 이러한 방식은 완벽한 예산 정확도를 제공했지만, 용납할 수 없는 지연과 운영 복잡성 때문에 실시간 입찰에는 부적합했습니다.

해결책 B: 로컬 인메모리 캐시와 비동기 동기화

대안적으로, 우리는 각 엣지 노드가 30초마다 중앙 원장에 비동기적으로 동기화되는 순수 로컬 예산 카운터를 유지하도록 허용하는 것을 평가했습니다. 이는 5ms 미만의 경매 지연을 달성하였고 외부 의존성 없이 트래픽 급증을 원활하게 처리했습니다. 불행히도, 급증 중 여러 엣지 노드에서 동기화가 발생하기 전에 고가치 캠페인에 대해 총 $800K가 과도 판매되어 광고주 신뢰 문제와 계약 위반이 발생했습니다. 속도는 최적이었지만, 재무적 위험은 결제 인접 시스템에 대해 재앙적이었습니다.

해결책 C: 계층화된 페이싱이 있는 하이브리드 CRDT 아키텍처

우리는 엣지, 지역, 전역의 세 계층에 Redis에서 델타 상태 CRDT를 사용하는 하이브리드 접근 방식을 구현했습니다. 엣지 노드는 로컬 PN-카운터(Positive-Negative Counters)를 사용하여 입찰을 수락하며, 이때 로컬 임계값은 전역 예산의 95%로 설정됩니다. 로컬 예산이 소진되면 노드는 지역 캐시에 읽기-쓰기 일관성을 통해 조회합니다. 남은 5% 버퍼는 CRDT 병합을 통해 전역 원장이 관리합니다. 사기를 탐지하기 위해서는 네트워크 호출 없이 봇 패턴을 탐지하도록 훈련된 TinyML 모델을 엣지 노드에 배포했습니다. 우리는 이 솔루션이 99.9%의 예산 정확성을 제공하면서 45ms의 p99 지연을 유지하기 때문에 이 방법을 선택했습니다.

결과

플랫폼은 피크 시간 동안 초당 1200만 쿼리를 처리하였고, 한정된 캠페인에서 예산 초과가 없었습니다. 사기 탐지 지연은 150ms에서 8ms로 감소하여, 입찰 제출 전에 3.4%의 악성 트래픽을 차단했습니다. CRDT 조정은 지역 간 200ms 이내에 최종 일관성을 달성하며, 청구 조정 창 내에서 잘 이루어졌고, GDPR 준수는 엣지 로컬 데이터 처리로 유지되었습니다.

후보자들이 종종 놓치는 것

여러 엣지 노드가 전역 잠금을 획득하지 않고 동일한 캠페인 예산을 동시에 감소시킬 때 예산 초과 지출을 어떻게 방지합니까?

대부분의 후보자는 네트워크 분할이나 높은 지연에서 실패하는 Redis의 분산 잠금 또는 원자적 감소 작업을 제안합니다. 올바른 접근 방식은 CRDT로 구현된 PN-카운터(Positive-Negative Counters)를 사용하는 것입니다. 각 엣지 노드는 지출을 위한 로컬 증가 카운터와 환불을 위한 감소 카운터를 유지합니다. 노드가 입찰을 수락할 때 로컬 지출 카운터를 증가시킵니다. Gossip 동기화 중에 노드들은 자신의 카운터 상태를 교환하고, 각 카운터 요소의 최대값을 취하여 Join 연산을 사용하여 병합합니다. 일시적인 초과 지출을 방지하기 위해서, 보수적인 한도를 가진 토큰 버킷(Token Bucket) 알고리즘을 로컬에서 구현합니다. 모든 로컬 지출의 합계가 전역 한도에 접근할 경우, 노드는 남은 5% 예산을 위한 지역 코디네이터에 조회합니다. 이렇게 하면 파편화가 발생하는 동안 최대 1-2%의 일시적인 초과 지출이 이론적으로 가능하더라도, 시스템은 예산의 105%를 초과하지 않는 것을 보장할 수 있습니다. 이는 전통적인 은행 시스템과 달리 디지털 광고 SLA에서 받아들일 수 있습니다.

사용자 브라우저에서 노출 추적 픽셀이 발사되지만 네트워크 오류로 인해 경매 서버에 대한 확인 전달이 실패할 때, 어떻게 정확히 한 번 청구를 보장합니까?

후보자들은 종종 Kafka의 단일성 또는 데이터베이스의 upsert를 제안하며, 엔드 투 엔드 문제를 놓칩니다. 이 솔루션은 엣지에서 생성된 UUIDv7(시간 순서대로) 기반의 Idempotent Keys가 필요한데, 이는 크리에이티브 마크업에 내장됩니다. 브라우저가 노출 픽셀을 발사할 때, 이 키를 포함합니다. 엣지 Nginx 계층은 24시간 창을 사용하는 Deduplication EnabledApache Pulsar에 기록합니다. Pulsar의 BookKeeper 저장소는 동일한 키로 중복 쓰기가 브로커 수준에서 폐기되도록 보장합니다. 또한, BigQuery 스테이징 테이블에 At-Least-Once 전송을 구현하여 단일성 키로 분할하고, ETL 과정에서 중복 제거하는 MERGE 문을 사용합니다. 이 이중 보호는 브라우저가 500 오류로 인해 픽셀 발사를 50번 재시도하더라도 광고주가 정확히 한 번만 청구되도록 보장합니다.

시간 반응 기반 경매 승자 결정 시 지리적으로 분산된 입찰자 간의 시계 차이를 어떻게 처리합니까?

이는 미묘한 문제입니다. 후보자들은 종종 NTP 또는 TrueTime( Spanner에서) 제안을 하지만, 이는 지연을 증가시킵니다. 올바른 아키텍처는 경매 로직에서 벽시계 종속성을 제거합니다. DSP 응답의 타임스탬프를 비교하는 대신, 엣지에서 논리 시계(람포르트 타임스탬프) 또는 단순 FIFO 큐를 사용합니다. 경매가 시작되면 엣지 노드는 고해상도 타이머( V8Performance.now() 또는 C++ chrono)를 시작합니다. DSP 응답은 타임스탬프 헤더가 아닌 네트워크 인터페이스에서 도착 순서에 따라 순위를 매깁니다. 지연된 응답을 처리하기 위해서는 적응형 타임아웃 알고리즘을 사용하는 조정 가능한 타임아웃을 구현하여, 각 DSP의 역사적 p99 지연을 기반으로 조정합니다. 사후 분석 및 청구 분쟁을 위해 Monotonic Clock 판독값 및 불확실성 간격과 함께 UTC Timestamp를 기록하여, 이를 처리하는 CockroachDB에 저장합니다. 이는 한 DSP의 서버 시계가 다른 DSP보다 200ms 빠를 때조차 공정성을 보장합니다.