Redis의 sorted set을 이용해서 랭킹 기능을 구현한 내용을 정리하고자 한다 💻
속도 차이 !!!
랭킹 기능은 DB에 저장된 데이터를 count 하여 구현할 수도 있다. 하지만 그렇게 하면 데이터 양이 증가할수록 count를 계산하고 결과를 가져오는 시간이 오래 걸리기 때문에 성능면에서 좋지 않다고 판단하였다.
그래서 속도 개선을 위해 in-memory DB인 Redis를 사용하였다.
in-memory DB는 Redis와 Memcached 두 가지를 많이 사용한다고 한다.
Memcached
대신 Redis
를 선택한 이유는 Redis가 더 다양한 자료구조를 지원하기 때문이다.
Memcached
는 String 타입 하나만을 지원하는데에 비해 Redis
는 String과 지금 사용하려는 sorted-set
이외에도 다양한 자료구조를 지원하고 있기 때문에 개발에 용이하다고 판단하였다.
즉, 랭킹 기능을 구현하는데 있어 Redis
에서 제공하는 sorted-set
을 사용하면 빠르고 용이하게 개발을 할 수 있을 것이라고 생각하여 Redis
를 사용하게 되었다.
$ docker run --name redis_prac -p 6379:6379 -d redis:alpine
docker image를 사용하여 redis를 사용할 수 있다. 도커 짱
$ redis-cli
$ ZADD <key> <score> <member>
$ ZSCORE <key> <member>
1순위부터 보고 싶다면 0을 사용해야 한다!
$ ZRANGE <key> <시작> <끝>
$ ZRANGE <key> <시작> <끝> REV
$ ZRANK <key> <member>
$ ZREVRANK <key> <member>
redis:
image: redis:7.0
container_name: redis
env_file: ./.env
restart: always
ports:
- $REDIS_LOCAL_PORT:$REDIS_DOCKER_PORT
command: redis-server --requirepass ${REDIS_PASSWORD}
NestJS와 Mysql을 이미 docker-compose로 묶어서 사용하고 있어 redis도 docker image를 사용하였다.
각각 변수들은 .env
로 관리해 주었다.
$ npm install @liaoliaots/nestjs-redis ioredis
...
import { RedisModule } from '@liaoliaots/nestjs-redis';
@Module({
imports: [
RedisModule.forRoot({
config: {
host: 'localhost',
port: 6379,
password: process.env.REDIS_PASSWORD,
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
라이브러리에서 제공하는 RedisModule
을 사용하여 app.module.ts
에 redis 연결을 위한 설정을 해준다.
import { Injectable } from '@nestjs/common';
import { InjectRedis } from '@liaoliaots/nestjs-redis';
import Redis from 'ioredis';
@Injectable()
export class AppService {
constructor(@InjectRedis() private readonly redis: Redis) {}
async setRank(user_number: number) {
const user_score = await this.redis.zscore('rank', `user:${user_number}`);
await this.redis.zadd('rank', +user_score + 1, `user:${user_number}`);
}
async getRank() {
const result = await this.redis.zrevrange('rank', 0, 6);
return result;
}
}
호출할 때마다 해당 user의 score 값을 1씩 증가시키는 setRank
함수와 순위를 가져오는 getRank
함수를 만들어주었다. 라이브러리에서 대부분의 함수를 redis-cli에서 사용하는 명령어 이름으로 작성해두었기 때문에 원하는 기능의 함수를 찾기 편했다!
docker image를 실행시킬 때 redis에 비밀번호 설정을 해주었기 때문에 auht <password>
명령을 통해 접근해야 redis-cli 사용이 가능하다.
실시간 랭킹 기능을 구현하기 위해 redis의 sorted-set을 사용해 보았는데 사실 redis는 cache
용도로 가장 많이 사용된다. 그래서 나도 조만간 redis를 사용해 다양한 캐싱 전략을 직접 구현해 보고 글로 정리하고자 한다 🔥
참고
https://redis.io/docs/data-types/sorted-sets/
https://hub.docker.com/_/redis
https://github.com/liaoliaots/nestjs-redis
https://luran.me/359