게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌19 - NodeJS - 7년 전 등록 / 5년 전 수정

Redis

Node와 연동하기

안녕하세요. 이번 시간에는 Redis를 배워보고 노드와 연동하는 방법에 대해 알아보겠습니다.

undefined

Redis는 NoSQL 데이터베이스 중 하나로 다양한 자료구조를 저장할 수 있습니다. NoSQL 데이터베이스가 많은데 왜 그 중에서 레디스를 쓸까요? 바로 In-memory라는 특성 때문입니다.

처음 노드를 하시는 분들은 아마 express-session을 사용할 때 store로 메모리 스토어를 사용하고 계실 겁니다. 메모리 스토어는 서버를 재시작 하는 순간 저장했던 내용들이 날아가버립니다. 만약 서버를 재시작해도 데이터를 유지하고 싶다면 어떻게 해야 할까요? 데이터베이스를 사용해서 데이터를 유지하는 것이겠죠?

그런데 데이터베이스는 접근하고, 커넥션을 유지하고 하는 데 비용이 많이 듭니다. 세션같은 것은 간단한 데이터(심지어 단순 문자열 하나)를 사용해서 저장해도 되거든요. MySQL, MongoDB같은 데이터베이스에 저장하는 것은 뭔가 비용이 많이 들고 속도도 느릴 것 같습니다.

이 때 절충안이 레디스입니다. 데이터베이스라서 데이터가 어느 정도 유지도 되면서 데이터를 불러올 때 메모리에 로드하기 때문에 접근 속도가 매우 빠릅니다. 세션이나 간단한 키-값, 간단한 자료 구조 데이터를 유지할 수 있으면서도 속도도 빠르게 사용할 수 있는 것이죠. 노드 클러스터링 시 pid가 달라 세션이 유지되지 않는 문제도 레디스를 통해 세션을 공유함으로써 해결할 수 있습니다.

또한 레디스는 Pub/Sub 서버로도 많이 씁니다. Pub는 퍼블리시, Sub는 섭스크립션인데, 출간/구독과 비슷한 개념입니다. 신문 구독 신청을 하면 신문이 나올 때마다 배달이 오듯, 알림 같은 것을 미리 받도록 신청하고 알림 상황이 발생하면 구독했던 클라이언트들에게 알림을 전달하는 것입니다.

다만 레디스의 단점은 데이터가 항상 정확하게 유지됨을 보장하지는 않는다는 것입니다. 따라서 유지되면 좋긴 하지만 날아가도 서비스 자체에 큰 지장이 없는 데이터를 저장하는 게 좋습니다.

자료구조

먼저 레디스 자료구조부터 알아봅시다. 코드는 노드의 redis 모듈 기반으로 작성합니다. redis 모듈은 레디스의 커맨드를 모두 지원합니다. 커맨드가 너무 많아 쓸 만한 것들만 추려보았습니다. npm i redis로 설치한 후 다음 코드로 연결합니다. 레디스 데이터베이스 프로그램은 따로 설치하고 실행해야 합니다. 또는 elastiCache나 Redis Lab같은 호스팅 서비스를 사용할 수도 있습니다.

const redis = require('redis');
const client = redis.createClient();

나머지 코드는 데이터베이스 연결 후 이어서 쓰면 됩니다. 호스팅을 사용하는 경우에는 createClient의 인자로 주소를 넣으면 됩니다.

string

먼저 가장 일반적인 키-값 문자열입니다. set으로 설정하고 get으로 가져옵니다.

client.set('name', 'zerocho');
client.get('name', (err, reply) => {
  console.log(reply); // zerocho
});

hash

키-해시입니다. 객체를 저장한다고 보시면 됩니다. hmset으로 설정하고 hgetall로 가져옵니다.

client.hmset('friends', 'name', 'zero', 'age', 24);
client.hgetall('friends', (err, obj) => {
  console.log(obj); // { name: 'zero', age: '24' }
});

list

키-배열입니다. 중복 데이터를 허용합니다. rpush는 자바스크립트의 push랑 비슷하고, lpush는 unshift랑 비슷합니다. 가져올 때는 lrange 메소드를 사용하는데요. 0, -1는 처음과 끝 인덱스를 의미합니다. -1이 배열의 가장 끝인건 아시죠? 결과에서 pear가 왜 banana보다 앞에 있는지는 잘 생각해보시기 바랍니다.

