ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Boot + Redis 대기열 시스템 만들어보기 - 이론편
    프로젝트/선착순 쿠폰 발급 시스템 2023. 10. 29. 00:01
    728x90

    개요

    이전부터 만들어보고 싶었던 대기열 시스템을 만들어보고자 합니다!

    일시적으로 많은 트래픽이 발생하는 경우에 과도한 트래픽의 유입을 방지해 주는 대기열 시스템입니다.

    특정 이벤트가 있을 때 예측된 트래픽을 대비하여 Scale out 할 수 있지만 폭주하는 짧은 기간이 지나가면 대부분의 자원들은 낭비됩니다.

    이런 상황일 때 대기열 시스템을 도입할 수 있습니다.

     

    Redis 활용 이유

    • redis의 자료구조 중 sorted set을 활용하게되면 rdb를 활용하는 것보다 성능적인 면에서 우수합니다.
    • Redis는 In-memory 저장소로 높은 처리량을 가지고 있기 때문에 많은 트래픽을 잘 버틸 수 있습니다.
    • 많은 트래픽이 한번에 DB로 부하가 가지 않게 됩니다.

     

    Redis Sorted Set이란?

    score에 따라 정렬되는 고유한 members의 모음입니다.

    A와 B의 점수가 다른경우에 A.score > B.score 라면 A > B입니다.

    A와 B의 점수가 같은 경우에는 A 문자열이 사전적으로 B 문자열보다 크면 A > B입니다.

    A와 B는 members의 모음으로 고유한 요소로만 구성되어 있어야 해서 같을 수 없습니다.

     

    ZADD을 활용하여 score, member를 넣어 줄 수 있으며 넣을 때마다 O(log(N)의 시간복잡도가 소요됩니다.

    > ZADD racer_scores 10 "Norem"
    (integer) 1
    > ZADD racer_scores 12 "Castilla"
    (integer) 1
    > ZADD racer_scores 8 "Sam-Bodden" 10 "Royce" 6 "Ford" 14 "Prickett"
    (integer) 4

     

    ZRANGE를 통해 score의 순서대로 조회할 수 있습니다.

    > ZRANGE racer_scores 0 -1
    1) "Ford"
    2) "Sam-Bodden"
    3) "Norem"
    4) "Royce"
    5) "Castilla"
    6) "Prickett"

    이때 0과 -1은 0번째 index부터 -1(마지막 요소까지)를 의미합니다.

     

    어떻게 구현할 것인가?

    • 1. 유입된 시간에 맞춰 대기열에 추가하며 순번을 부여해야 한다.

    사용자의 request time을 unixTimeStamp로 변경하여 score로, 사용자의 id를 member로 사용하는 아이템을 sorted set에 저장하여 설정한 유입량에 따라 처리를 수행합니다.

     

    Redis의 ZADD 명령어 활용 O(log(N))

     

    • 2. 사용자의 자신의 순번을 확인할 수 있어야 한다.

    사용자는 자신의 id를 넘기면 자신의 몇 번째 사용자인지 알 수 있어야 합니다.

     

    Redis의 ZRANK 명령어 활용 O(log(N))

     

    • 3. 대기열에 순번이 도달한 사용자는 대기열에서 제외됩니다.

    Redis의 ZREM 명령어 활용 O(M*log(N))

     

    • 4. 자신의 순번에 도달한 경우에는 알 수 있어야 한다 (Optional)

    SSE(Server Sent Event) 등으로 Client에게 push 해주거나, Polling 방식을 활용할 수 있습니다.

     

     

    서버 아키텍처 구상도

    https://jgrammer.tistory.com/entry/Redis%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%A0%EC%B0%A9%EC%88%9C-%EC%BF%A0%ED%8F%B0-%EB%B0%9C%EA%B8%89-%EC%84%9C%EB%B2%84-%EC%84%A4%EA%B3%84

    대기열 관련 서버는 등록과 조회에 관한 일만 수행합니다.

    등록은 ZADD NX 명령어, 대기열 순위 조회는 ZRANK 명령어를 활용할 수 있습니다.

     

    쿠폰 발급 서버의 핵심은 선착순으로 대기열에 있는 발급 대상을 가져와서 쿠폰을 발급하는 것입니다.

    ZPOPMIN 명령어를 사용하면 score(여기서는 timestamp)가 작은 순으로 가져옵니다.

    하지만 이때 선착순 로직을 병렬로 처리한다면 동시성 문제도 해결해주어야 합니다.

     

    동시성 문제는 Redis의 분산락을 활용하여 해결해 줄 수 있습니다.

     

     

     

    참고자료

    https://www.youtube.com/watch?v=MTSn93rNPPE&t=710s 

    https://redis.io/docs/data-types/sorted-sets/

    https://velog.io/@hgs-study/redis-sorted-set

    https://moonsiri.tistory.com/156

    https://jgrammer.tistory.com/entry/Redis%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%A0%EC%B0%A9%EC%88%9C-%EC%BF%A0%ED%8F%B0-%EB%B0%9C%EA%B8%89-%EC%84%9C%EB%B2%84-%EC%84%A4%EA%B3%84

     

    댓글

Designed by Tistory.