forked from earthkingman/42Swim
-
Notifications
You must be signed in to change notification settings - Fork 1
Redis 로 랭킹시스템 구현
박찬얼 edited this page Sep 13, 2023
·
10 revisions
- 모든 유저의 점수를 저장하여 점수로 정렬하여 1~10위 유저의 데이터를 응답해줘야한다.
- 유저가 글을 작성하거나, 유저의 글이 좋아요를 받거나, 유저의 글이 채택 당할때 점수를 증가 시켜줘야한다.
- 이때 유저의 닉네임, 순위, 프로필 사진을 응답해줘야 한다.
- 유저가 글을 쓰거나 좋아요를 누르거나 채택 할때 점수를 업데이트 해야하기 때문에 데이터베이스에 접근이 빈번 해진다.
- 메인 페이지에 접속할 때 마다 모든 유저를 점수로 정렬하여 1~10위 유저 정보를 출력해줘야 하기 때문에 메인 페이지 또한 무거워 질 수 있다고 생각한다.
SELECT * FROM `user` ORDER BY `score` DESC
SELECT * FROM `user` ORDER BY `score` DESC LIMIT 101, 100
SELECT `m`.* FROM `user` `m`
INNER JOIN (
SELECT id FROM `user`
ORDER BY `score` DESC LIMIT 101, 100
) `lu` ON (`m`.`id` = `lu`.`id`)
SELECT COUNT(*) + 1 FROM `user` WHERE `score` > (
SELECT `score` FROM `user`
WHERE `name` = `닉네임`
)
async updateRank(userId: number, score: number) {
redisClient.zincrby('total_rank', score, String(userId), (err, result) => {
if (err) console.log(err);
})
redisClient.zincrby('month_rank', score, String(userId), (err, result) => {
if (err) console.log(err);
})
}
async getTotalRanker(range: number) {
const getAsync = util.promisify(redisClient.zrevrange).bind(redisClient);
const temp = await getAsync('total_rank', 0, range - 1, 'withscores');
return temp;
}
async getMonthRanker(range: number) {
const getAsync = util.promisify(redisClient.zrevrange).bind(redisClient);
const temp = await getAsync('month_rank', 0, range - 1, 'withscores');
return temp;
}
async getTotalRankerInfo(range: number) {
const totalRanker = await this.getTotalRanker(range);
const totalRankerInfo = [];
for (let i = 0; i < range; i++) {
const id = Number(totalRanker[i * 2]);
const photo = await this.getUserProfile(id);
const nickname = await this.getUserName(id);
const ranker = {
id: id,
score: totalRanker[i * 2 + 1],
photo: photo,
nickname: nickname
};
totalRankerInfo.push(ranker);
}
return totalRankerInfo;
}
- 유저 닉네임
- 유저 프로필 사진
- 유저 월간 점수
- 유저 총 점수
- Sorted set을 사용하여 month_rank 라는 set에 유저 아이디를 key로 유저 월간 점수를 value로 사용하여 저장
- Sorted set을 사용하여 total_rank 라는 set에 유저 아이디를 key로 유저 월간 점수를 value로 사용하여 저장
- Redis set에 userId_nickname 를 key로 닉네임을 value로 사용하여 저장
- Redis set에 userId_profile 를 key로 유저 프로필 사진 url 을 value로 사용하여 저장
