학습일지/Redis

[Redis 맛보기] Sorted Set 활용 - 리더보드

Merge Log 2025. 10. 21. 15:57

Redis 를 활용하면 리더보드(순위표), 장바구니 등을 간단히 구현할 수 있다

여기서는 리더보드를 구현하는 테스트를 진행한다

  • 요구사항 : 제일 많이 구매한 상품 10개 조회

ERD

  • Product 와 Order 추가

Sorted Set 을 활용한 리더보드 구현

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, ProductDto> rankTemplate(
            RedisConnectionFactory redisConnectionFactory
    ) {
        RedisTemplate<String, ProductDto> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.json());
        return template;
    }
}
  • 사용할 RedisTemplate 를 빈으로 정의
  • application.yml 기준으로 설정된 커넥션을 연결
@Service
@RequiredArgsConstructor
public class ProductService {
    private final ProductRepository productRepository;
    private final OrderRepository orderRepository;
    private final RedisTemplate<String, ProductDto> rankTemplate;

    public void purchase(Long id) {
        Product product = productRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));

        ZSetOperations<String, ProductDto> rankOps = rankTemplate.opsForZSet();
        orderRepository.save(new Order(product));

        rankOps.incrementScore("soldRanks", ProductDto.from(product), 1);
    }

    public List<ProductDto> getMostSold() {
        Set<ProductDto> ranks = rankTemplate.opsForZSet().reverseRange("soldRanks", 0, 9);

        if (ranks == null) {
            return Collections.emptyList();
        }

        return ranks.stream().toList();
    }
}
  • 상품 구매와 많이 팔린 상품 조회 구현
  • 상품 구매시 DB에 데이터를 저장하고 기존에 정의했던 RedisTemplate 에서 ZSET 연산을 활용하여 스코어를 1로 정의
    • ZADD 를 하지 않은 이유는 순위표 특성상 INC 연산만 수행하면 되므로 굳이 필요없음
    • 더불어 초기 데이터가 없는 상황에서도 INC 연산을 수행하면 자동으로 데이터를 생성하고 작업을 수행한다
  • 역순으로 0 ~ 9 까지 데이터 조회

이를 만약 DB 쿼리로 조회해야 한다면

SELECT p.name, SUM(o.count)
FROM products p
    JOIN orders o
    ON p.id = o.product_id
GROUP BY p.id
ORDER BY SUM(o.count) DESC
LIMIT 10
  • 위와 같은 쿼리로 매번 요청마다 DB 접근을 수행해야함
  • 더불어 요청마다 집계함수를 실행하므로 효율적이지 않음

테스트 코드

'학습일지 > Redis' 카테고리의 다른 글

Redis Purge 를 사용할 경우 문제점  (1) 2025.10.23