개발일지

개발일지 65일차

index.ys 2023. 6. 3. 03:07

1. Redis로 데이터 캐싱을 구현했는데 mysql에 저장된 데이터와 Redis에 저장된 데이터의 싱크가 맞지않아 캐싱이 제대로 작동하지 않음

현재 캐시체크 미들웨어 위치

  • poo.routes.js에서 푸박스 등록,조회에만 캐싱구현 look-aside
//푸박스 조회 캐싱 미들웨어 추가
router.get("/", casheCheck, pooController.getPoo);

//푸박스 상세조회
router.get("/:pooId", casheCheck, pooController.getPooDetail);

캐시 체크 미들웨어

  1. 요청된 url 주소에 해당하는 데이터가 Redis에 있는지확인
// 캐시 체크를 위한 미들웨어
const redisClient = require("../modules/redisClient")
checkCache = async (req, res, next) => {
    try {
        const cacheData = await redisClient.get(req.originalUrl)
        // Redis에 저장된게 존재한다.
        if (cacheData) {
            console.log("Cashe Hit")
            return res.send(JSON.parse(cacheData));
        } else {
            // Redis에 저장된게 없기 때문에 다음 로직 실행
            console.log('Cashe Miss')
            next();
        }
    } catch (error) {
        error.failedApi = "캐쉬 미들웨어 에러";
        throw error;
    }

}

module.exports = checkCache

캐싱 로직

  1. 처음 서버에 요청된 데이터는 cashe miss 콘솔을 찍고 mysql에 접근하여 데이터를 반환함
  2. 한번이상 요청된 데이터는 cashe hit 콘솔을 찍고 mysql에서 데이터를 가져온후 redis에 저장함
