SRE TechNote/Nodejs

Nodejs + Redis 연동하기

Halfmoon 2021. 11. 9. 15:55

개요

redis를 사용하는 이유는 여러 가지이겠지만, 세션 저장용 혹은 데이터의 빠른 접근이 필요할 때 사용하면 아주 유용한 서비스이다. redis를 pod 혹은 서버로 띄워서 사용할 수도 있지만 운영하는데 힘이 덜 드는 완전 관리형 서비스인 AWS ElastiCache의 Redis 서비스를 사용하는 것을 추천한다.

 

타 서비스의 API를 호출하여 데이터를 시각화하는 플랫폼을 운영 중이다. 하지만 많은 데이터를 호출하기에는 불필요한 트래픽이 오갔고 타 서비스의 API 서버에서의 Call이 제한되어 불러오지 못하는 경우가 있었다. 이를 어떻게 해결했는지 알아보자.

Redis 환경 설정

기본적으로 Redis는 VPC 위에서 구성이 되며, 각 application 혹은 관리자의 접근만을 제어하기 위해서 private 하게 구성해야 한다.

기본 및 리더 엔드포인트가 주어지며, 리더는 말 그대로 'reader' 읽기만 사용 가능한 엔드포인트 이므로 Redis에 데이터를 쓰기 위해서는 기본 엔드포인트로 환경변수를 잡아줘야 한다.

 

Redis CLI

Redis cli 설치 (linux)

sudo yum install -y gcc
wget http://download.redis.io/redis-stable.tar.gz && tar xvzf redis-stable.tar.gz && cd redis-stable && make
sudo cp ~/redis-stable/src/redis-cli /usr/bin

Redis 접속

redis-cli -h srebgk-redis.******.**.****.apn2.cache.amazonaws.com -p 6379

접속이 잘 안될 경우에는 redis에 설정된 방화벽 (SG)를 잘 확인해보자. telnet으로 아래와 같이 접속이 안된다면 sg문제일 경우가 크다.

telnet <<redis-endpoint>> 6379 
Trying 10.***.***.203...
Connected to srebgk-redis.******.**.****.apn2.cache.amazonaws.com.

CRUD 명령

> keys *

# GET
> get <key>

# SET
> set <key> <value>

# 여러개의 Key GET / SET
> mget <key> <key2>
> mset <key> <value> <key2> <value2>

# DELETE
> del <key>
# (integer) 1일 경우 삭제 성공 (integer) 0일 경우 해당 Key 존재 X

 

 

redis-cli, the Redis command line interface – Redis

*redis-cli, the Redis command line interface redis-cli is the Redis command line interface, a simple program that allows to send commands to Redis, and read the replies sent by the server, directly from the terminal. It has two main modes: an interactive m

redis.io

NodeJs 설정

npm을 이용해 redis 라이브러리를 설치한다. 해당 라이브러리를 이용해 nodejs와 redis의 연동이 가능하다. 자세한 내용은 아래 문서를 참고.

npm install --save redis

 

 

redis

A high performance Redis client.

www.npmjs.com

createClient 구문을 이용해 Redis Port와 URL을 지정해 줄 수 있다. 위에서 확인한 기본 엔드포인트 및 포트 6379를 적용하면 된다.

const redis = require('redis');
const redis_client = redis.createClient(REDIS_PORT,REDIS_URL);

// Redis
redis_client.on("error", (err) => {
  console.error(err);
});

redis_client.on("ready", ()=> {
  console.log("Redis is Ready");
});

 

nodejs의 장점인 미들웨어로 생성해 redis를 불러오는 곳에 미들웨어를 끼워 넣는다. redis에 key값이 존재하지 않을 경우 set 함수를 통해 데이터를 redis에 저장하고 해당 key가 존재할 경우 redis의 값을 반환한다.

전체적인 코드를 리뷰할 순 없지만 대략적인 flow는 이렇다. 해당 월에 일치하는 데이터는 set_expireOneHourCache를 호출해 한 시간 뒤에 만료되는 key를 저장하고, 그 외에는 영구적으로 저장되는 key를 저장한다.

 

const set_cache = ( key, value ) => {
  redis_client.set( key, JSON.stringify(value) );
  console.log('Redis set Data',key);
}

const set_expireOneHourCache = ( key, value ) => {
  redis_client.set( key, JSON.stringify(value), 'EX', 60*60 );
  console.log('60 Mins Expire Redis set Data',key);
}

const get_listCache = ( request, response, next ) => {
  response.set('Access-Control-Allow-Origin','*')
  var key = request.query.started_at + '&' +String(request.query.page);
  redis_client.get(key, (error, data) => {
    if (error) response.status(400).send(error);
    if (data !== null) response.status(200).send(JSON.parse(data));
    else next();
  })
}

router.get('/list', get_listCache, (request, response) => {
  response.set('Access-Control-Allow-Origin','*')
  axios({
    url: `${API_URL}`,
    method: 'get',
    headers: { "Content-Type": "application/json" },
  }).then(res => {
    if (request.query.started_at == changeDateFormat( year, month, 1 ) ){
      set_expireOneHourCache(request.query.started_at + '&' +String(request.query.page), res.data)
    }else{
      set_cache(request.query.started_at + '&' +String(request.query.page), res.data);
    }
    response.send(res.data);
  }).catch(function(error){
      response.send({status: 429, statusText: JSON.stringify(error)});
      console.log(JSON.stringify(error))
  })

})

 

Redis를 구성함으로써 불필요한 데이터 호출을 줄였고 Too Many Request 오류를 99%로 해결할 수 있었다.

환경마다 다르겠지만 Redis를 통해 데이터를 읽어올 때와 그렇지 않을 때의 속도 차이는 꽤 크다. 자신이 원하는 성능이 나오지 않을 때 Redis를 도입해 보는 것도 좋을 것이다.