Development Tip - Lock
- 공부나 경험을 통해 얻은, 개발에서 활용할 내용들을 담은 포스팅
1. Redis Watch Multi 활용 해야하는 경우 ( 동시성 - 낙관적 LOCK )
- 예를들어 배달의 민족에서 주문을 하면, 라이더들이 서로 자기가 배달을 하기 위해 해당 주문을 잡는다.
- 이 때 동시에 하나의 주문을 잡을 때 동시성이 일어나서 중복으로 라이더가 주문을 잡는 일을 방지해야 한다.
- 그럴 때 Redis에서 낙관적 LOCK을 해당 key에만 걸어서
- 단 한 명의 라이더만 주문을 잡을 수 있게 처리 해야한다.
2. Redis 분산 LOCK 활용하기 ( Red-Lock )
- 레디스에는 pub sub 이라는 것이있다.
- 메시지를 받으면 subscriber 에게 메시지 전달 가능한다
- 단, Message Queue 와는 다름. Message Queue 의 경우 메시지를 받았다는 ack 가 와야 메시지 큐에서 비워지는데 Redis 는 그냥 전달한다.
- 메시지를 받으면 subscriber 에게 메시지 전달 가능한다
- 이걸 분산 LOCK으로 적용할 수 있는데, 해당 Key 값에 LOCK을 걸었다가 완료되면 해제하고를 반복한다.
- 그러면 예를들어 포인트를 사용가능한 돈으로 전환을 할 때, 악의 적인 프로그램으로 연달아 눌러서 스레드를 보내는 기능을 사용했다고 가정하면 그러한 경우 보유한 포인트보다 많은 양의 포인트가 전환되는 오류를 막을 수 있다.
3. 보상 트랜잭션 활용하기
- 예를 들어 쿠폰 발급을 100명으로 지정해놨을 때 동시성 때문에 100명 넘게 발급이 되면 안된다.
- 그럴 때 사용하는게 보상 트랜잭션이다.
- 일단 100명 넘게 발급을 하고, 넘어가는 사람들에게는 예외 문구를 보내준 뒤, Redis나 DB에서 다시 마이너스를 해주는 방식이다.
@Test public void test() throws InterruptedException { final ValueOperations valueOperations = redisTemplate.opsForValue(); blitzer.blitz(() -> { final String count5 = "count8"; final Object count1 = valueOperations.get(count5); // limit final int i = 30000; if (count1 != null && Long.parseLong(count1.toString()) > i) { return; } final Long count2 = valueOperations.increment(count5); if (count2 > i) { valueOperations.decrement(count5); //그리고 추가적으로 사용자한테 예외를 던져주는 로직이 필요함 //요청한 것이 해당 제한 범위를 넘어섯다 } }); }
- 멀티스레드 환경을 java에서 테스트 하고 싶다면, Jmock의 Blitzer를 활용할 수 있다.