✅오늘 학습 Keyword
2023.06.15 - [실전프로젝트] - 230616 실전프로젝트15 [Nest.js] Jmeter로 부하테스트하기
JMeter 사용법을 숙지한 후에 기능별로 기준을 나누어 테스트를 진행했다.
✅JMeter로 애플리케이션 성능테스트 해보기
테스트 기준과 결과는 아래와 같다.
✅오늘 알게된 점
caching intercepter를 적용한 검색 부분은 정말 경이로울 정도로 속도가 개선되는 것을 알 수 있었다.
그러나 팀원들의 의견은 좌표를 이용한 위치기반 식당 조회 부분에서는 요청 좌표의 아주 사소한 부분만 바뀌어도 결과를 전부 캐싱해야하는 점이 비효율 적이고 메모리 관리가 어렵다고 판단되어 캐싱이 아닌 indexing 을 사용한 elastic search를 사용하기로 했다.
내 생각엔 TTL을 약 하루정도로 설정하여 caching을 사용하는 것도 충분히 효율적이고 속도 또한 보장을 할 수 있을 것 같고, ㄴ특정 유저는 대체로 하루동안은 비슷한 지역에서 식당을 조회할것이기에 빠르게 결과를 조회할 수 있을 것이다. 만약 caching이 indexing보다 월등하게 빨랐다면 caching을 사용하는 쪽으로 진행 했겠지만 그건 아니니까~ 또 식당에는 실시간으로 변하는 waiting list가 존재하기에 TTL을 오래 설정하기엔 무리가 있을지도 ..
**Nestjs 캐시 무효화
TTL을 길게 설정하여 캐시가 더 오래 남아 활용되도록 구성하면, 반복적인 비즈니스 로직의 실행을 더 많이 줄여 자원을 아낄 수 있고 더 빠른 접근을 가능케 할 수 있습니다. 그러나 모든 캐시의 만료기간을 길게 설정하는 문제를 초래할 수 있습니다. 오랜 기간 변경되지 않아도 되는 데이터가 있는 반면, 짧은 변경 주기를 가지는 데이터도 있습니다. ‘캐시를 얼마나 오래 유지해야 하는가?‘의 문제는 언제나 답이 없습니다. 데이터의 성격과 상황에 따라 알맞게 설정해야 할 것입니다.
만료기간이 긴 경우 캐시 데이터가 오래된 데이터일 가능성이 높아지며, 만료기간이 짧은 경우 캐시 효율성이 낮아집니다. 물론 캐시처리 하지 않는 것보다는 짧은 유효기간의 캐시라도 두는 것이 성능 향상에 있어 도움이 될 것은 분명합니다.
**caching intercepter
Nest.js에서 Interceptor란?
https://docs.nestjs.com/interceptors#interceptors
//프로젝트 내에서 interceptor 설정
import {
CACHE_KEY_METADATA,
CACHE_MANAGER,
CACHE_TTL_METADATA,
} from '@nestjs/cache-manager';
import {
Injectable,
ExecutionContext,
Optional,
Inject,
CallHandler,
HttpServer,
NestInterceptor,
} from '@nestjs/common';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
const HTTP_ADAPTER_HOST = 'HttpAdapterHost';
const REFLECTOR = 'Reflector';
export interface HttpAdapterHost<T extends HttpServer = any> {
httpAdapter: T;
}
@Injectable()
export class CacheInterceptor implements NestInterceptor {
@Optional()
@Inject(HTTP_ADAPTER_HOST)
protected readonly httpAdapterHost: HttpAdapterHost;
protected allowedMethods = ['GET'];
constructor(
@Inject(CACHE_MANAGER) protected readonly cacheManager: any,
@Inject(REFLECTOR) protected readonly reflector: any,
) {}
async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<any>> {
const key = this.trackBy(context);
const ttlValueOrFactory =
this.reflector.get(CACHE_TTL_METADATA, context.getHandler()) ?? null;
if (!key) {
return next.handle();
}
console.log('key:', key);
try {
const value = await this.cacheManager.get(key);
console.log('value:', value);
if (value !== undefined && value !== null) {
return of(value);
}
// const ttl =
// typeof ttlValueOrFactory === 'function'
// ? await ttlValueOrFactory(context)
// : ttlValueOrFactory;
const ttl = 5;
console.log('ttl:', ttl);
return next.handle().pipe(
tap((response) => {
console.log('response:', response);
const args =
ttl === undefined ? [key, response] : [key, response, ttl];
this.cacheManager.set(...args);
}),
);
} catch {
return next.handle();
}
}
protected trackBy(context: ExecutionContext): string | undefined {
const httpAdapter = this.httpAdapterHost.httpAdapter;
const isHttpApp = httpAdapter && !!httpAdapter.getRequestMethod;
const cacheMetadata = this.reflector.get(
CACHE_KEY_METADATA,
context.getHandler(),
);
if (!isHttpApp || cacheMetadata) {
return cacheMetadata;
}
const request = context.getArgByIndex(0);
if (!this.isRequestCacheable(context)) {
return undefined;
}
return httpAdapter.getRequestUrl(request);
}
protected isRequestCacheable(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest();
return this.allowedMethods.includes(req.method);
}
}
'개발 > 프로젝트-식당 웨이팅 앱 FOOD LINE' 카테고리의 다른 글
230622 실전프로젝트20 [Nest.js] Jest로 Unit test code 짜기2 (0) | 2023.06.23 |
---|---|
230621 실전프로젝트19 [Nest.js] Jest로 Unit test code 짜기 (0) | 2023.06.21 |
230619 실전프로젝트17 [Nest.js] Load balancer (0) | 2023.06.19 |
230616 실전프로젝트16 [Nest.js] Jmeter로 부하테스트하기 (0) | 2023.06.15 |
230615 실전프로젝트15 [Nest.js] 데이터베이스 migration, TypeORM (0) | 2023.06.15 |