주니어 개발자 1호

NestJs CacheModule 사용기 본문

Server 관련

NestJs CacheModule 사용기

No_1 2023. 4. 25. 23:05

NestJs로 프로젝트를 진행하며, Redis를 직접 연결해서 쓰고있었는데

CacheModule을 뒤늦게 알게 되어 프로젝트에 적용해보고자, 테스트를 했었습니다.

그런데.. 그런데…….. 메이저 버젼 업그레이드 ( v4 → v5 )에서 큰 변환점이 하나 있었던거 있죠..

그것도 모르고… 그것도 모르고…….. 왜 캐싱이 안되는거지….하면서…..한참을 헤매었어요…

 

TIP: 공식 문서를 ..꼼꼼히 읽자. 나는..빡빡이다..

공식 문서를 ..꼼꼼히 읽자. 나는..빡빡이다..

공식 문서를 ..꼼꼼히 읽자. 나는..빡빡이다..

 

간단하게 주의사항과, 사용 방법에 대해 올려보겠습니다!

 

주의사항

  • cache-module의 버젼에 따른 option 변화
    • v4: cacheModule의 ttl-초 단위
    • v5: cacheModule의 ttl- 밀리세컨드 단위 ( 1000ms = 1초 )
    • 전역적으로 사용할 경우 HTTP Method GET에만 캐싱이 동작합니다.
    • Controller에서 Res를 호출할 경우, 인터셉터를 사용할 수 없습니다.
      • { passthough: true } 시 사용 가능

 

 

사용방법

크게 두가지 사용법이 있습니다.

  • 인 메모리 캐시
    • 프로그램이 사용가능한 만큼 메모리 자원 소모 가능
    • Node가 실행되었을 때 Node 버젼에 따라 기본적으로 메모리 제한이 걸려져 있습니다.
    • 하지만 실행될 컴퓨터의 용량에 따라 option 값을 달리해두는 것이 좋습니다.
    대충 2GB 의 컴퓨터에서 1.5GB를 사용하고, 나머지 0.5는 여분으로 남겨두어야 한다는 것 같습니다.
  • 참고사이트: https://nodejs.org/api/cli.html#cli_node_options_optionsOn a machine with 2 GiB of memory, consider setting this to 1536 (1.5 GiB) to leave some memory for other uses and avoid swapping.
  • $ node --max-old-space-size=1536 index.js
  • Sets the max memory size of V8's old memory section. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory.
  • Redis <Store>
    • Redis를 연결합니다.
    • 장점: 다른 프로세스에서 가동시 자원 공유가 가능합니다.

 

인 메모리 캐시 사용 방법

npm install @nestjs/cache-manager cache-manager
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';

@Module({
  imports: [CacheModule.register({
		// ttl: v4일 때 = second / v5 일 때 milli second 
		ttl: 5, 
		max: 10,
	})],
  controllers: [AppController],
})
export class AppModule {}

 

Redis 사용 방법

import type { RedisClientOptions } from 'redis';
import * as redisStore from 'cache-manager-redis-store';
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';

