엘리스 AI트랙 4기/프로젝트

Redis 윈도우 설치 / nodejs 코드에 적용하는 법 / redis-cli 명령어 / 캐시 서버 사용전후 응답속도 차이

남쪽마을밤송이 2022. 5. 10. 21:57

 [01 Redis란? ] 

  • NoSQL의 종류 중 하나로 메모리 기반 Key-Value Storage 형 구조의 데이터 관리 시스템이다.
  • 시스템 메모리를 사용하는 특징이 있으며, 문서형 NoSQL인 MongoDB 보다 빠르고 가볍게 동작하며 I/O가 수시로 발생하는 (캐시, 인증 토큰, 세션 관리 등등) 데이터 구조에서 주로 사용한다.
  • 글 스레드 기반이므로 하나의 명령이 오래 걸린다면 이는 적합하지 않다. 

 

 [02 Redis 설치 ] 

  • Redis는 윈도우 설치를 공식적으로 지원하지 않으므로 대신 윈도우에서 설치할 수 있도록 release 해주는 팀이 있다.
  • 해당페이지에 가서 다운로드를 받고 설치하면 된다.
    • 설치 옵션은 나의 경우 중간에 환경 변수 설정에만 체크해주었다.
  • 설치가 잘 되었는지 확인하는 법은 cmd 창을 켜고 아래 명령어를 작성했을 때 다음과 같은 명령어가 돌아온다면 정상적으로 설치된 상태이다.
redis-cli # redis의 기본 포트인 6379로 접속
ping # pong으로 응답

 

 [03 nodejs 코드에 적용하는 법 ] 

 (1) express에서 redis를 사용하려면 

  • 위에서 window 환경에 redis를 설치해 주었지만 nodejs express 환경에서 사용하려면 또 redis 라이브러리를 install 해야 한다.
  • 따라서 자신이 쓰는 패키지 매니저에서 redis를 설치해주면 된다.
    • 나의 경우 npm을 쓰고 있으므로 간단하게 vscode에서  npm i redis  명령어로 설치했다.

 (2) redis 라이브러리 호출 및 서버 연결 

  • 먼저 redis DB를 연결할 곳에서(보통 db 폴더의 index.js 파일) redis를 호출한다.
  • 그리고 redisClient를 생성해 준 뒤 캐시 서버에 저장해 둘 시간을 DEFAULT_EXPIRATION 변수에 설정한다.
    • 나의 경우 여기서 구글링의 힘이 필요했는데 대부분의 블로그 예제에서 createClient( )로 클라이언트를 생성해주기만 했기 때문이다. 그런데 아래 설정한 redis 연결시 콘솔 메시지가 뜨질 않는거다... 이상한데 오류메세지도 안떠서 그냥 그 상태로 다른 코드 다 작성하고 요청 메시지를 보내봤더니 다음과 같은 오류메세지가 떴다. 
ClientClosedError: The client is closed

 

    • 이 오류메세지를 구글링했더니 여기를 참고하면 node-redis V4 이상부터는  클라이언트명.connect( ) 를 해줘야 연결이 수립된다고 한다.
    • DEFAULT_EXPIRATION 변수는 필수는 아니고 나중에 redis 서버에 접근할 때 직접 설정해 줄수도 있지만 모두 같은 만료 시간으로 설정할 것이라면 정해두는 것이 편하다.
  • 마지막으로 확인을 위해 "connect"된 경우와 "error"가 발생한 경우에 console.log를 출력하도록 했다.
  • 또 redis를 호출한 파일과 사용할 파일이 다르다면 export 해주어야 함을 잊지 말자.
import * as Redis from "redis";

const redisClient = new Redis.createClient(); // redis 기본 포트는 6379
const DEFAULT_EXPIRATION = 3600; //seconds

// redis 서버 연결
redisClient.connect();

redisClient.on("connect", () => {
  console.log("정상적으로 Redis 서버에 연결되었습니다.");
});

redisClient.on("error", (error) => {
  console.log("Redis 서버 연결에 실패하였습니다..." + error);
});

