관리 메뉴

Mini

[Redis] Redis를 이용한 우아한 조회수 증가 본문

CS/DB

[Redis] Redis를 이용한 우아한 조회수 증가

Mini_96 2024. 10. 20. 20:08

* 조회수 증가 구현

  • 의문 : 조회수가 +1 될때마다 db에 update 를 하는게 좋은가?
    • 사용자가 100명일때 한게시물을 조회하는 경우 -> 100개의 db update 쿼리 
    • critical 한 정보가 아니기때문에 얻는 이득대비 db 비용이 크다고 생각한다.
  • 개선 : 레디스캐시에 조회수를두고 여기에 업데이트한다.
    • 5분마다 db에 업데이트 쿼리를 날린다.
    • 5분에 1번만 db에 update 쿼리를 날린다.

 
  • 우분투에 redis설치

* 리눅스서버의 redis 연결

  • config
  • 참고로 host에 192로 시작하는 내부ip를 입력해야 작동한다. 
  • dotenv.config해야 제대로 .env 파일의 내용을 불러온다.
import { createClient } from 'redis';
import * as dotenv from 'dotenv';

dotenv.config(); // env환경변수 파일 가져오기

export const RedisClient = createClient({
    url: `redis://${process.env.DB_HOST}:${process.env.PORT_REDIS}`,
    socket: {
        reconnectStrategy: (retries) => {
            if (retries > 10) {
                console.error('Redis 연결 최대 재시도 횟수 초과');
                return new Error('Redis 연결 실패');
            }
            return Math.min(retries * 100, 3000);
        },
    },
});

RedisClient.on('error', (err) => console.error('Redis 클라이언트 에러:', err));
RedisClient.on('connect', () => console.log('Redis에 연결되었습니다.'));
RedisClient.on('reconnecting', () => console.log('Redis에 재연결 중...'));

(async () => {
    await RedisClient.connect();
})();
  • 사용
export class HomeControllerV6 implements ControllerV6{

    private sessionMgr : SessionManager = SessionManager.getInstance();
    private postRepository  = PostRepository.getInstance().getRepo();
    private redisClient = RedisClient

    async process(req: Request, res: Response, paramMap: Map<string, string>, model: Map<string, object>) {
        const findCookieVal = this.sessionMgr.findCookie(req, this.sessionMgr.SESSION_COOKIE_NAME);
        const findMember = this.sessionMgr.findMemberByCookieVal(findCookieVal);

        // await this.redisClient.connect();

        let posts;
        const cachedPosts = await this.redisClient.get('posts');
        const temp = await this.redisClient.get('a');
        console.log(temp);
        if (cachedPosts) {
            posts = JSON.parse(cachedPosts);
        } 
  • 우분투 설치방법
    • sudo apt install redis-server
    • etc/redis redis conf 수정
    • 모든 ip 허용
    • 비밀번호없이도 접근가능
    • 어차피 방화벽에서 1차로 인증했다고 간주. (미들웨어랑 유사하다)

  • 게시글 조회시 조회수 증가로직 개선을 해보자.

redis에는 8

db에는 0

// 주기적으로 동기화 작업 실행 (예: 5초마다)
setInterval(() => {
    console.log('Syncing view counts to database...');
    viewCountManager.syncViewCountsToDatabase()
        .catch(console.error);
}, 5000);

레디스의 post:id:views를 완탐하면서 값이 있는경우, 업데이트 쿼리가 5초마다 나간다. 업데이트후 key값 삭제

  • db의 조회수에 redis의 조회수를 더하는 방식이다. => redis값이 초기화 되더라도 상관없음!

결과

  • 매번 사용자가 조회할때마다 db에 update 쿼리를 날리는 대신, 배치를 통해 조회수를 누적하고 5분마다 1회만 update 쿼리를 보내도록 개선!!