혼자 고민해보기_ 개발

Redis 캐시(Cache)적용을 통한 조회 성능 개선

nuri-story 2023. 11. 2. 19:03

배경

회사정보와 채용공고 영역을 메인에 조회할때 효율적으로 성능 개선을 하기 위해 Cache를 도입하게 되었습니다.

 

캐시(Cache)란?

일반적으로 캐시(cache)는 메모리(RAM)를 사용하기 때문에 데이터베이스 보다 훨씬 빠르게 데이터를 응답할 수 있어 이용자에게 빠르게 서비스를 제공할 수 있습니다. 미리 결과를 저장하고 나중에 요청이 오면 그 요청에 대해서 DB 또는 API를 참조하지 않고 cache에 접근하여 요청을 처리하게 됩니다. 이러한 cache가 동작 할 수 있는 철학에는 파레토 법칙이 있습니다.

 

 

파레토의 법칙

파레토의 법칙이란 80퍼센트의 결과는 20퍼센트의 원인으로 발생한다는 말입니다.

모든 결과를 캐싱할 필요는 없으며, 서비스를 할때 많이 사용되는 20퍼센트를 캐싱한다면 전체적으로 영향을 주어 효율을 극대화 한다는 것입니다. 하지만 cache는 기본적으로 RAM의 용량은 커봐야 16 ~ 32G 정도라, 데이터를 모두 캐시에 저장해버리면 용량 부족 현상이 일어나 시스템이 다운 될 수 있다고 합니다.

 

Cache hit / Cache miss

캐시 히트(Cache Hit) 캐시 미스(Cache Miss) 컴퓨터 시스템의 캐시 메모리와 관련된 용어입니다.

 

cache hit란
- CPU가 참조하고자 하는 메모리가 캐시에 존재하고 있을 경우를 말합니다. 

- 캐시 스토어(redis)에 데이터가 있을 경우 바로 가져옵니다. (빠름)

 

cache miss란
- CPU가 참조하고자 하는 메모리가 캐시에 존재하지 않을때를 말합니다.
- 캐시 스토어(redis)에 데이터가 없을 경우 어쩔수없이 DB에서 가져옵니다. (느림)

 

 

 

 

캐시(Cache)설정 

저희 프로젝트의 프레임워크는 Nest.js를 사용하고 있으므로 공식 사이트의 가이드에 따라 설치를 진행해 주었습니다.

npm install @nestjs/cache-manager cache-manager

 

 

app.module.ts

