#8 Nestjs, Graphql과 Redis로 캐싱하기

2023년 08월 23일

필자는 현재는 어플리케이션에 캐싱을 적용할 필요가 없지만 Nestjs와 Graphql에서 캐싱을 어떻게 적용하는지에 대해 알고 싶었습니다. 그래서 이 글에서는 캐싱에 대해 알아보겠습니다.

Nestjs에서는 cache-manager 라이브러리를 이용하면 캐싱을 쉽게 구현할 수 있습니다. 이제 캐싱을 설정하는 법을 알아보겠습니다.

Redis를 활용한 캐싱

우선 디펜던시들을 설치합니다.

pnpm install @nestjs/cache-manager cache-manager

디폴트인 in-memory 캐싱을 사용하는 대신에 필자는 Redis를 사용하기로 했습니다. 이를 위해 필요한 디펜던시들을 추가적으로 설치합니다.

pnpm install cache-manager-redis-store@2
pnpm install --save-dev @types/cache-manager-redis-store

캐싱이 가능하게 만드려면 toilet.moduel.ts 파일에 cache 모듈을 import합니다.

imports: [
  CacheModule.registerAsync({
    imports: [ConfigModule],
    useFactory: (config: ConfigService) => ({
      ttl: config.get('REDIS_DEFAULT_TTL'),
      isGlobal: true,
      store: redisStore,
      host: config.get('REDIS_HOST'),
      port: config.get('REDIS_POST'),
    }),
    inject: [ConfigService],
  }),
  //..
]

Redis 설정을 위해 config 모듈을 불러온 것을 확인하실 수 있습니다. 이는 여러 환경들을 대비하여 설정하기 위함입니다 - .env파일에 Redis 설정을 위한 적절한 값을 넣어주어야 합니다.

Docker로 Redis 시작

docker-compose.yml 파일에 Docker를 이용해 Redis를 로컬 환경에서 설치 및 실행하기 위해 다음의 코드를 입력합니다.

services
  redis:
    container_name: cache
    image: redis
    ports:
      - 6379:6379
    volumes:
      - redis:/data
volumes:
  redis:
    driver: local

docker-compose up -d을 입력하면 Redis가 포트 6379에서 실행이 될 것입니다.

toilet 캐싱

toilet 서비스에서 캐싱이 어떻게 되는지 알아보기 위해 toilet 쿼리를 캐싱해볼 것입니다.

@Injectable()
export class ToiletsService {
  constructor(
    @Inject(CACHE_MANAGER) private cacheService: Cache,
    //..
  ) {}

  public async getToilet(getToiletArgs: GetToiletArgs): Promise<Toilet> {
    const cachedData = await this.cacheService.get<Toilet>(getToiletArgs.id);
    if (cachedData) return cachedData;

    const toilet = await this.repository.getToilet({
      where: { id: getToiletArgs.id },
    });

    await this.cacheService.set(getToiletArgs.id, toilet);
    return toilet;
  }
  //..
}

cache manager를 contructor에 주입하고 getToilet 메소드에 캐싱을 적용할 것입니다. 쿼리를 전달받을 때 해당 toilet이 캐싱이 되었다면 캐싱이 된 값을 반환할 것이고 캐싱이 되지 않았다면 데이터 베이스에서 불러온 값을 반환하고 Redis에 저장하게 될 것입니다.

Redis에 저장된 캐싱 값 확인

캐싱이 된 값이 Redis에 저장이 되었는지 확인해 보기 위해 Redis docker 컨테이너를 접속한 뒤 redis-cli를 이용해 값을 확인할 수 있습니다.

docker exec -it [redis-container-id] redis-cli
// if accessed

127.0.0.1:6379> GET [id of toilet that was cached]
"{\"id\":\"[id of toilet that was cached]\",\"isPaid\":true,\"price\":1000}"
or
(nil)

toilet 쿼리를 전달할 때, 캐싱이 되었다면 해당 화장실 정보를 출력되고 그렇지 않다면 nil을 출력할 것입니다.

정리

글의 서두에서 언급했다시피 아직 이 어플리케이션은 캐싱이 필요하지 않을 수 있습니다. 아직 오랫동안 변화가 없으면서 복잡한 연산이 없고 트래픽이 많지 않기 때문입니다. 하지만 캐싱을 적용하는 법을 미리 익힌다면 캐싱이 필요할 때 빠르게 도움이 될 것이라고 생각합니다.

읽어 주셔서 감사합니다. To be continued!

참조