Redis redis를 이용하여 랭킹 리더보드 구현하기

redis 이용한 리더보드

Redis를 사용하여 랭킹 리더보드를 구현 했을 때 장점

  • Redis는 In-Memory 저장소로 매우 빠른 액세스 속도를 갖습니다. 또한 자료구조(Key-Value) 특성으로 읽기 및 작업 속도를 제공합니다. 때문에 랭킹을 실시간으로 업데이트 할 수 있습니다.
  • Redis는 Sorted Set이라는 데이터 구조를 제공하여 요소를 정렬된 상태로 저장할 수 있습니다. 이 데이터 구조는 랭킹을 구현하는 데 유용합니다.

 

Sorted Set 데이터 구조 이용하기

Redis의 Soted Set 데이터 구조를 조작하기 위해 Spring Data Redis에서 제공하는 인터페이스인 ZSetOperations를 이용해주면 됩니다.

ZSetOperations 인터페이스를 통해 다음과 같은 기능을 수행할 수 있습니다.

  • Sorted Set 조작
  • 사용자의 점수를 증가 시키거나 감소
  • 사용자의 순위 조회

 

구현 코

@Service
@RequiredArgsConstructor
public class RankingService {

	private final StringRedisTemplate redisTemplate;
	
	private static final String LEADERBOARD_KEY = "Ranking_Leader_Board";
	
	public List<String> getTopRank(int limit) {
		ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
		Set<String> rangeSet = zSetOperations.reverseRange(LEADERBOARD_KEY, 0, limit - 1);
		return new ArrayList<>(rangeSet);
	}
	
	public List<String> getTopRankWithScore(int limit) {
		ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
		Set<TypedTuple<String>> rangeWithScoreSet = zSetOperations.reverseRangeWithScores(LEADERBOARD_KEY, 0, limit - 1);
		
		return rangeWithScoreSet.stream()
				.map(tuple -> tuple.getValue() + "," + tuple.getScore())
				.toList();
	}
	
	public Long getUserRank(String userId) {
		ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
		Long rank = zSetOperations.reverseRank(LEADERBOARD_KEY, userId);
		return (rank != null) ? rank + 1 : null;
	}
	
	public boolean setUserScore(String userId, int score) {
		ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
		zSetOperations.add(LEADERBOARD_KEY, userId, score);
		return true;
	}
	
	public boolean removeUser(String userId) {
		ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
		return zSetOperations.remove(LEADERBOARD_KEY, userId) > 0;
	}
}