반응형
개요
이 포스팅에서는 스프링의 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와 같이 동시성 제어가 필수적인 분야에서 더욱 그렇습니다.
반응형
'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 |