‘오늘의집’이 CPC 광고 시스템을 도입하면서 예산 충전과 클릭당 차감을 실시간으로 처리하고, 중복 처리를 방지하기 위해 Kafka Streams를 도입하게 된 사례
문제점: 모든 클릭 요청은 Kafka Topic의 메시지로 들어오게 된다. Kafka와 RDB만으로 설계했을 경우, 정산 처리 단계 중 클릭에 따른 예산 차감이 실패하게 되었을 때 Topic offset이 commit되지 않았다면, 재시도 로직에서 예산 차감이 중복될 수 있다.
개선 방향1: RDB 테이블에 예산 차감 히스토리 목적으로 Topic offset을 저장해서 Consumer가 처리할 현재 Offset보다 높은 경우, 처리하지 않고 Offset을 Commit하는 방법
단점1: 정산 처리 비즈니스 로직과 중복 처리 방지 로직이 함께 구현되어 복잡성 증가
단점2: 모든 클릭 로그를 저장해야 하기 때문에 RDB 부하가 발생할 수 있다.
개선 방향2: Kafka Streams (클라이언트 라이브러리)로 exactly-once 처리하기
제약 사항: RDB 같은 외부 연동이 포함된 경우, exactly-once를 보장하지 못 한다.
해결: in-memory DB(state store) 활용
정산처리 애플리케이션 안에 Kafka Streams 구현과 in-memory DB를 포함하고 있게 된다.
애플리케이션이 재시작될 경우 in-memory DB의 데이터가 사라지는 것을 복구하기 위해 in-memory DB에 저장되는 모든 데이터를 Kafka topic으로 전송. 애플리케이션이 재시작될 때 이 Topic에서 메시지를 읽어와 마지막 데이터 상태를 유지
in-memory DB에 저장될 데이터를 Topic에 전송하는 것과 클릭 로그 Topic offset을 commit하는 작업이 Atomic함을 보장하기 위해 Kafka Transaction을 활용
예산 차감 처리 내역을 별도 Topic에 저장하고, 이 메시지를 Kafka Connect를 통해 S3로 저장. Apache Spark으로 일별 통계 계산 후 RDB 저장
결론
장점
Kafka Streams의 exactly-once 기능 덕분에 비즈니스 로직에만 집중할 수 있다.
in-memory DB를 활용하기 때문에 빠르다. (예: 예산 조회)
처리량 부하에 따라 스케일 아웃이 용이하다.
단점
새로운 것에 대한 거부감?
(내 생각) Kafka Streams가 어려워서?
Tech Video
INFCON 2023 - EKS 비용 절감 전략 (회사에서 실현한 사이드 프로젝트의 아이디어)