@Module({
  imports: [
    CacheModule.register({
      isGlobal: true, // 전역 설정
      store: redisStore,
      host: process.env.CACHE_REDIS_HOST,
      port: process.env.CACHE_REDIS_PORT,
      ttl: 10, // 캐시된 데이터가 유지될 시간
    })

 

 

jobposting.module.ts

@Module({
  imports: [
    CacheModule.register(),
    TypeOrmModule.forFeature([Jobposting, Company]),
  ],
  controllers: [JobpostingController],
  providers: [JobpostingService],
  exports: [JobpostingService, TypeOrmModule],
})
export class JobpostingModule {}

 

 

jobposting.controller.ts

import { Cache } from 'cache-manager';
import { CACHE_MANAGER } from '@nestjs/cache-manager';


// 채용공고 전체 조회
  @Get()
  @ApiOperation({
    summary: '채용공고 전체조회 API',
    description: '채용공고 전체조회',
  })
  @ApiCreatedResponse({ description: '채용공고 전체조회' })
  async findAllJobposting(
    @Query() pageReqDto: PageReqDto,
  ): Promise<Jobposting[]> {
    const { page, size } = pageReqDto;

    const cachedList: Jobposting[] = await this.cacheManager.get(
      `jobpostingList${page}`,
    ); // 캐싱된 리스트가 있는지 조회
    if (cachedList) {
      return cachedList;
    } else {
      const jobposting = await this.jobpostingService.findAllJobposting({
        pageReqDto,
      });
      await this.cacheManager.set(`jobpostingList${page}`, jobposting, 5);
      // 캐싱된 데이터가 없을 경우 페이지별로 캐시를 구분하고 5초 동안 데이터를 캐싱
      return jobposting;
    }
  }

 

 

jobposting.service.ts

  // 채용공고 전체 조회
  async findAllJobposting({ pageReqDto }): Promise<Jobposting[]> {
    const { page, size } = pageReqDto;
    const jobpostings = await this.jobpostingRepository.find({
      order: { createdAt: 'DESC' },
      take: size,
      skip: (page - 1) * size,
    });
    return jobpostings;
  }

 

회사 전체 영역도 동일하게 캐싱처리를 해주었습니다.

 

 

Apache JMeter를 통한  HTTP요청 테스트

Thread Group을 통해 사용자수 1000 시간 단위는 10초로 설정해주었습니다.

ExceptionFilter에서 짧은 시간에 요청을 보내면 아래와 같이 문제가 생겨서 10초로 제한했습니다.

======================
예외가 발생했습니다.
예외내용 ThrottlerException: Too Many Requests
예외코드 429
======================

 

 

Redis 사용 전
Redis 사용 후

 

Average 평균 응답시간 17ms Redis 사용 시 Average 평균 응답시간 3ms로 약 80% 평균 응답시간을 개선했다고 볼 수 있습니다.

 

마치며

비교적 단순한 방법으로 효율을 극대화할 수 있어 사용할 일이 많을 것 같습니다. 메인 콘텐츠를 조회하는 것 외에도 채팅과 같은 곳에도 활용되면 사이트의 부하를 줄일 수 있을 것으로 보입니다.

 

참고

https://stackoverflow.com/questions/22610316/how-do-i-install-jmeter-on-a-mac?source=post_page-----e21a65f94617--------------------------------

 

How do I install jmeter on a Mac?

We want to use JMeter. I've downloaded the production version as directed in the user manual at http://jmeter.apache.org/usermanual/get-started.html But how do I get started and install the softw...

stackoverflow.com

 

https://inpa.tistory.com/entry/REDIS-%F0%9F%93%9A-%EC%BA%90%EC%8B%9CCache-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5-%EC%A7%80%EC%B9%A8-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

[REDIS] 📚 캐시(Cache) 설계 전략 지침 💯 총정리

Redis - 캐시(Cache) 전략 캐싱 전략은 웹 서비스 환경에서 시스템 성능 향상을 기대할 수 있는 중요한 기술이다. 일반적으로 캐시(cache)는 메모리(RAM)를 사용하기 때문에 데이터베이스 보다 훨씬 빠

inpa.tistory.com

 

https://creampuffy.tistory.com/209

 

Apache JMeter를 이용한 부하 테스트 및 리포트 생성

서버의 성능을 최적화하기 위해선 어떤 작업이 필요할까요? 어떤 지표를 기준으로 성능을 측정할 것인지, 정의된 지표에 영향을 미치는 변수에는 무엇이 있는지, 해당 변수들의 변화가 성능에

creampuffy.tistory.com

 

https://docs.nestjs.com/techniques/caching

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

https://aws.amazon.com/ko/elasticache/what-is-redis/

 

Redis란 무엇입니까? – Amazon Web Services(AWS)

Redis 개발자는 백 개가 넘는 오픈 소스 클라이언트를 사용할 수 있으며, Java, Python, PHP, C, C++, C#, JavaScript, Node.js, Ruby, R, Go를 비롯한 다수의 언어가 지원됩니다.

aws.amazon.com

 

'혼자 고민해보기_ 개발' 카테고리의 다른 글

Test Code -Nest.js  (0) 2023.11.07
cypress로 e2e테스트 이해하기  (0) 2023.11.07
[항해커톤] 후기 제출  (0) 2023.10.07
.env 정리  (0) 2023.09.30
생활코딩 Docker 입문수업  (0) 2023.09.28