본문 바로가기
SpringBoot

Redis를 활용한 레이스 컨디션 개선.

by jisung-kim 2023. 11. 30.
레이스 컨디션이란?

멀티쓰레드 환경에서 공유자원을 경합하며 벌어지는 동기화 문제가 발생한 현상.

 

 

 

레디스의 INCR 활용한 간단한 해결방안

 

INCR은 Redis에서 제공하는 명령 중 하나로, "increment"의 약어이다. 이 명령은 키에 저장된 값이 정수일 경우에만 사용할 수 있다. 키에 저장된 값을 1씩 증가시킨다.

 

 

 

SET mykey 10
INCR mykey

 

위 예제에서 mykey의 초기 값은 10으로 세팅했다. INCR mykey를 실행하면 mykey의 값이 1이 증가하여 11이 된다.

이 명령은 분산 환경에서도 안전하게 사용할 수 있어서,

여러 클라이언트가 동시에 INCR을 실행해도 서로 간섭 없이 값이 증가한다

 
 

코드를 통해 알아보자 

 

@Repository
public class RedisRepository {

    private final RedisTemplate<String,String> redisTemplate;

    public CouponCountRepository(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public Long increment(){
        return redisTemplate
                .opsForValue()
                .increment("coupon_count"); // incr coupon_count
    }
}

 

Service로직

 

    /**
     * 레디스의 incr을 활용한 레이스컨디션 해결
     * @param userId
     */
    public void apply(Long userId){
       long count =  redisRepository.increment();

       if(count > 100){
           return;
       }
       couponRepository.save(new Coupon(userId));
    }​

 

테스트

 

    @Test
    public void 쿠폰100개까지만받기() throws InterruptedException { 
        int threadCount = 1000;
        ExecutorService executorService = Executors.newFixedThreadPool(32);
        CountDownLatch latch = new CountDownLatch(threadCount);

        for(int i=0; i< threadCount; i++){
            long userId = i;
            executorService.submit(()->{
                try{
                    applyService.apply(userId);
                }finally {
                    latch.countDown();
                }
            });

        }
        latch.await();

        long count = couponRepository.count();
        assertThat(count).isEqualTo(100);
    }

 

 

 

레디스의 INCR명령어를 활용한 레이스컨디션 해결방법을 알아보았다.

폭발적인 트래픽이 발생한다면 이 방법은 에러를 내게된다.

이럴때는 또 다른 해결방안인 카프카를 활용하는 방법, 락을 사용하는 방법 등이 있다.