Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 부트캠프
- JWT
- unnest
- 레포지토리
- 알림생성모듈
- 알림생성
- N+1문제
- 환경변수
- 게시글 이미지 업로드
- 메뉴바 한번에
- JSON Web Token
- 스테이지어스
- 3계층구조
- Winston
- element.style
- 이미지가 포함된 게시글
- 메뉴바
- 게시글 이미지
- .env
- JWT 쓰는 방법
- secret코드
- 토큰
- 포트번호
- 쿼리스트링
- N+1
- getComputedStyle
- route 53
- 네비게이션 한번에
- JWT 쓰는이유
- 패스파라미터
Archives
- Today
- Total
기주
[redis] 캐싱으로 조회수기능 개선하기 본문
캐싱으로 조회수기능 개선하기
기존 조회수기능 방식)
DB update 조회수+1
async increaseViewCount(reviewIdx: number): Promise<void> {
await this.prismaService.reviewTb.update({
where: {
idx: reviewIdx,
},
data: {
viewCount: {
increment: 1,
},
},
});
}
기존 조회수 기능의 문제점)
- 트래픽이 많아질수록 인덱싱된 데이터의 수정작업이 계속 이루어지게되면서 DB작업에 부담이 늘어난다.
- DB작업은 컴퓨터작업의 가장 느린부분으로 작업량이 늘어날때 병목현상이 일어나서 시스템 전체의 성능이 떨어질 수 있다.
- 그래서 불필요하게 DB에서 입출력작업이 많이 발생하지 않도록 해야한다.
캐싱기법 도입시의 장점)
- 캐싱기법은 조회수 증가작업을 일시적으로 메모리에 모아놨다가 한번에 할 수 있도록 해준다. 따라서 기존에 수시로 DB데이터 수정작업이 이루어지던 것을 한번의 메모리의 입출력작업으로 대체한다. 이처럼 주기적으로 캐시에서 DB로 데이터를 동기화해줌으로써 DB부하를 줄인다.
- 캐싱은 메모리 데이터를 저장함으로써 디스크의 I/O보다 훨씬 빠르게 동작한다.
하지만 캐싱을 통해 주기적으로 조회수를 업데이트하는 것만 반영한다면 실시간으로 조회수를 보여줄 수 없게된다.
이를 해결하기위해 조회수를 증가시키는 작업뿐만아니라 조회수를 표시할 때도 캐시를 이용해야한다.
캐싱기법 도입시의 단점과 보완)
- 캐시와 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,
);