Kafka와 Redis로 초과 발급 없는 쿠폰 시스템 구축하기

배상규·2025년 3월 25일
1

프로젝트를 진행하면서 선착순 쿠폰 발급을 진행시 중복발급이 발생하여 이를 해결하기 위해 여러 고민들을 하였고 Kafka + Redis를 활용한 대기열 시스템으로 개발하였습니다.

1. 기존 문제점

case
이벤트성 상품 할인 쿠폰 이벤트 시 중복하여 쿠폰이 발생하는 경우

이러한 문제점이 발생했습니다, 그렇담 왜 이러한 중복 발급이 발생하는걸까요?

선착순 쿠폰 발급을 동시에 많은 사용자가 요청 시 쿠폰 수량을 줄이기전에 다른 트랜잭션이 읽을 경우 중복 발급이 발생되어집니다.


모색 방안

현재 프로젝트의 경우 분산환경에서 N개의 서버를 구동중에 있습니다.

낙관적락 비관적락

이러한 락을 처리하기 위해 보편적으로 많이 사용하는 낙관적락 비관적락이 있으나 현재 저의 상황에서는 맞지 않다 판단하여 적용하지 않았습니다.

1. 낙관적 락을 채택하지 않은 이유

  • 낙관적 락은 version 필드를 활용하여 동시성을 제어하는데, 쿠폰 발급 요청이 동시다발적으로 들어오는 상황에서는 충돌이 빈번하게 발생하여 롤백을 직접 해주어야 하기에 성능이 저하되었고, 때문에 이를 채택하지 않았습니다.

2. 비관적 락을 채택하지 않은 이유

  • 비관적 락은 하나의 트랜잭션이 특정 데이터(쿠폰)를 갱신하는 동안 다른 트랜잭션의 접근을 차단하는 방식입니다. 이런 경우 데이터베이스 락이 병목이 발생하여, 성능 저하가 발생하여 이를 채택하지 않았습니다.

그럼에도 불구하고 낙관적 락, 비관적 락은 많은 부하가 있지 않은 경우 훌륭한 선택지가 될 수 있다고 생각합니다.

Redisson 기반 Redis 분산락 적용

기존의 Lettuce 방식은 스핀락 기반으로 동작하여 Redis에 지속적으로 요청을 보내는 방식이었습니다. 이는 Redis 부하를 유발하는 단점이 있었기 때문에, Redisson의 Pub/Sub 기반 분산락을 적용하여 성능을 개선하였습니다.

Redisson 적용 장점:

  • 불필요한 Redis 요청 감소: 락 대기 시 Pub/Sub 방식으로 이벤트를 수신하여, 스핀락 방식보다 효율적으로 관리 가능
  • 데드락 방지: 락의 만료 시간을 설정하여 불필요한 리소스 점유 방지

분산 락을 적용하지 않은 이유

  • 부하테스트 시 높은 동시 요청이 발생하면 TPS 감소 및 서버 부하 증가 문제가 발생하여 이를 채택하지 않았습니다.

여러 서버가 있는 분산 환경에서 분산락은 좋은 선택지가 될 수 있다 생각합니다.


Kafka 대기열 + Redis Sorted Set 적용

앞선 문제들을 해결하기위해 Kafka + Redis를 활용한 대기열을 도입하였습니다.

아키텍처

주요 방식

1. Kafka를 활용한 요청 대기열 구성

  • 사용자가 쿠폰을 요청하면, Kafka Producer가 해당 요청을 메시지로 변환하여 대기열(Kafka 토픽)에 전송합니다.
  • 이때, Kafka 브로커 개수, 파티션 수, ISR 등의 설정을 최적화하여 메시지가 빠르고 안정적으로 처리되도록 구성하며. (추후 이부분에 대한 게시글 작성하겠습니다.)
  • 대기열 서버에서 순차적으로 요청을 처리하여 과부하를 방지합니다.

2. Redis Sorted Set을 활용한 쿠폰 발급 요청 정렬

  • Redis sorted Set을 활용하면 중복 요청 방지 및 순서 보장이 가능합니다.
  • Kafka에서 전달된 요청을 도착 시간 기준으로 Redis Sorted Set에 저장 합니다.

3. 쿠폰 발급 배치를 활용한 빠른 Insert 처리

  • 배치 서버에서 Redis에 적재된 시간순으로 적재된 발급정보들을 읽어옵니다.(지정된 수 만큼)
  • JDBC Bulk Insert를 활용하여 DB에 적재합니다.
  • Redis에 저장된 정보를 삭제하며, 중복 발급 방지를 위한 TTL 설정이 포함된 정보를 Redis에 다시 적재하게 됩니다.

성능 비교

락 적용 X 기본

쓰레드호출수TPS초과발급수
28,597152.4247
410,793191.6672
812,613231.31353
1013,947247.31678
1614,836253.42850

4-2-2 redis Redission (pub/sub)분산락 적용

쓰레드호출수TPS초과발급수
24,13276.10
44,65382.70
84,67785.10
104,71786.80
166,243110.90

4-2-3 kafka + redis 대기열 시스템 적용

쓰레드호출수TPS초과발급수
227,119500.90
432,530820.00
837,742751.10
1039,542758.40
1646,382882.30

효과

  • 쿠폰 초과 발급(동시성) 문제 해결 - Kafka 대기열과 Redis Sorted Set을 활용해 요청을 순차적으로 처리하면서 동시성 문제를 해결 하였습니다.
  • 서버 부하 감소 - Kafka가 요청을 분산 처리하면서 서버의 부하를 효과적으로 분산할 수 있었습니다.

마지막으로

선착순 쿠폰 발급 시스템의 초과 발급 문제를 해결하기 위해 Redis 기반 분산락과 Kafka 대기열 시스템을 비교해 개발을 진행해 보았습니다.

최종적으로 Kafka와 Redis Sorted Set을 활용한 대기열 시스템이 높은 성능을 보이며, 초과 발급을 방지하면서도 빠른 응답성을 유지할 수 있었습니다.

선착순 쿠폰 발급뿐만 아니라 동시 요청이 많은 서비스(티켓팅, 한정판 판매 등) 에서도 활용할 수 있다 생각하며 오늘의 글은 여기 까지 작성하도록 하겠습니다.

profile
기록에 성장을

0개의 댓글