-
스프링의 RedisLockRegistry를 활용한 제한된 상품의 동시성 제어 및 주문 처리Tech/SpringBoot 2023. 10. 9. 15:15반응형
개요
이 포스팅에서는 스프링의 RedisLockRegistry를 활용하여 제한된 상품의 주문 처리에 대한 동시성 제어를 다루어 보겠습니다. 사용자가 동일한 제한된 상품을 구매할 때, 여러 주문 서비스 인스턴스에서 동시성 제어를 해야 할 필요가 있습니다. 이 때 RedisLockRegistry가 큰 역할을 합니다.
설정
의존성 추가
id 'org.springframework.boot' version '3.1.4' id 'io.spring.dependency-management' version '1.1.3'
먼저, 필요한 의존성을 추가합니다.
implementation 'org.springframework.integration:spring-integration-redis'
RedisLockRegistry 설정
RedisLockRegistry를 스프링 빈으로 등록합니다.
@Configuration public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory("localhost", 6379); } @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) { return new RedisLockRegistry(redisConnectionFactory, "locks"); } }
주문 처리 로직
주문 처리 로직 개요
- 사용자는 한 종류의 제한된 상품만 주문할 수 있습니다.
- 주문을 시작하면 해당 주문은 Redis 분산 락으로 보호되어야 합니다.
- 결제가 완료되면 락은 해제됩니다.
- 만약 주문이 취소되거나 결제가 실패하면 락 역시 해제되어야 합니다.
- 일정 시간 내에 결제가 완료되지 않는다면 락은 자동으로 해제됩니다.
주문 서비스 구현
아래는 위 로직을 기반으로 한 주문 서비스의 간략한 구현입니다.
@Service public class OrderService { @Autowired private RedisLockRegistry redisLockRegistry; @Autowired private OrderRepository orderRepository; public boolean processOrder(OrderRequest orderRequest, User user) { String lockKey = "product:" + orderRequest.getProductId(); Lock lock = redisLockRegistry.obtain(lockKey); try { // 락 획득 시도 (예: 최대 5초 동안 기다림) if (lock.tryLock(5, TimeUnit.SECONDS)) { // 이미 주문한 상품인지 확인 if (hasAlreadyOrdered(user, orderRequest.getProductId())) { return false; } // 주문 로직 처리... orderRepository.save(new Order(user, orderRequest.getProductId(), ...)); // 결제 로직 처리... boolean paymentSuccess = paymentProcess(orderRequest); return paymentSuccess; } else { // 락 획득 실패 (다른 사용자가 주문 중인 경우) return false; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 예외 처리 로직... return false; } finally { // 무조건 락 해제 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } private boolean hasAlreadyOrdered(User user, String productId) { // 사용자가 이미 주문한 상품인지 확인하는 로직... } private boolean paymentProcess(OrderRequest orderRequest) { // 결제 처리 로직... } }
위 로직에는 몇 가지 주요 포인트가 있습니다.
- lock.tryLock(5, TimeUnit.SECONDS): 최대 5초 동안 락 획득을 시도합니다.
- hasAlreadyOrdered(user, orderRequest.getProductId()): 사용자가 이미 상품을 주문했는지 확인합니다.
- orderRepository.save(...): 주문 로직이 처리됩니다.
- paymentProcess(orderRequest): 결제 로직이 처리됩니다.
마무리
스프링의 RedisLockRegistry를 활용하여 제한된 상품의 주문 처리에 대한 동시성 제어 방법에 대해 알아보았습니다. 분산 환경에서도 안정적으로 락을 관리하여 데이터 일관성을 유지하는 것이 중요하며, 이는 특히 e-commerce와 같이 동시성 제어가 필수적인 분야에서 더욱 그렇습니다.
반응형'Tech > SpringBoot' 카테고리의 다른 글
스프링 클라우드 스트림과 카프카를 활용한 마이크로서비스 이벤트 처리 (1) 2023.10.22 몽고디비를 활용한 주문 프로세스 관리: 스텝별 상태 저장 및 조회 (0) 2023.10.22 스프링 부트에서 외부 API 서비스를 병렬 처리하여 응답하는 방법 (0) 2023.10.09 자바의 Supplier와 Consumer 인터페이스 이해와 활용 (0) 2023.10.09 Spring Boot Config Server (0) 2023.09.29