본문 바로가기
토이프로젝트/선착순쿠폰발급

[선착순 쿠폰 발급 2편] Redis 자료 구조 설계 (lua script)

by 무대포 개발자 2023. 3. 18.
728x90
반응형

source 는 Github 에 있습니다.

목차는 선착순 쿠폰 발급 에 있습니다.

[선착순 쿠폰 발급 2편] Redis 자료 구조 설계 (lua script)

코틀린, Redis 공부를 위해 작성했습니다.

쿠폰 발급 요청 처리 FLOW

  • 쿠폰 발급 요청 처리 FLOW 는 다음과 같습니다.

system architecure

Redis 자료 구조 설계

  • 쿠폰 발급 요청이 들어왔을 때 DB 처리 부하를 줄이기 위해 Redis 자료구조를 사용하여 한 번에 처리하지 않고 앞단에 Redis를 두기로 결정했습니다.
  • 또한, 여러 단계로 이뤄지는 쿠폰 ID 발급 과정에서 동시성 처리 문제를 해결하기 위해 lua script를 사용하여 처리합니다.
  • Redis 자료구조를 설계하는 두 가지 방법은 다음과 같습니다.

Redis 에 한정된 쿠폰 데이터를 미리 생성해서 분배하는 것

설명
  • 예를 들어 Redis에 Set 자료구조로 쿠폰 ID를 1000개 미리 생성합니다.
  • 사용자 요청이 들어오면 Set에서 SPOP 명령어로 쿠폰 ID를 가져옵니다. (시간 복잡도 O(1))
  • 가져온 쿠폰 ID를 가지고 Hash에 key는 userId, value는 쿠폰 ID로 저장합니다. (시간 복잡도 O(1))
  • user 중복을 막기 위해 Hash에서 userId가 존재하는지 체크합니다. (중복 방지, 시간 복잡도 O(1))
source (lua script)
"""
    -- 체크할 user Id를 매개변수로 받음
    local userId = ARGV[1]

        -- Hash에서 userId가 있는지 확인하고, 있다면 "exist"를 리턴
    local check = redis.call('HEXISTS', KEYS[2], ARGV[1])
    if check == 1 then
        return "exist"
    end

        -- Set에서 쿠폰 ID를 가져와서 제거
    local couponId = redis.call('SPOP', KEYS[1])
    if not couponId or couponId == nil then
        return "empty"
    end

        -- Hash에 쿠폰 ID를 저장
    redis.call('HSET', KEYS[2], ARGV[1], couponId)

        -- 발급된 쿠폰 ID 리턴
    return couponId
""",

요청이 들어올 때마다 쿠폰 발급 요청된 개수를 비교해 발급 요청해줄지를 결정하는 것

설명
  • 예를 들면 다음과 같습니다. 쿠폰은 최대 1000개를 발급할 수 있다고 가정하겠습니다.
  • 요청이 들어오면 Redis 에 저장된 자료구조에 데이터가 1000개를 넘었는지 체크합니다.
    • 어떤 자료구조를 써도 count 해야하기에 시간복잡도가 높게 측정됩니다.
  • 1000개가 이미 발급됐다면 더 이상 발급하지 않고, 아니라면 쿠폰을 발급해줍니다.
source (lua script)
"""
    -- 체크할 user Id를 매개변수로 받음
    local userId = ARGV[1]

    -- Hash에서 userId가 있는지 확인하고, 있다면 "exist"를 리턴
    local check = redis.call('HEXISTS', KEYS[2], ARGV[1])
    if check == 1 then
        return "exist"
    end

    -- Set에서 쿠폰 ID를 가져와서 제거
    local couponId = redis.call('SPOP', KEYS[1])

    -- Hash에 쿠폰 ID를 저장
    redis.call('HSET', KEYS[2], ARGV[1], couponId)

    -- 발급된 쿠폰 ID 리턴
    return couponId
"""

정리

  • 미리 쿠폰을 발급해둔 상태에서 쿠폰이 소진될 때까지 처리하는 방식으로 진행했습니다. 쿠폰이 다 소진됐다면 쿠폰을 발급해주는 화면에서 더 이상 쿠폰 발급 요청을 못하도록 막는 방법으로 진행하면 좋을 것 같습니다.

댓글