client.rpush('fruits', 'apple', 'orange', 'apple');
client.lpush('fruits', 'banana', 'pear');
client.lrange('fruits', 0, -1, (err, arr) => {
  console.log(arr); // ['pear', 'banana', 'apple', 'orange', 'apple']
});

set

키-셋입니다. 배열과 비슷하지만 중복을 허용하지 않습니다. 고양이가 귀엽기 때문에 두 번 넣어보겠습니다. 하지만 중복은 무시되고, 넣었던 순서와 상관없이 섞인 결과가 출력되었습니다.

client.sadd('animals', 'dog', 'cat', 'bear', 'cat', 'lion');
client.smembers('animals', (err, set) => {
  console.log(set); // ['cat', 'dog', 'bear', 'lion']
});

sorted set

키-정렬셋입니다. 셋인데 순서를 정렬할 수 있습니다. 키 순으로 정렬해보겠습니다. 여기서나마 제 키는 180입니다. list와 비슷한 방법으로 데이터를 가져옵니다. 오름차순으로 정렬되는데 내림차순으로 하고싶다면 zrevrange가 있습니다.

client.zadd('height', 180, 'zero', 168, 'aero', 176, 'nero', 172, 'hero');
client.zrange('height', 0, -1, (err, sset) => {
  console.log(sset); // ['aero', 'hero', 'nero', 'zero'
});

geo

키-경도위도입니다. 잘만 사용하면 정말 편리합니다. longitude가 먼저라는 것에 주의합시다. 위치들을 추가한 후 위치간 거리나 특정 좌표 중심으로 해당하는 지역을 구할 수 있습니다.

client.geoadd('cities', 126.97, 37.56, 'seoul', 129.07, 35.17, 'busan', 126.70, 37.45, 'incheon');
client.geodist('cities', 'seoul', 'busan', (err, dist) => {
  console.log(dist); // 325619.5465
});
client.georadius('cities', 126.8, 37.5, 50, 'km', (err, cities) => {
  console.log(cities); // ['incheon', 'seoul']
});

hyperloglog

얜 써본 적이 없어서 뭔지 잘 모르겠습니다;; 적은 메모리로 원소의 숫자를 최대한 근접하게 산출해낸다고는 하는데 써볼 기회가 없네요.

기타 명령어

열심히 키와 값을 설정했으니 지울 수도 있어야겠죠?

client.del('name');

키가 존재하는 지 확인하는 명령어입니다.

client.exists('name'); // 있으면 1 없으면 0

키 이름을 바꾸는 명령어입니다.

client.rename('animals', 'pets');

커맨드가 너무 많아 기본적인 get set만 소개하였습니다. 다른 커맨드들은 레디스 홈페이지 에서 찾아보실 수 있습니다. 커맨드 이름이 redis 모듈의 메서드명이기 때문에 그대로 사용하시면 됩니다.

express-session과 함께 사용하기

보통 레디스는 세션 저장 용도로 많이 사용합니다. 익스프레스에서 세션하면 express-session이 떠오르죠? 이 패키지도 Redis와의 연동을 지원합니다.

npm i connect-redis

일단 express용 redis를 하나 설치합니다.

const session = require('express-session');
const connectRedis = require('connect-redis');
const RedisStore = connectRedis(session);
const sess = {
  resave: false,
  saveUninitialized: false,
  secret: sessionSecret,
  name: 'sessionId',
  cookie: {
    httpOnly: true,
    secure: false,
  },
  store: new RedisStore({ url: '레디스 호스팅 주소', logErrors: true }),
};
app.use(session(sess));

익스프레스 세션의 다른 설정은 알아서 하시면 됩니다. store만 주목해주세요. store는 세션을 어디에 저장할지를 고르는 옵션입니다. 기본값은 메모리 스토어로, 서버의 메모리에 저장합니다. 따라서 서버가 꺼지면 세션 데이터들이 다 날아가는 것이죠. 이것을 RedisStore로 바꾸면 이제 세션 데이터를 레디스에 저장합니다. 서버가 꺼져도 데이터가 유지되는 것이죠. logErrors는 레디스 에러를 로깅하는 것이라 필요에 따라 껐다 켰다 하시면 됩니다.

