Redis

AFDB·2024년 11월 18일
post-thumbnail

왜 redis(ElastiCache)?

redis는 인메모리 데이터 스토어로, 세션 유지, 실시간 데이터 처리, 캐싱 등 다양한 사용 사례에서 사용된다.
AWS ElastiCache는 Redis를 완전 관리형으로 제공하여, 확장성과 안정성을 더한 서비스다.

💡 일반적인 데이터베이스는 식당 안에서 음식을 만드는 주방이라고 볼 수 있다.

데이터베이스 조회를 주방에서 주문에 따라 음식을 처음부터 만들어야 하는 것에 비유할 수 있다.
만약 주문이 폭주(데이터베이스 조회량이 늘어나면)하면, 처리 속도가 느려져 대기 시간이 길어진다.

💡 ElastiCache는 인기 메뉴를 미리 만들어 두는 드라이브스루 창구와 같다.

미리 준비된 음식을(저장된 데이터를) 즉시 가져올 수 있어 주방에(데이터베이스에) 요청을 보낼 필요가 없다.
인기 메뉴만 미리 준비하듯, 자주 사용하는 데이터(세션 데이터나 API 응답 결과)를 ElastiCache에 저장해서 바로 사용하기 때문에 결과적으로 응답 속도가 빨라진다.

현재 문제점

🚨 컨테이너 전환 시 세션 정보 소실
사용자가 기존 backend_blue 컨테이너에서 로그인한 세션 정보는 최신 컨테이너인 backend_green으로 전환되면 사라진다.(각 컨테이너의 메모리에 저장된 세션 데이터에 접근할 수 없기 때문에)
이를 해결하기 위해 redis를 사용하려고 한다.

redis를 세션 저장소로 사용하면

사용자가 앱에 로그인하면, 세션 정보를 컨테이너 메모리가 아닌 redis에 저장한다. 세션 데이터는 사용자의 고유 식별자(user_idx)와 로그인 상태를 포함한다. 덕분에

  • 👍 컨테이너 간 세션 정보 공유 가능
    Blue-Green 간의 전환에도 세션 정보가 유지되므로 사용자 로그인이 풀리지 않는다.

  • 👍 빠른 자동 로그인
    사용자가 앱을 재실행할 때 Redis에서 세션 데이터를 빠르게 조회해 자동 로그인 처리 속도가 향상됩니다.

로컬에서 테스트

AWS redis OSS는 외부에서 접근이 안된다고 해서 로컬에 직접 Redis를 설치해 테스트했다.

1. Redis for Windows 다운로드 및 설치

2. 터미널에서 설치된 디렉토리로 이동 후 실행

PS C:\Program Files\Redis> .\redis-server.exe

3. ENV 파일을 로컬 환경에 맞게 수정한다.

REDIS_HOST=localhost
REDIS_PORT=6379
NODE_ENV=development

4. 새로운 터미널을 열어서 같은 경로에서 redis-cli.exe를 실행시킨다.

PS C:\Program Files\Redis> .\redis-cli.exe
127.0.0.1:6379> 

5. KEYS * 명령어로 세션 확인

PS C:\Program Files\Redis> .\redis-cli.exe
127.0.0.1:6379> 127.0.0.1:6379> KEYS *
1) "조회된 세션정보"

배포 서버에 적용하기

AWS ElastiCache 세팅

1. AWS 콘솔에서 ElasticCache 항목으로 이동해서 Redis OSS를 생성해준다.

클러스터 모드는 비활성화해준다.(노드1,샤드1)

2. 구성, 클러스터 모드, 위치 설정

자체 캐시 설계, 암호화 설정 후 생성해준다. 위치는 클러스터를 AWS 클라우드로 선택

3. 클러스터 설정

노드 유형 t2.micro가 프리티어 적용이 되어 무료고, 복제본 0으로 설정한다.

4. 보안 그룹

사용 중인 EC2 인스턴스의 보안 그룹을 선택한다.

5. 해당 보안 그룹의 인바운드 규칙에서 6479포트 열기

소스는 해당 보안그룹의 소스로 선택한다.

6. 생성

대기 시간은 10분 정도 걸렸던 것 같다.

코드에 적용하기

1. Redis 클라이언트 초기화 및 연결

Redis 작업을 위해 필요한 모듈을 require로 가져온다.

const RedisStore = require("connect-redis").default; // Redis 세션 스토어
const { createClient } = require("redis"); // Redis 클라이언트

createClient()를 사용해 Redis 클라이언트를 생성하고고 .env 파일에서 설정한 Redis의 host와 port를 가져온다. 클라이언트 연결에 성공하면 콘솔 로그 출력!

const redisClient = createClient({
  socket: {
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    tls: true,
  },
});

redisClient
  .connect()
  .then(() => console.log("redis is connected!"))
  .catch((err) => console.error("Redis connection failed...", err));

2. 세션에 Redis를 세션 스토어로 설정

// 기존 세션 관련 코드
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: true, 
    saveUninitialized: false, 
    cookie: {
      httpOnly: true, 
      maxAge: 2678400000, 
      secure: process.env.NODE_ENV === "production",
    },
  })
);

세션 정보가 서버의(배포서버에선 컨테이너의) 메모리에 저장되었었다.
이제 메모리가 아닌 Redis에 저장해야하므로 RedisStore를 store로 설정해준다.

// 수정 후 코드
app.use(
  session({
    store: new RedisStore({ client: redisClient }), // RedisStore로 세션 저장
    secret: process.env.SESSION_SECRET,
    resave: false, 
    saveUninitialized: false, 
    cookie: {
      httpOnly: true,
      maxAge: 2678400000, 
      secure: process.env.NODE_ENV === "production",
    },
  })
);

3. 주요 확인점

1. 배포 옵션에서 서버리스 사용하면 요금 청구가 많이 된다 🧨
서버리스 설명:
서버를 관리하지 않고도 애플리케이션 트래픽 수요에 맞게 자동으로 확장되는 캐시를 빠르게 생성하는 데 사용합니다.
사용하는 만큼만 탄력적으로 비용 청구가 되는 합리적인 요금제인줄 알았는데, 그냥 프리티어로 무료사용 가능한 t2.micro 사용하면 된다. 확장이 필요하면 그때 바꾸면 될 것 같다.

2. 위에서 말한 5. 해당 보안 그룹의 인바운드 규칙에서 6479포트 열기
처음에 보안 그룹의 인바운드 규칙 편집에서 내 IP주소에서 허용하는 것으로 무지성 설정했다가 구글링과 GPT에 물어보니 EC2에서 실행되는 것이므로 같은 보안 그룹 소스를 참조해야한다고 한다.

3. ENV 확인!.
AWS ElasticCache의 Redis OSS 캐시에서 조회해보면 엔드포인트가 <캐시이름>-<어쩌고저쩌고>amazonaws.com:6379
이렇게 나오는데, 이 주소를 그대로

REDIS_HOST=<캐시이름>-<어쩌고저쩌고>amazonaws.com:6379 //(X)

이렇게 복사했다가 실행 오류가 계속 나왔다.
뒤에 포트번호 :6379는 뺴줘야한다.

REDIS_HOST=<캐시이름>-<어쩌고저쩌고>amazonaws.com //(O)

4. 저장, 전송 중 암호화 설정
Redis 클러스터를 생성할 때, 암호화를 사용하도록 설정되어 있다면, 클라이언트에서도 TLS를 사용해야 한다.

const redisClient = createClient({
  socket: {
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    tls: true, // 추가!
  },
});

0개의 댓글