Skip to content

[feat] Stock 도메인 Redisson 분산 락 기반 재고 감소 동시성 처리 적용#2

Merged
hellonaeunkim merged 17 commits into
devfrom
test/1
Jun 17, 2026
Merged

[feat] Stock 도메인 Redisson 분산 락 기반 재고 감소 동시성 처리 적용#2
hellonaeunkim merged 17 commits into
devfrom
test/1

Conversation

@hellonaeunkim

Copy link
Copy Markdown
Owner

📍 PR 타입 (하나 이상 선택)

  • 기능 추가
  • 버그 수정
  • 리팩토링
  • 기타 사소한 수정

❗️ 관련 이슈 링크

Close #1


📌 개요

  • Stock 도메인의 재고 감소 로직(decreaseStock)에서 동시 주문 요청 시 발생할 수 있는 재고 정합성 문제를 테스트로 재현하고, Redisson 기반 분산 락을 적용했습니다.
  • 동일 상품 재고 감소 요청을 상품 ID 기반 lock key로 직렬화하여 분산 환경에서도 lost update 문제가 발생하지 않도록 개선했습니다.
  • 단순 락 적용 후 트랜잭션 커밋보다 락 해제가 먼저 일어날 수 있는 문제를 확인하고, 실제 재고 감소 트랜잭션을 별도 Processor로 분리하여 락 해제 순서를 개선했습니다.
  • 락 획득 실패 시 즉시 실패하지 않고 제한적으로(3회) 재시도한 뒤, 최종 실패 시 명시적인 예외를 반환하도록 처리했습니다.

🔁 변경 사항

  • 재고 감소 동시 요청 테스트 추가

    • 동일 상품 재고 100개에 대해 100개의 스레드가 동시에 1개씩 감소 요청하는 테스트를 추가했습니다.
    • CountDownLatch를 사용해 다수의 스레드가 최대한 동시에 요청을 시작하도록 구성했습니다.
    • Redisson 적용 전 현재 구현에서 최종 재고가 기대값과 달라지는 race condition을 확인했습니다.
  • Redisson 기반 분산 락 적용

    • RedissonClient 설정을 추가하고 Redis host/port를 설정값으로 분리했습니다.
    • StockLockManager 인터페이스를 추가해 재고 서비스가 Redisson 구현체에 직접 의존하지 않도록 분리했습니다.
    • RedissonStockLockManager를 통해 상품별 lock key 기반 분산 락을 적용했습니다.
    • lock key 형식: stock:decrease:{productId}
  • 재고 감소 트랜잭션 분리

    • 기존 단순 락 적용 구조에서는 @Transactional 메서드 내부에서 락을 획득/해제하여, 락 해제가 DB commit보다 먼저 일어날 수 있는 문제가 있었습니다.
    • 이를 해결하기 위해 실제 재고 감소 DB 작업을 StockDecreaseProcessor로 분리했습니다.
    • 최종 흐름을 락 획득 → 재고 감소 트랜잭션 실행/커밋 → 락 해제 구조로 개선했습니다.
  • 락 획득 실패 처리 개선

    • 락 획득 실패 시 최대 3회까지 재시도하도록 처리했습니다.
    • 재시도 후에도 락을 획득하지 못하면 STOCK_LOCK_TIMEOUT 예외를 반환합니다.
    • 이를 통해 호출 측에서 재시도 여부를 판단할 수 있도록 명확한 실패 응답을 제공합니다.

📸 스크린샷

테스트 통과 Screenshot 2026-06-16 at 11 42 46 PM

@hellonaeunkim hellonaeunkim self-assigned this Jun 16, 2026
@hellonaeunkim hellonaeunkim added feature New or improved functionality for the product test Work related to writing, updating, or refactoring test code labels Jun 16, 2026
@hellonaeunkim hellonaeunkim requested a review from Copilot June 17, 2026 07:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stock 도메인의 decreaseStock 동시성 문제를 재현하는 테스트를 추가하고, Redisson 분산 락을 통해 상품별 재고 감소를 직렬화하여 분산 환경에서도 정합성을 보장하려는 PR입니다. 또한 락 해제 시점이 트랜잭션 커밋보다 앞설 수 있는 구조를 피하기 위해 실제 감소 로직을 별도 트랜잭션 컴포넌트로 분리했습니다.

Changes:

  • 재고 감소 단일/동시 요청(100 threads) 테스트 및 테스트용 픽스처 추가
  • RedissonClient 구성 및 StockLockManager 포트/구현체 추가로 분산 락 기반 직렬화 적용
  • 재고 감소 트랜잭션을 StockDecreaseProcessor로 분리하고 락-트랜잭션-락해제 흐름으로 변경

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
product/src/test/resources/application-test.yml 테스트 프로파일에서 DB/Redis 및 config/eureka 비활성 설정 추가
product/src/test/java/com/hubEleven/product/stock/application/service/StockServiceImplTest.java 단일 재고 감소 성공 케이스 테스트 추가
product/src/test/java/com/hubEleven/product/stock/application/service/StockConcurrencyTest.java 100개 동시 재고 감소 정합성 검증 테스트 추가
product/src/test/java/com/hubEleven/product/stock/application/fixtures/StockFixture.java 테스트용 Stock 생성/요청 생성 헬퍼 추가
product/src/test/java/com/hubEleven/product/stock/application/fixtures/ProductFixture.java 테스트용 Product 생성 헬퍼 추가
product/src/main/resources/application.yml Redis host/port 설정 추가 및 config import 변경
product/src/main/java/com/hubEleven/stock/infrastructure/lock/RedissonStockLockManager.java Redisson 기반 분산 락 실행 유틸 구현 추가
product/src/main/java/com/hubEleven/stock/infrastructure/configuration/RedissonConfig.java RedissonClient 빈 구성 추가
product/src/main/java/com/hubEleven/stock/domain/exception/StockErrorCode.java 락 타임아웃 에러 코드 추가
product/src/main/java/com/hubEleven/stock/application/service/StockServiceImpl.java decreaseStock에 분산 락 + Processor 호출 적용
product/src/main/java/com/hubEleven/stock/application/service/StockDecreaseProcessor.java 재고 감소 트랜잭션 로직 분리 컴포넌트 추가
product/src/main/java/com/hubEleven/stock/application/port/StockLockManager.java 락 실행을 위한 포트 인터페이스 추가
product/build.gradle Redisson 의존성 추가
config/src/main/resources/config-repo/product-service.yml product-service 중앙 설정에 Redis host/port 추가

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread product/src/test/resources/application-test.yml
Comment thread product/src/main/resources/application.yml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Comment thread product/src/main/resources/application.yml Outdated
Comment thread config/src/main/resources/config-repo/product-service.yml Outdated
@hellonaeunkim hellonaeunkim merged commit c5229c9 into dev Jun 17, 2026
2 checks passed
@hellonaeunkim hellonaeunkim deleted the test/1 branch June 17, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New or improved functionality for the product test Work related to writing, updating, or refactoring test code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] Stock 도메인 Redisson 분산 락 기반 재고 감소 동시성 처리 적용

2 participants