생각보다 별 거 없죠? 하지만 다양한 자료구조를 저장할 수 있는 만큼 레디스는 활용도가 무궁무진합니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

11개의 댓글이 있습니다.
2년 전
"redis": "^4.0.6", 버전으로 되어있어서 npm uninstall redis 로 지우고
교재 버전대로 맞췄더니 이제는 됩니다... npm install redis@3.0.2
답변해주셔서 감사합니다.
3년 전
말씀해주신대로 체크는 하고 있는데 쿠키 저장 확인했고, 라우터에 오류없이 세션도 저장되는거같은데 세션이 redis 에 저장되 있는동안은 사이트가 무한로딩 하고 있습니다.
3년 전
안녕하세요 제로님 항상 좋은 정보 감사하고 있습니다, pm2 클러스터모드 적용하고나서 세션관리를 하고자 redis 를 적용하고 로그인하면 사이트 응답이 없습니다. redis 서버에서 키값을 검색하면 이런 식으로 나오는데
1) "sess:wI50hayKjThhQ0ee8PXGT5gebiW3YR1Z,{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":{\"id\":3,\"accessToken\":\"\"}}},EX,86400"
다른 별도의 오류 로그가 없어서 혹시 어디를 점검해야 할지 조언을 부탁드립니다 ㅠ
3년 전
로그인 라우터에 서버 에러가 있을텐데요?? 브라우저에는 쿠키가 제대로 저장되었나요?
3년 전
You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:
Error: The client is closed
at Commander._RedisClient_sendCommand

오류가 있습니다. 어디가 문제인지 감이 안옵니다.
3년 전
promise이므로 catch를 붙여보세요.
4년 전
secure를 true로 설정하면 어떤 내용을 추가해야 할까요,,,?
4년 전
저자님의 책을 보고 그대로 따라해봤는데 에러가 발생합니다..그래서 코드를

var host = process.env.RedisHost;

var port = process.env.RedisPort;

var password = process.env.RedisPassword;

// 여기부터 추가 ***********

var redisClinet = redis.createClient(port, host);

var redisConnectionResult = redisClinet.auth(password, err => {

if (err) console.log(err, " 에러 발생했습니다");

});

console.log("redis 연결 결과는? - ", redisConnectionResult);

// 여기까지 추가 ***********

위의 부분을 인터넷을 보고 추가헀는데 다음의 오류가 발생합니다..

etaddrinfo ENOTFOUND redis~~
code: 'UNCERTAIN_STATE',
command: 'AUTH',
args: [ 'G1Q6SApVCEqHPURBircDbLUAqF3vKS2h' ]
} redis 에러
redis 연결 결과는? - true
어떻게 해결해야할까요..? 레디스를 데리스 홈페이지에서 등록을 할 때 잘못한거일까요?
4년 전
제 책 코드가 아닌 코드는 답변을 드리기 어렵습니다. 제 책 코드는 버전을 맞추면 잘 동작합니다. 아마 버전이 제 책과 다른것 같습니다.
4년 전
뒤로가기 할때 서로 다른 시스템에 세션처리가 가능할까요?
4년 전
서로 다른 시스템이라는 게 어떤 시스템을 의미하시는 건가요?
4년 전
네 도메인이 다른 시스템입니다.
4년 전
도메인이 다르더라도 세션 쿠키가 같다면 레디스에서 세션공유 가능합니다.
5년 전
레디스 서버가 꺼지면 메모리에 남아있던 데이터는 다 날라가는건가요?? 이거를 저장하는 방법은 따로 없나용..
5년 전
express-session 관련해서 오타 때문에 동작이 안됩니다.
7년 전
node js로 시리얼통신 송신 수신 하는방법도 알고 싶은데 알려주실수있으신가요??
7년 전
레디스 데이터 베이스는 말씀해주신 세션데이터 사용에 엄청 적합합니다 특히 node.js를 클러스터링 해서 사용하면 pid가 서로 달라서 로그인을 제대로 캐치 못합니다 그럴때 사용해도 한방에 해결이 가능하죠!
7년 전
감사합니다! 말씀해주신 내용도 넣도록 하겠습니다!