기주

[redis] 캐싱으로 조회수기능 개선하기 본문

DBMS/Redis

[redis] 캐싱으로 조회수기능 개선하기

기주그지마 2024. 11. 27. 14:57

캐싱으로 조회수기능 개선하기

 

기존 조회수기능 방식)

DB update 조회수+1 

async increaseViewCount(reviewIdx: number): Promise<void> {
    await this.prismaService.reviewTb.update({
      where: {
        idx: reviewIdx,
      },
      data: {
        viewCount: {
          increment: 1,
        },
      },
    });
}

 

 

 

기존 조회수 기능의 문제점)

  1. 트래픽이 많아질수록 인덱싱된 데이터의 수정작업이 계속 이루어지게되면서 DB작업에 부담이 늘어난다.
  2. DB작업은 컴퓨터작업의 가장 느린부분으로 작업량이 늘어날때 병목현상이 일어나서 시스템 전체의 성능이 떨어질 수 있다.
  3. 그래서 불필요하게 DB에서 입출력작업이 많이 발생하지 않도록 해야한다.

 

 

캐싱기법 도입시의 장점)

  1. 캐싱기법은 조회수 증가작업을 일시적으로 메모리에 모아놨다가 한번에 할 수 있도록 해준다. 따라서 기존에 수시로 DB데이터 수정작업이 이루어지던 것을 한번의 메모리의 입출력작업으로 대체한다. 이처럼 주기적으로 캐시에서 DB로 데이터를 동기화해줌으로써 DB부하를 줄인다.
  2. 캐싱은 메모리 데이터를 저장함으로써 디스크의 I/O보다 훨씬 빠르게 동작한다.

 

하지만 캐싱을 통해 주기적으로 조회수를 업데이트하는 것만 반영한다면 실시간으로 조회수를 보여줄 수 없게된다.

이를 해결하기위해 조회수를 증가시키는 작업뿐만아니라 조회수를 표시할 때도 캐시를 이용해야한다.

 

 

캐싱기법 도입시의 단점과 보완)

  1. 캐시와 DB의 데이터 일관성을 유지하기 위해 동기화 전략이 필요하다

-> 캐시된 데이터를 주기적으로 DB에 반영했다.

 

 

 

캐싱을 통한 실시간 조회수 반영)

  • 조회수 증가 시 : 조회수 증가를 캐시에 저장.
  • 조회수 표시 시 : 조회수를 표시할 때도 캐시에서 가져와 실시간으로 보여준다.

 

 

캐싱이 적용된 조회수 기능 코드)

 

조회수 증가 메서드

//조회수 증가 메서드
async increaseViewCount(reviewIdx: number): Promise<void> {
    await this.redis.incr(`review:${reviewIdx}:viewCount`);
  }

 

조회수 불러오기 메서드

1.캐싱된 조회수 찾기

2.캐싱된 조회수가 없다면 DB에서 찾기


// 조회수 불러오기 메서드
async getViewCount(reviewIdx: number): Promise<number> {
    //메모리에서 조회수를 불러오기
    let viewCount = parseInt(
      await this.redis.get(`review:${reviewIdx}:viewCount`),
      10,
    );

    //없다면 DB에서 조회수를 불러오기
    if (!viewCount) {
      const review = await this.getReviewByIdx(reviewIdx);
      viewCount = review.viewCount;

      await this.redis.set(`review:${reviewIdx}:viewCount`, viewCount);
    }

   return viewCount;
}

 

주기적으로 캐싱된 데이터 DB 동기화

1. 생성자내부에서 실행하여 객체 생성 즉시 주기적으로 동기화 진행

2.동기화한뒤 캐싱된 데이터 삭제

//주기적으로 캐싱된 조회수 DB에 동기화 
//생성자 내부에서 실행하여 객체생성 즉시 주기적으로 동기화
setInterval(
  async () => {
    const keys = await this.redis.keys(`review:*:viewCount`);
    for (const key of keys) {
      const reviewIdx = key.split(':')[1];
      const viewCount = await this.redis.get(key);
      await this.prismaService.reviewTb.update({
        where: {
          idx: parseInt(reviewIdx, 10),
        },
        data: {
          viewCount: parseInt(viewCount, 10),
        },
      });
    }
  },
  10 * 60 * 1000,
);

 

 

 

 

'DBMS > Redis' 카테고리의 다른 글

db) Redis  (0) 2024.01.14