Conversation
…s(레디스 키를 만드는 로직), StockRedisArgs(전달될 인자 배열 만드는 로직) 추가
…ilable()메서드가 true를 반환하도록 수정
yawning5
approved these changes
Dec 24, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
Redis와LuaScript를 이용하여 부하 분산 구현시퀀스 다이어그램
Redis 기반 재고 및 부하 분산 흐름 정리
요청이 들어오면 DB에 접근하기 전, Redis의 reserve 메서드를 통해 재고 확보를 먼저 시도합니다.
Redis는 싱글 스레드 기반으로 원자적(Atomic) 연산을 수행하므로, 재고가 소진된 경우 DB 트랜잭션까지 진입하지 않고 즉시 요청을 거절합니다.
이를 통해 불필요한 DB 커넥션 점유와 락 대기 시간을 획기적으로 감소시켰습니다.
Redis 선점에 성공했더라도, 네트워크 지연이나 재시도 로직에 의해 이미 처리된 요청일 수 있습니다.
DB 트랜잭션 내부에서 Winner 테이블을 조회하여 동일한
idempotencyKey로 처리된 내역이 있는지 확인합니다.이미 처리된 요청이라면 Redis 선점 내역을 롤백(Rollback)하고, 기존 처리 결과를 반환하여 데이터 일관성을 유지합니다.
Redis와 멱등성 검증을 통과한 유효한 요청에 대해서만 DB의 비관적 락(findByIdForUpdate)을 획득합니다.
실제 재고 차감(decreaseStock)과 당첨자 생성(Winner), 로그 기록(BidInventoryLog)을 하나의 트랜잭션으로 묶어 최종적인 데이터 정합성을 보장합니다.
DB 트랜잭션 수행 중 예외가 발생하거나 비즈니스 로직(예: 판매 종료)에 의해 실패하는 경우,
stockRedisService.rollback을 호출합니다.선점했던 Redis 재고를 다시 원복시켜 Redis와 DB 간의 재고 수량 불일치를 방지합니다.
기술적 선택 이유
Redis와 Lua를 활용한
첫 번째 이유는 높은 트래픽 환경에서 원자적으로 제어할 수 있기 때문입니다.선착순 이벤트는 순간적으로 엄청난 트래픽이 몰리게 되는데 이를 감당하기 위해
디스크 기반의 MQ 보다는 인메모리 기반의 Redis가 적합하다고 판단했습니다. 또한단순 재고 차감 로직을 위해 MQ의 컨슈머를 별도로 구현하는 것은 과하다고 생각했습니다.대신 Lua Script를 활용하여 간단하게 원자적 연산을 수행하고자 했습니다.두 번째 이유는 명확한 역할 분리를 통해 DB로 몰리는 부하를 구조적으로 분산할 수 있기 때문입니다.Redis는 재고의 최종 상태를 관리하지 않고 수 많은 요청 중 일부만 선별하는 진입 제어 역할을 수행합니다.
즉,
Redis는 높은 트래픽을 먼저 받아 여기서 통과된 요청만 DB로 전달하고,DB는 제한된 요청에 대해서만 최종 재고 검증하고 확정합니다.그 외 변경된 내용
-
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()정책을 추가하여 스레드 풀이 고갈되면 작업을 수행하던 스레드가 다음 작업을 동기적으로 실행하고, 이후 다시 스레드 풀에 여유가 생기면 메인 스레드는 비동기 스레에 작업을 위임하는 방향으로 수행됨application-prod.yml추가 (Bid,Order)