Appearance
수백만 사용자의 동시 접속을 막아내는 이벤트 전시 페이지 시스템
- 초당 6만 6천 개의 요청을 처리하기 위해 CQRS 도입
- 분당 400만 요청의 대부분은 읽기 작업
- 모놀리식 아키텍처 시기 조회와 주문 생성이 동일한 데이터베이스를 바라보고, 읽기 요청의 폭주로 DB Connection Pool 고갈 > 주문 처리(쓰기)가 불가능해져 전체 서비스 마비
- CQRS 패턴 도입
- Command : 주문 생성, 재고 차감 등 데이터 일관성이 중요한 쓰기 작업은 트랜잭션 DB에서 처리
- Query : 빠르고 대규모 처리가 필요한 읽기 작업은 조회 전용 Redis 사용, 모든 상품 데이터를 사전에 가공해서 Materialized View 형태로 저장
- 최종적 일관성(Eventual Consistency) 과제 해결을 위해 CDC 파이프라인 구축
- 파이프라인에서 발생하는 몇 초간의 데이터 지연은 서비스 전체가 마비될 수 있는 위험보다 합리적인 비즈니스 트레이드오프로 판단
- 다음 문제는, Redis 데이터 압축 최적화
- 복잡한 상품 정보를 JSON 형태로 직렬화 하면 데이터 크기가 수십 KB를 넘어, 막대한 메모리 비용을 초래
- 압축률보다는 압축 해재속도와 CPU 사용량이 중요한 성능 지표 > LZ4 알고리즘 선택하여 압축
- 1KB 미만 데이터는 원문 그대로 저장, 1KB 이상 데이터는 LZ4 압축 후 저장하는 조건부 압축
- 캐시 전략
- 배포 또는 캐시 만료 직후의 Cold Start로 인한 Cahce Miss에 대한 대비가 필요
- 특정 시간에 트래픽이 몰리는 상황에서의 Colde Start는 원본 DB로 모든 요청이 한꺼번에 몰리는 Cache Stampede 현상을 유발
- 타임세일 상품과 프로모션 정보는 사전에 확정되므로 필요한 데이터를 예측할 수 있었고, 이를 Cache Warming, Cache Prefecthing으로 해결
초당 166건의 주문을 처리하기
- 이벤트 기반 아키텍처로 전환하기
- 과거의 주문처리는 거대한 동기 트랜잭션으로 동작
- 주문 유효성 검사, 쿠폰 적용, 재고 차감, 결제, 알림 발송 등 모든 작업이 순차적으로 실행되는 구조는 로직이 단순하지만 트래픽이 집중될 때 한 단계라도 지연되면 전체 트랜잭션이 연쇄적으로 지연
- Apache Kafka 메세징 플랫폼 기반 EDA > 분리와 탄력성 확보
- 주문 서비스에 도달
- 주문완료 이벤트 토픽 발행
- 사용자는 주문이 완료되었음을 확인
- 재고 / 쿠폰 / 결제 / 알림 등의 서비스들이 주문완료 이벤트를 구독하여 각자의 역할을 수행
- Saga Pattern
- 결제 실패와 같은 오류가 발생하면 보상(Compensating) 이벤트를 발행하여 이미 처리된 재고 차감 등을 취소하는 보상 트랜잭션 실행
- 안정성과 확장성 강화
- 이커머스 할인 이벤트에서 가장 치열한 전쟁터는 인기 상품의 재고
- UPDATE inventory SET quantity = quantity - 1 쿼리는 DB의 Lock Contention과 Deadlock 유발
- 요청의 성격에 따라 각기 다른 기술을 단계적으로 적용한 다층 방어 전략 구축
- 1차 : Redis를 활용한 비관적 재고 검사
- 장바구니 혹은 주문서 페이지 진입
- 원자적 연산인 INCR/DECR 활용
- 2차 : Redlock을 이용한 임계 영역(Critical Section) 보호
- 결제하기 버튼
- 실제 DB의 재고를 차감하는 코드 블록을 분산 락(Distributed Lock) 처리
- 3차 : 낙관적 락
- 재고 테이블에 version 컬럼으 추가하여 재고를 업데이트 할 때 version 값을 함께 검사
안정적인 이벤트 운영을 위한 최종 방어 : 예측과 제어
- AIOps
- 이상 징후 탐지를 정적인 임계치 대신, 머신러닝을 통해 평상시 시스템의 정상 상태를 학습하고 동적인 베이스라인을 설정
- 베이스라인을 벗어나는 미세한 변화를 감지
- 다른 시스템에서 발생한 여러 알람들을 지능적으로 묶어 이벤트 상관관계를 분석하여 하나의 인시던트로 알람
- Feature Flag
- 코드 배포 없이 런타임에 애플리케이션의 동작을 동적으로 변경할 수 있는 강력한 제어 장치
- Kill Switch - Ops Toogles
- 서비스의 핵심 기능이 아닌 경우 피처 플래그로 감싼다
- 담당 엔지니어는 문제를 감지하면 피처 플래그 관리 도구에서 스위치를 내려 해당 기능을 비활성화 가능
- Gradual Rollout - Release Toggles
- 새로운 기능을 배포할 때, 전체 사용자 중 소수에게만 기능을 노출
- 안정성이 확인되면 노출 범위를 점진적으로 확대