-
Notifications
You must be signed in to change notification settings - Fork 0
Description
📍 상황
Redis의 Sorted Set을 사용하여 투표에 대한 랭킹 시스템을 구현했다. Sorted Set은 score가 높은 순으로 정렬되는 특징을 가지고 있고, 현재 랭킹에서는 진행 중인 투표 참여자 수를 score로 하고 있다.
score가 같을 때 동점자 처리를 해줘야 하는 상황에 부딪혔고, 효율적인 동점자 처리 방법에 대해 고민하게 되었다.
동점자 처리에 대한 요구사항
- score가 동점일 때는 투표 마감 시각이 더 임박한 쪽(투표 마감 시각이 더 빠른 쪽)이 더 높은 랭킹을 가지도록 해야 한다.
📍 생각한 구현 방법
동점자 처리를 위해 세 가지 방법을 생각해 봤다.
- Application 단에서 처리
- value에 시간에 따른 정렬 값을 추가하여 처리
- 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번 방법과 동일하게 계산한다.
이렇게 하면 정수부가 같을 경우 (즉, 투표 참여자 수가 같을 경우) 소수부 (즉, 투표 마감 시각에 따른 정렬 값)에 따라 순위가 결정되므로 원하는 방향으로 동점자를 처리할 수 있을 것이다.