003 Huge Traffic Handling

우아콘 2023, 우아한 형제들 세션 정리 #

대규모 트랜잭션을 처리하는 배민 주문시스템 규모에 따른 진화 #

성장통들 #

img.png

  • 개선 대상 리스트
  1. 단일 장애 포인트
  2. 대용량 데이터
  3. 대규모 트랜잭션
  4. 복잡한 이벤트 아키텍처

단일 장애 포인트 #

  • 루비라 불리는 중앙 집중 저장소에 모든 시스템이 의존 img_1.png

  • 중앙 저장소의 부하 발생 img_2.png

해결 #

  • 중앙 저장소 -> 각 시스템을 분리하는 프로젝트 진행 img_3.png

  • 시스템 간 통신은 Message Queue 기반으로 통신 img_4.png

  • 특정 시스템의 장애는 메시지 발행의 실패로 끝 img_5.png

정리 #

중앙 집중 DB의 장애, 전체 시스템의 전파 -> MQ를 이용한 이벤트 기반 통신으로 시스템간 영향도를 분리

대용량 데이터 #

  • 주문 아키텍처 img_6.png

  • 정규화된 주문 DB에서 저장 + 조회가 함께 발생 img_7.png

  • 주문 내역 정보에는 많은 정보가 포함되어있음 img_8.png

해결 #

  • 정규화된 주문 애그리거트는 수많은 조인이 발생 -> 조회 성능을 높이기위해 단일 도큐먼트로 역정규화 img_9.png

  • 단순 단일 도큐먼트 조회만으로 주문 정보를 가져올 수 있음 (with MongoDB) img_10.png

  • 주문 도메인 생명주기 : 주문 도메인은 생명주기에서만 도메인 변경이 발생 img_11.png

  • 주문 도메인 생명주기에 발생되는 도메인 이벤트를 통해 데이터 동기화 수행 img_12.png

  • CQRS 적용 아키텍처 : 저장과 조회를 분리한 아키텍처 img_13.png

정리 #

대용량 데이터 RDB 조회 성능 저하 -> 커맨드 모델과 조회 모델을 분리, 조회 모델 역정규화를 통해 조회 성능 개

대규모 트랜잭션 #

  • 주문 DB의 분당 쓰기 처리량 한계치 도달 img_14.png

  • 쓰기 요청의 증가 : 스펙업으로 대응 (최고사양의 스펙으로도 처리량을 감당 불가능) img_15.png

해결 #

  • 샤딩

  • 애플리케이션 샤딩 구현

    • 고민 1) 샤드 클러스터 내 어느 샤드에 접근할지 결정하는 샤딩 전략
    • 고민 2) 여러 샤드에 있는 데이터를 애그리게이트 하는 방법에 대한 고민
  • 샤딩 전략

      1. Key Based Sharding : Shard Key를 이용하여 데이터 소스를 결정하는 방식 (Hash Based Sharding)
      1. Range Based Sharding : 값의 범위(Range) 기반으로 데이터를 분산시키는 방식
      1. Directory Based Sharding : 샤드가 어떤 데이터를 가질지 look up table을 유지하는 방식

1. Key Based Sharding #

img_16.png

  • 장점 : 구현 간단, 데이터를 샤드에 골고루 분배 가능
  • 단점 : 장비를 동적으로 추가, 제거할때 데이터 재배치 필요

2. Range Based Sharding #

img_17.png

  • 장점 : 특정 값의 범위 기반으로 샤드를 결정하면 되기 때문에 구현이 간단
  • 단점 : 데이터가 균등하게 배분되지 않아 특정 샤드에 데이터가 몰리면 Hotspot이 되어 성능 저하 발생

3. Directory Based Sharding #

img_18.png

  • 장점 : 샤드 결정 로직이 Look Up Table로 분리되어있어 동적으로 샤드 추가하는데 유리
  • 단점 : 단일 장애 포인트

주문 시스템의 특징 주문이 정상 동작하지 않으면, 서비스 전체의 좋지않은 경험으로 이어지고, 동적 주문 데이터는 최대 30일만 저장한다. -> 단일 장애 포인트를 피하고, 샤드 추가 이후 30일이 지나면 데이터는 다시 균등하게 분배된다.

샤드키 주문번호를 통해 주문 순번을 알 수 있다. -> B1MU00584X : 주문순번 % 샤드 수 = 샤드번호

정리 #

img_19.png 주문번호 샤드키를 이용한 해싱은 주문 순번 순으로 샤드에 고르게 분배된다.

  • 다건 조회는 대용량 처리르 위해 몽고DB를 활용했고, 저장&조회 로직을 분리해둔 덕분에 애플리케이션 샤딩 적용시 큰 도움이 되었다.

    • N개의 샤드에 분산 저장된 데이터를 조합하여 내려주는것을 해결할 수 있었음 img_21.png
  • 쓰기 요청 증가 스케일 아웃 대응 img_20.png 샤딩으로 인해 증가하는 트랜잭션을 스케일 아웃으로 대응 가능

  • 샤딩이 적용된 아키텍처 모습 img_22.png

복잡한 이벤트 아키텍처 #

  • 규칙성 없는 무분별한 이벤트 발행

  • 주요 도메인 로직과 서비스 로직을 이벤트 기반으로 관심사를 분리 img_23.png

  • 주문 시스템의 이벤트 아키텍처 img_24.png

  • 문제점1. 스프링 애플리케이션 이벤트는 로직을 수행하는 주체를 파악하기 어려움 img_25.png

  • 문제점2. 이벤트 유실이 발생할 경우 재처리가 어려움 img_26.png

해결 #

  • 내부 / 외부 이벤트 정리 img_27.png

  • ZERO Payload 이벤트 처리기가 모든 서비스 로직을 처리 필요한 데이터는 주문저장소(MongoDB) 조회 img_28.png

  • 이벤트 처리 주체의 단일화 img_29.png 네트워크 비용보다 이벤트 처리 주체의 단일화에 이점이 있다.

또다른 문제 #

  • 이벤트 발행 실패 유형 img_30.png

  • 트랜잭션 내부 외부에서 발행 실패 유무에 따라 처리가 달라진다. img_31.png

해결 #

  • 트랜잭션 아웃박스 패턴

    • 이벤트 발행 실패와 서비스 실패를 격리하여 재발행 수단을 보장한다. img_33.png
  • 이벤트 발행 실패시, OUTBOX 엔티티에 저장된 페이로드를 재발행한다.

    • 유실된 데이터를 배치로 재발행 img_34.png

정리 #

규칙성 없는 무분별한 이벤트 발행 -> 이벤트 로직을 단일 애플리케이션에 위임하여 관리 포인트를 집중