@Module({
  imports: [
    CacheModule.register<RedisClientOptions>({
      store: redisStore,

      // redis host, port 연결
      host: 'localhost',
      port: 6379,
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

 

 

공통 사항

  • 지역 Caching
    • method 별, Controller 별로 가능합니다.
@Controller()
export class AppController {

	// method 별
  @CacheKey('custom_key')
  @CacheTTL(20)
  findAll(): string[] {
    return [];
  }
}
@Controller()
// controller router를 key로 사용
@UseInterceptors(CacheInterceptor)
export class AppController {
  @Get()
  findAll(): string[] {
    return [];
  }
}

 

  • 전역 Caching
    • AppModule에 Provider 로 공급합니다.
    • HTTP METHOD: GET 에 대한 api end point 에 바인딩 되어 동작합니다.
    import { Module } from '@nestjs/common';
    import { CacheModule, CacheInterceptor } from '@nestjs/cache-manager';
    import { AppController } from './app.controller';
    import { APP_INTERCEPTOR } from '@nestjs/core';
    
    @Module({
      imports: [CacheModule.register({
    		// ttl: v4일 때 = second / v5 일 때 milli second 
    		ttl: 5, 
    		// 최대 캐시 요소
    		max: 10,
    		// 모듈 전역 설정
    		isGlobal: true,
    	})],
      controllers: [AppController],
      providers: [
        {
          provide: APP_INTERCEPTOR,
          useClass: CacheInterceptor,
        },
      ],
    })
    export class AppModule {} 
    
  • 직접 제어
    • 생성자에 주입
    • import library를 참고해주세요
    import { CACHE_MANAGER } from '@nestjs/cache-manager';
    import { Cache } from 'cache-manager';
    
    ...
    constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) 
    

 

 

테스트

  • 인 메모리 캐시로 테스트
  • 컨트롤러에 @UseInterceptors(CacheInterceptor) 설정
  • ttl: 5초
  • max: 2

END POINT

@Get(':id')
  async findOne(@Param('id') id: string) {
    console.log('findOne');
    return this.appService.getHello();
  }

LOGGING ( 시간을 봐주세요 )

  • 5초 동안 Response 값 기억, Controller 아래값을 기억하지 않음.
[Nest] 57385  - 04/25/2023, 10:46:03 PM     LOG [LoggingInterceptor] [1ca4283b-2e76-48c2-bf28-122857832618] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 57385  - 04/25/2023, 10:46:03 PM     LOG [LoggingInterceptor] [1ca4283b-2e76-48c2-bf28-122857832618] GET /test213123 200 undefined: 0ms
[Nest] 57385  - 04/25/2023, 10:46:04 PM     LOG [LoggingInterceptor] [869782a7-171f-4803-bd6b-582f71f4dd84] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57385  - 04/25/2023, 10:46:04 PM     LOG [LoggingInterceptor] [869782a7-171f-4803-bd6b-582f71f4dd84] GET /test213123 200 undefined: 0ms
[Nest] 57385  - 04/25/2023, 10:46:06 PM     LOG [LoggingInterceptor] [23bf17f5-cc18-4d25-b1e3-4fd61c609e1a] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57385  - 04/25/2023, 10:46:06 PM     LOG [LoggingInterceptor] [23bf17f5-cc18-4d25-b1e3-4fd61c609e1a] GET /test213123 200 undefined: 0ms
[Nest] 57385  - 04/25/2023, 10:46:07 PM     LOG [LoggingInterceptor] [2e418036-3ba2-4474-b805-68fb3e324dec] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 57385  - 04/25/2023, 10:46:07 PM     LOG [LoggingInterceptor] [2e418036-3ba2-4474-b805-68fb3e324dec] GET /test213123 200 undefined: 0ms

Response 에 대한 실험

  • Res 사용시, Cache 되지 않음
  • Res { passthough: true } 사용시, Cache 됨

END POINT

// # passthrough: false
@Get(':id')
  async findOne(
    @Param('id') id: string,
    @Res({ passthrough: false }) res: Response,
  ) {
    console.log('findOne');
    //return this.appService.getHello();
    res.send('Hello World!');
  }

// # passthrough: true
@Get(':id')
  async findOne(
    @Param('id') id: string,
    @Res({ passthrough: true }) res: Response,
  ) {
    console.log('findOne');
    return this.appService.getHello();
  }

TEST

passthrough false 시

Error 발생, Response는 잘 됨

findOne
[Nest] 58015  - 04/25/2023, 10:54:09 PM     LOG [LoggingInterceptor] [b9564c56-9106-4816-b383-f8792a1aa44a] GET /test213123 200 2: 1ms
[Nest] 58015  - 04/25/2023, 10:54:09 PM   ERROR [CacheInterceptor] An error has occurred when inserting "key: /test213123", "value: undefined"
[Nest] 58015  - 04/25/2023, 10:54:10 PM     LOG [LoggingInterceptor] [1e958969-68a5-4947-80bb-8aee68c7584d] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 58015  - 04/25/2023, 10:54:10 PM     LOG [LoggingInterceptor] [1e958969-68a5-4947-80bb-8aee68c7584d] GET /test213123 200 2: 0ms
[Nest] 58015  - 04/25/2023, 10:54:10 PM   ERROR [CacheInterceptor] An error has occurred when inserting "key: /test213123", "value: undefined"
[Nest] 58015  - 04/25/2023, 10:54:10 PM     LOG [LoggingInterceptor] [fdb2a7f7-9ecd-4f8e-a32b-af32bbf45e7e] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 58015  - 04/25/2023, 10:54:10 PM     LOG [LoggingInterceptor] [fdb2a7f7-9ecd-4f8e-a32b-af32bbf45e7e] GET /test213123 200 2: 1ms
[Nest] 58015  - 04/25/2023, 10:54:10 PM   ERROR [CacheInterceptor] An error has occurred when inserting "key: /test213123", "value: undefined"
[Nest] 58015  - 04/25/2023, 10:54:14 PM     LOG [LoggingInterceptor] [466b2a82-3eda-48c0-b204-ea7516f98af3] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 58015  - 04/25/2023, 10:54:14 PM     LOG [LoggingInterceptor] [466b2a82-3eda-48c0-b204-ea7516f98af3] GET /test213123 200 2: 1ms
[Nest] 58015  - 04/25/2023, 10:54:14 PM   ERROR [CacheInterceptor] An error has occurred when inserting "key: /test213123", "value: undefined"
[Nest] 58015  - 04/25/2023, 10:54:15 PM     LOG [LoggingInterceptor] [0c64bdd3-8a35-4bb9-b0cd-7e448721254b] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 58015  - 04/25/2023, 10:54:15 PM     LOG [LoggingInterceptor] [0c64bdd3-8a35-4bb9-b0cd-7e448721254b] GET /test213123 200 2: 1ms
[Nest] 58015  - 04/25/2023, 10:54:15 PM   ERROR [CacheInterceptor] An error has occurred when inserting "key: /test213123", "value: undefined"

passthrough true 시

[Nest] 57756  - 04/25/2023, 10:51:32 PM     LOG [LoggingInterceptor] [b012737f-f39d-4e69-807e-86ff51848b47] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 57756  - 04/25/2023, 10:51:32 PM     LOG [LoggingInterceptor] [b012737f-f39d-4e69-807e-86ff51848b47] GET /test213123 200 undefined: 3ms
[Nest] 57756  - 04/25/2023, 10:51:33 PM     LOG [LoggingInterceptor] [86fc69f2-e61b-4f5e-a2bd-fc500ed50bb3] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57756  - 04/25/2023, 10:51:33 PM     LOG [LoggingInterceptor] [86fc69f2-e61b-4f5e-a2bd-fc500ed50bb3] GET /test213123 200 undefined: 0ms
[Nest] 57756  - 04/25/2023, 10:51:33 PM     LOG [LoggingInterceptor] [0a1b3206-ef6d-4537-bda2-72f04003a654] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57756  - 04/25/2023, 10:51:33 PM     LOG [LoggingInterceptor] [0a1b3206-ef6d-4537-bda2-72f04003a654] GET /test213123 200 undefined: 1ms
[Nest] 57756  - 04/25/2023, 10:51:35 PM     LOG [LoggingInterceptor] [aaaabe14-41b0-47eb-ab8c-486762ada0ed] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57756  - 04/25/2023, 10:51:35 PM     LOG [LoggingInterceptor] [aaaabe14-41b0-47eb-ab8c-486762ada0ed] GET /test213123 200 undefined: 0ms
[Nest] 57756  - 04/25/2023, 10:51:35 PM     LOG [LoggingInterceptor] [a2b7b2f7-ed77-4209-8f13-eb26fc607d54] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
[Nest] 57756  - 04/25/2023, 10:51:35 PM     LOG [LoggingInterceptor] [a2b7b2f7-ed77-4209-8f13-eb26fc607d54] GET /test213123 200 undefined: 0ms
[Nest] 57756  - 04/25/2023, 10:51:36 PM     LOG [LoggingInterceptor] [a7e78b86-82ff-43d0-8fc9-9c51364c0e6a] GET /test213123 undefined PostmanRuntime/7.32.2 ::1: AppController findOne
findOne
[Nest] 57756  - 04/25/2023, 10:51:36 PM     LOG [LoggingInterceptor] [a7e78b86-82ff-43d0-8fc9-9c51364c0e6a] GET /test213123 200 undefined: 1ms

 

인용

공식문서: https://docs.nestjs.com/techniques/caching
V8: https://nodejs.org/api/cli.html#cli_node_options_options