getPoo = async (originalUrl) => {
        try {
            const getPooData = await this.poosRepository.findAllPoo()
            const getPooDataAll = await Promise.all(
                getPooData.map((poo) => {
                    return {
                        pooId: poo.pooId,
                        UserId: poo.UserId,
                        pooLatitude: poo.pooLatitude,
                        pooLongitude: poo.pooLongitude,
                        address: poo.address,
                        createdAt: poo.createdAt,
                        updatedAt: poo.updatedAt,
                    };
                })
            )
            await redisClient.SETEX(originalUrl, DEFAULT_EXPIRATION, JSON.stringify(getPooDataAll))
            return getPooDataAll;

        } catch (error) {
            error.failedApi = "푸박스 조회에러";
            throw error;
        }

현재상황

  • 모든 푸박스의 조회 요청시 새로 추가된 데이터를 반환하지 못하고 기존에 redis에 저장된 데이터만 반환함
  • 현재 mysql에는 pooId가 18번째 까지 있지만 Redis에 저장된 pooId는 12번임

생각하고있는 해결방안

  • mysql에 데이터가 업데이트 되었을때 업데이트된 데이터를 다시 요청했을때 redis에 갱신하여 저장하는 방법
  • redis에 get메서드로 데이터를 요청했을때 현재 redis의 데이터 수와 mysql에 데이터가 수가 맞지 않을때 redis에 저장해주는 방법
  • 주기를 설정하여 mysql에 저장된 데이터를 redis로 주기적으로 전달하는방법
  • 304응답을 반환함 ⇒ 서버에서 같은요청을 받았을때 데이터가 리렌더링 되지 않고 일정 딜레이를 두고 데이터를 반환함 데이터를 바로 갱신 하는 방법??

2. Redis로 세션 구현시 로컬에서는 제대로 세션이 Redis에 저장되지만 서버 배포후 로그인시 Redis에 세션이 저장되지 않음

세션 옵션 설정 모듈

  • 세션저장소를 redis로 설정
const RedisStore = require("connect-redis").default
const redisClient = require('../modules/redisClient');
const session = require('express-session');

module.exports = session({
    store: new RedisStore({ client: redisClient }),
    secret: process.env.COOKIE_SECRET,
    saveUninitialized: true,
    resave: false,
    name: 'connect.sid',
    cookie: {
        secure: false, // if true: only transmit cookie over https, in prod, always activate this
        httpOnly: true, // if true: prevents client side JS from reading the cookie
        maxAge: 1000 * 60 * 30, // session max age in milliseconds
        sameSite: 'lax',
    },
});

// req.session.name = '세션ID' //세션등록
// req.sessionID //세션 아이디 확인
// req.session.destroy() //세션 모두제거
// req.session.data = "비밀번호"

세션을 체크하는 미들웨어

  • app.js 에서 전역을 설정하여 모든 요청에 대해 사용자가 로그인했는지 검증
const redisClient = require('../modules/redisClient')
//세션체크를 위한 미들웨어
checkSession = async (req, res, next) => {
    try {
        const getSession = await redisClient.get(`sess:${req.sessionID}`)
        if (getSession) {
            console.log("이미 로그인한 사용자입니다.")
            next()
        } else {
            console.log("로그인하지 않은 사용자 입니다.")
            next()
        }
    } catch (error) {
        next(error);
    }

}
    ;
module.exports = checkSession

로그인 요청시 사용자의 데이터를 session에 저장하는 코드

  • loginUser에 담긴 사용자의 데이터를 객체형태로 세션에 저장함
const sessionData = {
        userId: loginUser.userId,
        phoneNumber: loginUser.phoneNumber,
        nickname: loginUser.nickname,
        isLogined: true
      };

      req.session.sessionData = sessionData
      await req.session.save()
      return res.status(200).json({ accessToken, refreshToken });

로컬서버 실행 후 로그인 요청시 저장된 세션

  • userId, phoneNumber, nickname, isLogined 등의 사용자 정보를 담고 있고, 정상적으로 Redis에 저장함

배포서버에 요청시 세션에 사용자 정보가 저장되지않

  • 의심가는 부분 1 : api요청을 thunderClient로 실행하는데 thunderClient에서 ************api요청시 남아있는 cookie, token 때문에 이미 로그인한 사용자라고 인식함?
  • 의심가는 부분 2 : 배포된 서버와 현재 내 로컬과의 싱크기 맞지않아서 발생하는 문제??

3. redis legacyMode 옵션을 true로 설정시 get 메소드가 실행되지 않는 오류(set은 실행됨)

const redisClient = redis.createClient({
    url: `redis://${process.env.REDIS_USERNAME}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}/0`,
    // legacyMode 옵션은 Redis v2 호환성 모드를 사용합니다.
    // 따라서, Redis v4 사용시에는 필요 없습니다.
    //legacyMode: true,
});

해결방법

  • 이전 Redis 버전이 v3으로 설정되어 호환모드 설정시 get메소드가 실행되지 않음 ⇒ 자세한 이유를 아직 모름
  • redis의 버전을 5로 높여서 재설치 한후 legacymode는 설정하지 않음
  • 현재 redis 버전 5

질문

  • 카카오 api 데이터를 연습으로 요청했을때 응답속도와 현재 DB에 저장된 데이터를 요청했을때 응답속도가 다름

캐싱전 카카오 데이터 응답속도

캐싱후 카카오 데이터 응답속도

캐싱후 현재 데이터 응답속도

  • 상황 : 카카오 데이터는 캐싱후 응답속도가 6ms 빠른 속도로 응답됐지만 현재 db에 저장된 푸박스데이터는 854ms로 굉장히 느리게 응답함
  • app.use(session) app.use(checkSession)
  • 의심가는 부분 1 : 캐싱 미들웨어를 지나기 전에 전역으로 설정한 세션 미들웨어가 존재해서 서버 전체의 응답속도가 느려짐 ⇒ 해결방법??
  • 의심가는 부분 2 : 미들웨어의 위치에따라 응답속도가 변할 수 있는지? 만약그렇다면 캐시체크 미들웨어와 , 세션체크 미들웨어의 위치를 어디다가 두어야하는지?