export { redisClient, DEFAULT_EXPIRATION };

 (3) redis 캐시 확인 / 저장 

  • redis DB에 정상적으로 연결되었으면 이제 캐시 서버로서의 역할을 수행하게 해주어야 한다.
  • 캐시 서버라 함은 당연히 요청에서 요구하는 데이터가 캐시서버에 있으면 redis DB에서, 없으면 일반 DB에서 불러오고 그걸 다음을 위해 캐시 서버에 저장해두어야 한다.
    • 나의 경우 일반 DB로 mongoDB를 사용하고 있다.
  • 먼저 캐시서버에 있는지 확인하는 부분이다. 클라이언트에게 요청이 왔을 때  redis클라이언트명.GET( ) 으로 캐시에 저장된 키값을 검색한다.
    • 캐시가 있으면  JSON.parse(cache) 로 값을 전달해주고
    • 캐시가 없으면  redis클라이언트명.SETEX(키 이름, 캐시 서버 저장 만료 시간, 저장할 데이터) 의 구조로 캐시를 저장하는데 이 때 json 객체인 경우  JSON.stringfy(data) 의 형식으로 저장한다.
      • 주의할 점은 get 메소드는 상관이 없는데 setex는 자꾸 setex function을 찾을 수 없다는 오류가 떴고 구글링을 해도 아직 지원하는 메소드인 것 같아 이상해서 SETEX라고 대문자로 작성해봤더니 해결됐다...
      • SETEX라고 해도 안되시는 분들은 SET 메소드로 대신하고 expiration 옵션을 사용해도 상관없다.
    • 그리고 당연히 클라이언트에게도 요청에 대한 응답을 전송한다.
import { redisClient, DEFAULT_EXPIRATION } from "../db";
import { Router } from "express";
import { OutsideApi } from "../common/OutsideApi";

const OutsideApiRouter = Router();

OutsideApiRouter.get("/youtubeVideos", async (req, res, next) => {
  try {
    // redis 서버에서 캐시 확인
    const cache = await redisClient.GET(`youtubeVideos`);
    if (cache) {
      // 캐시가 있으면
      res.status(200).json(JSON.parse(cache));
    } else {
      const youtubeDatas = await OutsideApi.getYoutubeDatas();
      const searchedVideos = await OutsideApi.getSearchedVideos(youtubeDatas);

      await redisClient.SETEX(
        `youtubeVideos`,
        86400, // 유튜브 캐시는 하루동안 저장
        JSON.stringify(searchedVideos)
      );
      res.status(200).json(searchedVideos);
    }
  } catch (error) {
    next(error);
  }
});

export { OutsideApiRouter };
  • 나는 이번 프로젝트에서 redis 서버를 쓴 가장 큰 이유가 Youtube API 요청의 하루 할당량 때문이었는데 하루 접속자가 얼마나 될 지 예측이 안돼서 유튜브 캐시는 그냥 하루동안 저장하도록 해버렸다.
  • 이전에 설정한 DEFAULT_EXPIRATION 변수를 사용하려면 위의 코드에서 86400 대신 DEFAULT_EXPIRATION를 사용하면 된다.

 

 [04 redis-cli 명령어 ] 

 (1) 캐시를 잘못 저장한 경우 

  • 나의 경우 위와 같은 코드를 클라이언트 요청 응답이 큰 부분에 몇 개 적용했는데 그러다가 요청에 대한 응답이 이상해지는 경우가 종종 있었다.
    • 예를 들어 myPage... 지금 생각해도 웃긴데 myPage 응답이 크다고 냅다 redis 서버에 넣고 가져오기 했더니 모든 사용자의 myPage가 나의 정보로 응답되는 문제가 생겼다. 생각해보면 당연한데 별 생각 없이 응답이 크다고 아무데나 캐시를 사용하면 안된다는 교훈...!!
  • 어쨌든 이런 경우 캐시 서버에 데이터가 잘못 들어가 있기 때문에 삭제해줘야 하는데 위에서 redis가 잘 작동하는지 확인했던 명령어  redis-cli 로 redis 서버에 접속한다.
  • 그리고 키값으로 삭제하려면 ....를 사용하고 전체 데이터를 삭제하려면  flushdb  명령어를 사용한다.

 (2) 저장한 캐시가 잘 들어가 있는지 확인하고 싶은 경우 

  • 또 저장해놓은 캐시 내용이 기억나지 않으면  get {key이름}  형식으로 찾아볼 수 있다.
  • CLI가 불편하신 분들은 윈도우 프로그램으로 "Redis Desktop Manager" 프로그램을 설치해서 확인해도 된다.
    • 근데 유료버전으로 바꼈다더니 무료버전은 지원이 종료돼서 불편한게 많길래 나는 그냥 지웠다...

 

 [05 캐시 서버 사용 전후 응답속도 차이 ] 

  • 이렇게 캐시를 적용했으면 과연 응답속도가 진짜 빠른지!! 얼마나 빠른지!! 궁금할 것이다.
  • Postman으로 응답속도를 비교해볼 수 있다.
    • 캐시가 없을 경우 캐시를 저장하고 응답(위) 
    • 캐시가 있을 경우 redis 메모리에서 바로 응답(아래)
    • 623ms에서 8ms로 엄청나게 빠른 응답 속도로 반환하고 또 Youtube에도 요청을 수행하지 않으니 API 할당량이 줄어들지 않아 일석이조라고 할 수 있다! 😉