Nest.js 심화
7. 캐싱 사용하기
자주 변하지 않는 데이터에 동일한 요청이 지속적으로 들어오는 경우에 대해서는 캐싱 기능을 사용할 수 있다면 서버의 성능이 전반적으로 올라가겠죠?
캐싱은 사용할 수 있으면 무조건 사용하는 것이 성능을 끌어올릴 수 있는 비결
Nest.js 에서는 cache-manager 를 사용해서 캐싱 기능을 사용할 수 있다.
cache-manager 설치
npm i cache-manager
npm i -D @types/cache-manager
모듈에 패키지 적용
app.module.ts
import {
CacheModule,
MiddlewareConsumer,
Module,
NestModule,
RequestMethod,
} from "@nestjs/common";
CacheModule.register({
ttl: 60000, // 데이터 캐싱 시간(밀리 초 단위, 1000 = 1초)
max: 100, // 최대 캐싱 개수
isGlobal: true,
서비스에 캐시 매니저 ID 하기
board.service.ts 1차
import {
CACHE_MANAGER,
Inject,
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import _ from 'lodash';
import { Cache } from 'cache-manager';
import { ArticleRepository } from './article.repository';
@Injectable()
export class BoardService {
constructor(
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
private articleRepository: ArticleRepository,
) {}
async getArticles() {
const cachedArticles = await this.cacheManager.get('articles');
if (!_.isNil(cachedArticles)) {
return cachedArticles;
}
const articles = await this.articleRepository.find({
where: { deletedAt: null },
select: ['author', 'title', 'updatedAt'],
});
await this.cacheManager.set('articles', articles);
return articles;
}
이 코드는 다음과 같은 순서로 실행됩니다.
- 캐시를 뒤져본다.
- 캐시 히트가 되었다면 해당 캐시를 리턴한다.
- 캐시 미스가 되었다면 다음과 같이 행동한다.
- 리포지토리를 통해 데이터베이스에 접근해서 결과물을 가져온다.
- 결과물을 캐싱한다.
- 결과물을 리턴한다.
여기서는 “articles”라는 키를 통해 this.cacheManager.get 함수를 통해서 캐시를 뒤져보고 캐싱이 되었다면 캐싱된 결과(cachedArticles)를 리턴하고 그렇지 않으면 리포지토리로 결과 값을 가져온 뒤 this.cacheManager.set 함수를 통해서 캐싱을 한 후 결과물을 리턴
캐싱을 적용해도 크게 문제가 없는 서비스 로직에 한해서는 적극적으로 캐싱을 적용하는 것을 추천
max 속성을 통해 캐싱이 되는 데이터 양도 조절을 할 수 있어 메모리가 오버플로우 날 걱정은 딱히하지 않아도 된다.
지금은 인-메모리 기반으로 캐싱을 했지만 Redis와 같은 인-메모리 데이터베이스를 사용하는 것도 가능하니 항상 적극적으로 고려하면 좋다!
8. Rate limit 적용하기
DDos 공격이나 brute force 공격 등으로 서버가 다운되는 상황이 오게된다
이럴 때 Rate limit 를 사용하여 어느정도 방어가 가능하다.
최소한의 방어책을 구축해 놓는게 좋다.
@nestjs/throttler 를 설치
npm i @nestjs/throttler
모듈에 @nestjs/throttler 추가
app.module.ts
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
ThrottlerModule.forRoot({
ttl: 60,
limit: 10, // ttl 동안 limit 만큼의 요청만 받는다.
}),
BoardModule,
UserModule,
],
controllers: [AppController],
providers: [
AppService,
AuthMiddleware,
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
ThrottlerModule.forRoot 함수를 통해서 Rate limit 옵션을 글로벌하게 적용
limit 이상의 요청을 하게 되면 요청에 응답을 하지 않는다.
또한, imports 뿐 아니라 providers에도 추가적으로 코드를 작성해주어 글로벌하게 Rate limit을 적용
경우에 따라서는 특정 API는 Rate limit 기능 적용을 하고 싶지 않은 경우가 있을때는
@SkipThrottle() 데코레이터를 API 위에 명시 해주면 된다.
또는 @Throttle(limit, ttl) 데코레이터를 추가하여
Rate limit 정책을 다르게 줄수도 있다.
@SkipThrottle() // 데코레이터 추가!
@Get("/articles")
async getArticles() {
return await this.boardService.getArticles();
}
@Throttle(5, 60) // 이렇게 하면 60초에 5번 호출만 가능!
@Get("/articles/:id")
async getArticleById(@Param("id") articleId: number) {
return await this.boardService.getArticleById(articleId);
}
'코딩캠프 > 내일배움캠프' 카테고리의 다른 글
[ TIL ] 03.21(화) 89일차 (0) | 2023.03.21 |
---|---|
[ WIL ] 02.20~24 15주차 (0) | 2023.02.26 |
[ TIL ] 02.23(목) 72일차 (0) | 2023.02.23 |
[ TIL ] 02.22(수) 71일차 (0) | 2023.02.22 |
[ TIL ] 02.21(화) 70일차 (0) | 2023.02.21 |