Dico

if (kakao) dev 2019, Day 1 - 초당옥수수의 취소를 막아라! : 수만 건의 주문을 1초내에 처리하는 기술 요약

초당옥수수란? Super Sweet Corn!

구매자 → 주문 → 판매자 → 2~3주 → 수확 → 택배 발송

    농산물, 특히 과일은 우천 시 당도가 떨어져 배송 지연이 발생할 수 있다. 비를 맞게 되면 마르고나서 수확해야 당도가 떨어지지 않는다. 당도를 유지하기 위해 배송 지연이 발생할 수 있다.

결제완료 → 배송 요청 → 배송 준비 중 → 배송 중

    결제 완료와 배송 준비 중 사이에 결제 취소가 가능하다. 구매자가 무작정 결제 취소를 할 수 없도록 막기 위하여 판매자에게는 배송 지연 처리라는 기능이 제공 된다.

레거시 시스템이 가진 문제

    배송지연 안내를 위해 타겟 메세징 시스템(이하 TMS) 배치 수행하고 있었다. 배치 주기는 1시간 간격이었으며, 복잡한 비즈니스 로직을 담고 있었다. 심지어 내부는 스파게티 코드로 이루어져 있었고, 처리 속도 또한 느렸다. 단일 스레드에서 테스크를 반복적으로 수행하였고, 배송지연 안내 요청을 받은 대량 주문 리스트가 많았다.

우리의 미션

    실시간 TMS 발송을 위한 워커를 구성하였다. 하지만 이슈가 존재하였는데, TMS 명세 종류가 300개가 넘었다. 또한 주문 DB 등 추가적으로 필요한 정보가 매우 많았다. 따라서 실시간으로 처리할 경우 성능적인 제약사항이 컸다.

  • before: 1단계, 배송 지연 처리 / 2단계, TMS 발송 배치 실행
  • after: TMS 발송 비동기 워커

코드 리펙토링

    Request에 대하여 앞단에서 간단한 유효성 검증을 처리하였다. 단순 데이터에 대한 Validation으로 데이터 형식이 맞는지, 값Value는 존재하는지 앞단에서 체크하였다. 비즈니스와 관련 된 유효성 검증과 분리하도록 전반적인 코드 형식을 정하였고, 이를 통해 가독성을 높이고자 하였다.

    한 편, 그동안 반복 되는 테스크 수행시 병목이 발생했었다. 그로 인하여 모든 테스크가 끝날 때까지 많은 시간이 소요되었다. 비즈니스 로직 처리가 대부분의 테스크 수행 시간을 차지하고 있었다. 이를 해소하기 위하여 비즈니스 로직 처리를 비동기 워커를 통해 분산 처리하도록 변경하였다.

Validation → 비즈니스 비동기 워커 → TMS 발송 비동기 워커

액터가 된 비동기 워커

    신뢰할 수 있는 비동기 시스템을 만들기 위하여 다음과 같이 시스템을 구성하였다.

분산처리

    머신 당 Consumer를 늘리면 처리 속도가 증가한다. Consumer가 아토믹한 처리를 할 수 있도록 구현하여 작업 결과가 서로에게 영향을 미치지 않도록 처리하였다. 최소, 최대 Consumer 갯수 설정은 서비스에 맞추어 지정하였다.

자동 재처리 및 실패 감지

    Consumer에서 처리 중 예외가 발생하면 재처리할 수 있도록 자동화 구성을 하였다. 또한 실패 감지할 수 있도록 시스템에 구현하였다.

Publish → Queue → get ACK/NACK → Custom Interceptor → Job → DB/MSG

구현, RabbitMQ

    메세지 해더와 큐 속성을 활용하여 재처리/실패 전략을 수립하기 위해 RabbitMQ를 선택하였다. 액터는 쉽게 확장이 가능해야 하기 때문에 스케일업에 집중하였고, 이를 통해 처리 속도를 개선하였다.

배포없이 빠르게 롤백하는 전략

    코드 내에 온오프 스위치를 만들어 빠르게 로직을 스위칭할 수 있도록 구현하였다. 단순히 True/False 뿐만 아니라 퍼센트 지정을 하여 일부 서버에서 실시간 테스트를 할 수 있도록 구성되어 있다. 주키퍼에 있는 설정 값에 따라 배포 없이 Watcher로 읽고 처리하도록 만들었다.

참조: https://if.kakao.com/program?sessionId=0a88f257-fac7-451a-bf4a-2f20d6ca1137