안녕하세요. 이번 시간에는 Redis를 배워보고 노드와 연동하는 방법에 대해 알아보겠습니다.
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는 레디스 에러를 로깅하는 것이라 필요에 따라 껐다 켰다 하시면 됩니다.
생각보다 별 거 없죠? 하지만 다양한 자료구조를 저장할 수 있는 만큼 레디스는 활용도가 무궁무진합니다.
교재 버전대로 맞췄더니 이제는 됩니다... npm install redis@3.0.2
답변해주셔서 감사합니다.