-
redis를 활용한 동시성 문제 해결 - 1. Lettuce백엔드 관련 강의 공부/동시성 이슈 - 재고시스템 2024. 2. 4. 14:11
Lettuce 라이브러리는 setnx 명령어를 활용하여 분산락을 구현하는 방식이다. setnx 명령어는 key와 value를 set할 때 기존의 값이 없을 때에만 set을 하는 명령어이다. setnx를 이용하는 방식은 spin lock 방식이므로 retry 로직을 개발자가 직접 작성해야 한다.
setnx에 대해 설명하기 위해 터미널에서 도커로 docker exec -it <container_id> redis-cli를 통해 레디스에 접속해서 명령어를 입력했다. setnx <key> <value> 형태로 입력을 했는데, 처음의 setnx 1 lock은 key가 1인 값이 없기 때문에 1을 반환해준다. 그 이후에는 key가 1인 값이 존재하기 때문에 0을 반환해주고, del 1로 삭제한 다음에 setnx 1 lock을 하면 다시 1을 반환해준다.
위의 방식을 코드로 구현해서 spin lock을 구현한다.
RedisLockRepository.class
@Repository @RequiredArgsConstructor public class RedisLockRepository { private final RedisTemplate<String, String> redisTemplate; public Boolean lock(Long key) { return redisTemplate .opsForValue() .setIfAbsent(generateKey(key), "lock", Duration.ofMillis(3_000)); } public Boolean unlock(Long key) { return redisTemplate.delete(generateKey(key)); } private String generateKey(Long key) { return key.toString(); } }
우선 redis를 사용해야되기 때문에 redis repository를 만들어준다. 로직 실행 전에 key와 setnx 명령어를 통해 lock을 하고, 로직이 끝나면 unlock 메서드를 통해서 lock을 해제한다.
@Component @RequiredArgsConstructor public class LettuceLockStockFacade { private final RedisLockRepository redisLockRepository; private final StockService stockService; public void decrease(Long id, Long quantity) throws InterruptedException { while (!redisLockRepository.lock(id)) { Thread.sleep(100); } try { stockService.decrease(id, quantity); } finally { redisLockRepository.unlock(id); } } }
만약에 lock이 사용중이어서 setnx 명령어를 통해 lock을 하지 못한다면 Thread.sleep(100);으로 while문을 반복하고, lock을 획득한다면 decrease를, 로직이 정상적으로 수행되면 마지막에 unlock을 해주는 로직이다.
'백엔드 관련 강의 공부 > 동시성 이슈 - 재고시스템' 카테고리의 다른 글
redis를 활용한 동시성 문제 해결 - 2. Redisson (0) 2024.02.04 mysql을 활용한 동시성 문제 해결 - 3. Named Lock (0) 2024.02.03 mysql을 활용한 동시성 문제 해결 - 2. Optimistic Lock (0) 2024.02.03 mysql을 활용한 동시성 문제 해결 - 1. Pessimistic Lock (0) 2024.02.03 재고 시스템에서 동시성 문제 (0) 2024.02.03