IT/프로그래밍

[NodeJS/Redis] 캐시를 사용한 리스트 전달하기

홀롤록 2021. 5. 4. 11:44
반응형

최근에 프로젝트를 진행하면서 구현했던 기능 중 하나에 대해 포스팅하고자 한다.

해당 기능을 구현하는데 사용된 것은 Redis, MySQL, NodeJS 이렇게 3가지가 주된 기능을 구현하는데 사용됐다.

개요는 위와 같고, 실제 구현된 기능에 대한 메인 요구사항은 다음과 같다.

관리자 페이지에서 등록된 이벤트 중 진행중인 이벤트 리스트는 상위에서 랜덤한 리스트 배열로 전달해주시고,
이외에 신청한 이벤트/종료된 이벤트는 아래에서 무한스크롤로 할 수 있도록 해주세요.

이 기능에 대해 등록되는 이벤트들의 개수는 큰 변화가 없을 것이고 빈번한 수정이 일어나는 리스트 데이터가 아니기 때문에 

캐싱을 하여 작업하도록 설계했고, 이외에 무한스크롤에 해당하는 데이터는 실제 RDB에 접근하여 전달하도록 설계했다.

 

구현한 순서는 아래와 같다.

1. 캐싱된 이벤트 리스트 가져오기. => MySQL 에서 주기적으로 조회하여 캐싱한다.
2. 종료된 이벤트에 대한 무한스크롤 (페이징처리)
3. 1번,2번 리스트를 기준으로 신청이력 가져오기.

처음에 위 기능을 구현하는데에는 문제가 없었다.

인스턴스별 로컬 캐시를 사용했기에, 로컬 캐시 데이터를 쌓을 때마다, TTL을 걸었고, 중간에 이벤트가 종료되면 다시 RDB에서 캐싱처리 하면서 진행중인 이벤트가 종료되는 기능까지는...

문제가 터진 것은 중간에 새롭게 등록하는 경우였다. 이벤트 시작의 최소단위는 1시간 이다. 그래서 TTL을 1시간 잡았는데, TTL로 인해 캐시데이터가 없는 짧은 사이에 많은 요청 트래픽이 있게 된다면 서버는 부하를 견디지 못하게 되고 다운되게 될 것이라는 CTO님의 전언..

위 같은 장애가 발생할 수 있다라고 이야기하시며 조언해주신 내용은 NHN Cloud에서 작성한 글이었다.

 

캐시 성능 향상기 (Improving Cache Speed at Scale) : NHN Cloud Meetup

레디스를 캐시로 사용할 때 데이터의 갱신을 위해 대부분의 서비스에서는 키에 대해 `Expire time(TTL)`을 설정합니다.

meetup.toast.com

이런 경우에 Redis 에서 키가 완전히 만료되기 전에 데이터를 먼저 읽어오게 하는 방법을 사용하여 Cache Stampede 현상을 막을 수 있다. 는 내용이 작성되어있다. 참고하여 작업한 내용은 캐싱된 데이터의 키값의 TTL을 확인하여 최소 live 시간 이후부터는 100분의 1확률로 데이터를 재 조회하고 재 캐싱할 수 있도록 작업하였다. 소스코드는 아래와 같다.

  // Local Redis에 있는 내용의 TTL을 확인하여
  // TTL 이 한시간 남아있는 경우
  // 1/100 확률로 데이터를 새로 가져와 리스팅 처리한다.
  const getRedisItemsAndTTL = await Redis.ttlByKey(REDIS_EVENT_KEY);
  const timing = random(1, 100) === 1;
  // KEEP_ALIVE_TTL => 60 * 60, CHECK_REFRESH_TTL => 60 * 50
  const limitTTL = REDIS_CONFIG.KEEP_ALIVE_TTL - REDIS_CONFIG.CHECK_REFRESH_TTL;

  if (getRedisItemsAndTTL <= 0 || (getRedisItemsAndTTL < limitTTL && timing)) {
    await Redis.renew(REDIS_EVENT_KEY);
  }

이렇게 작업하여 이슈 해결! 새로 등록하는 이벤트들도 정상적으로 노출할 수 있고,
중간에 만일 시간이 지나 이벤트가 마감되거나 종료됐다면 처리해주는 기능까지 구현을 완료하여 리스트 캐싱에 대해서 처리 완료했다.

반응형