본문 바로가기
NestJS

[NestJS] Redis 연동과 Cron으로 업데이트

by 개복취 2024. 2. 1.

 

0. NestJS에서의 Redis 초기세팅

1. 랭킹조회(zset)하기 위한 레디스 명령어 (zadd, zrange)

2. 페이지네이션을 통해 레디스로부터 랭킹 가져오기

3. NestJS Cronjob


NestJS에서의 Redis 초기세팅 (ioredis + liaoliaots/nestjs-redis 사용하는 이유)

  • 기본 redis 는 redis 클라이언트 내부에서 사용하는 instruction(zadd, zrange) 을 사용하는게 불가함
  • 또한, 안정성이 기존의 이미지보다 높다고 이야기 한다. (기존 이미지보다 안정성이 높다는건 의외인데 이부분은 더 알아봐야할것같다)

랭킹조회(zset)하기 위한 레디스 명령어 (zadd, zrange)

  • 실시간 리더보드를 구현하기 위한 레디스의 Sorted Set을 사용한다.
  • 기본적으로 Sorted Set은 중복을 허용하지 않고, score 값을 기준으로 member을 정렬하여 결과값을 가져온다.

zadd?

key: Sorted Set의 이름, score: 멤버의 점수, member: 추가할 멤버의 값 순서로 이루어져 있다. 아래는 초기화하는 예시이다.

  • redis cli : ZADD myzset 1 "one"
  • NestJS: await redis.zadd(key, score, member);

하나 말고도 여러개를 받을 때에는 다음과 같이 적어줄 수 있다.

  • redis cli : ZADD myzset 2 "two" 3 "three"
  • NestJS: await redis.zadd('user_scores', 100, 'user1', 200, 'user2');

(user1의 점수를 100으로, user2의 점수를 200으로 설정)

 

zrange?

zadd해서 정렬된 세트에서 특정 멤버의 원소들을 가지고 온다. 랭킹 pagination을 구현해주어야 했기 때문에 zrange은 필수였다.

  • redis cli : ZRANGE myzset 0 -1 WITHSCORES (WITHSCORES 은 스코어까지 불러오는지 여부를 설정해주는 옵션)

페이지네이션을 통해 레디스로부터 랭킹 가져오기

app.service.ts

import { Injectable } from '@nestjs/common';
import { InjectRedis } from '@liaoliaots/nestjs-redis';
import { Redis } from 'ioredis';
import { Logger } from '@nestjs/common';
@Injectable()
export class AppService {
	constructor(@InjectRedis() private readonly redis: Redis) {}

	// push data to redis using zadd
	async updateRanking(score: number, id: number) {
		Logger.log(`Redis updateRanking: ${score}, ${id}`)
		await this.redis.zadd('rankings', score, id);
	}
}
  • redis 에 랭킹데이터를 넣는 updateRanking 메소드는 score과 id를 인자로 받아온다.
  • redis 내부에서는 score을 기준으로 랭킹이 정렬된다.

ranks.service.ts

const userRanking = await this.redis.zrange(
			'rankings',
			(page - 1) * 10,
			page * 10 - 1,
		);
  • 페이지네이션을 위해 zrange 로 page 파라미터에 따라 몇개를 자르고 올지 결정해 주었다.
  • 가령, 1페이지를 가지고 올 때 redis로 부터 0(1위)부터 9(10위)까지 가져올 수 있도록 구성해주는 것이다.

ranks.service.ts

@Post('/test/signin') {

...

Logger.log(`updateRanking(ladderScore, id): ${user.ladderScore}, ${user.id}`);
		await this.AppService.updateRanking(user.ladderScore, user.id);

		return res.send(userSigninResponseDto);
	}
  • 테스트 유저를 생성해 줄 때마다 위에서 정의해준 app.service.ts 의 updateRanking을 불러다가 초기화 시켜준다.

NestJS Cronjob

  • CronExpression 에서 테스트를 위해 매분마다 handleCron() 들어가도록 Cron annotation으로 설정해주었다.
  • 모든 유저를 updateRanking 할 수 있도록 유저 목록을 순회해서 레디스 내부에 업데이트 시켜주는 과정이다.
  • logger으로 확인한다면 아래와 같이 매 분마다 유저정보가 업데이트가 되는것을 확인해볼 수 있다.

 

정리하자면..

  1. 처음 계정생성할 때 레디스에 초기화 시켜준다. (zadd 로 내부에서 알아서 정렬됨)
  2. 페이지네이션 된 정보를 ladderscore 가 높은순으로 가져와야 하기 때문에 zrevrange 로 10개씩 불러온다.
  3. Cron으로 1분마다 db에서 redis로 정보를 넣어주기 위한 Cronjob을 설정해준다.

https://tech.socarcorp.kr/dev/2023/06/27/handling-authentication-token-traffic-01.html

https://velog.io/@wndbsgkr/Nestjs에서-Redis-사용기

https://redis.io/commands/zadd/