Skip to content

Redis을 이용한 투표 랭킹 시스템에서 동점자 처리 방법 고민 #9

@Yiseull

Description

@Yiseull

📍 상황

Redis의 Sorted Set을 사용하여 투표에 대한 랭킹 시스템을 구현했다. Sorted Set은 score가 높은 순으로 정렬되는 특징을 가지고 있고, 현재 랭킹에서는 진행 중인 투표 참여자 수를 score로 하고 있다.

score가 같을 때 동점자 처리를 해줘야 하는 상황에 부딪혔고, 효율적인 동점자 처리 방법에 대해 고민하게 되었다.

동점자 처리에 대한 요구사항

  • score가 동점일 때는 투표 마감 시각이 더 임박한 쪽(투표 마감 시각이 더 빠른 쪽)이 더 높은 랭킹을 가지도록 해야 한다.

📍 생각한 구현 방법

동점자 처리를 위해 세 가지 방법을 생각해 봤다.

  1. Application 단에서 처리
  2. value에 시간에 따른 정렬 값을 추가하여 처리
  3. score 값을 정수부(투표 참여자 수)와 소수부(투표 마감 시각에 따른 정렬 값)로 분리하여 처리

1. Application 단에서 동점자 처리 (기각)

첫 번째 방법은 Application 단에서 동점자 처리를 하는 것이다. 이 방법은 레디스에서 랭킹을 조회한 후 동점자에 대해 투표 마감 시각이 더 빠른 순으로 또 다시 정렬을 하는 것이다.

그러나 이 방법을 사용하면 Redis를 자동 정렬을 위해 사용한 의미가 흐려지게 된다. 또한 복잡한 재정렬 코드가 추가되면서 관리 측면에서 효율적이지 않다고 판단하였다.

2. value에 시간에 따른 정렬 값을 추가하여 처리

두 번째 방법은 value에 시간에 따른 정렬 값을 추가하여 처리하는 것이다. Redis의 Sorted Set은 score 값이 같을 때 value 값이 사전적으로 큰 순으로 정렬된다. 현재 value는 String 타입이 아닌 Object 타입이므로 JSON 형태로 직렬화해 Redis에 저장하고 있다. 이 경우, 동점자가 발생했을 때 정렬 순서는 JSON의 순서 그대로 id, item1Image, item2Image, participants 필드의 순서에 따라 결정된다.

이 문제를 해결하기 위해 value에 투표 마감 시각을 가지고 만든 정렬 값을 맨 앞 필드에 두면, 동점자일 경우 투표 마감 시각이 더 빠른 투표가 높은 순위를 가지도록 처리할 수 있다.

여기서 투표 마감 시각을 이용한 정렬 값은 투표 마감 시각을 숫자로 변환한 후 큰 값에서 빼준 값이다. 이렇게 하면 투표 마감 시각이 더 빠를수록 더 높은 순위를 가질 것입니다.

아래는 value로 사용하고 있는 레코드이고, 맨 앞 필드에 secondSortValue라는 투표 마감 시각을 이용한 정렬 값을 추가한 것이다.

@Builder
public record VoteRankingInfo(
        double secondSortValue // 투표 마감 시각에 따른 정렬 값 추가
	Long id,
	String item1Image,
	String item2Image,
	int participants
) {

3. score 값을 정수부(투표 참여자 수)와 소수부(투표 마감 시각에 따른 정렬 값)로 분리하여 처리

세 번째 방법은 score 값을 정수부와 소수부로 분리하여 처리하는 것이다. 이 방법은 기존 score에 소수점을 추가하는 방법입니다. 이때 소수점은 투표 마감 시각에 따른 정렬 값인데, 이 값은 2번 방법과 동일하게 계산한다.

이렇게 하면 정수부가 같을 경우 (즉, 투표 참여자 수가 같을 경우) 소수부 (즉, 투표 마감 시각에 따른 정렬 값)에 따라 순위가 결정되므로 원하는 방향으로 동점자를 처리할 수 있을 것이다.


참고 자료

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions