node.js에서 Redis 사용하기
조대협 (http://bcho.tistory.com)
Redis는 NoSQL 데이타 베이스의 한 종류로, mongoDB 처럼 전체 데이타를 영구히 저장하기 보다는 캐쉬처럼 휘발성이나 임시성 데이타를 저장하는데 많이 사용된다.
디스크에 데이타를 주기적으로 저장하기는 하지만, 이 기능은 백업이나 복구용으로 주로 사용할뿐 데이타는 모두 메모리에 저장되기 때문에, 빠른 접근 속도를 자랑한다.
이 이유 때문에 근래에는 memcached 다음의 캐쉬 솔루션으로 널리 사용되고 있는데, 간단하게 키-밸류 (Key-Value)형태의 데이타 저장뿐만 아니라, 다양한 데이타 타입을 지원하기 때문에 응용도가 높고, node.js 호환 모듈이 잘 지원되서 node.js와 궁합이 좋다. 여러 node.js를 클러스터링 하여 사용할때, node.js 인스턴스간 상태정보를 공유하거나, 세션과 같은 휘발성 정보를 저장하거나 또는 캐쉬등으로 다양하게 사용할 수 있다.
Redis가 제공하는 기능으로는 키로 데이타를 저장하고 조회하는 Set/Get 기능이 있으며, 메세지를 전달하기 위한 큐로도 사용할 수 있다.
큐로써의 기능은 하나의 클라이언트가 다른 클라이언트로 메세지를 보내는 1:1 기능뿐 아니라, 하나의 클라이언트가 다수의 클라이언트에게 메세지를 발송하는 발행/배포 (Publish/Subscribe) 기능을 제공한다.
그림 1 Redis의 Publish/Subscribe의 개념 구조
재미있는 것중에 하나는 일반적인 Pub/Sub 시스템의 경우 Subscribe 하는 하나의 Topic에서만 Subscribe하는데 반해서, redis에서는 pattern matching을 통해서 다수의 Topic에서 message 를 subscribe할 수 있다.
예를 들어 topic 이름이 music.pop music,classic 이라는 두개의 Topic이 있을때, "PSUBSCRIBE music.*"라고 하면 두개의 Topic에서 동시에 message를 subscribe할 수 있다.
자료 구조
Redis의 가장 기본이 되는 자료 구조를 살펴보자. Redis는 다양한 자료 구조를 지원하는데, 지원하는 자료 구조형은 다음과 같다.
1) String
Key에 대해서 문자열을 저장한다. 텍스트 문자열뿐만 아니라 숫자나 최대 512mbyte 까지의 바이너리도 저장할 수 있다.
2) List
Key에 대해서 List 타입을 저장한다. List에는 값들이 들어갈 수 있으며, INDEX 값을 이용해서 지정된 위치의 값을 넣거나 뺄 수 있고, 또는 push/pop 함수를 이용하여 리스트 앞뒤에 데이타를 넣거나 뺄 수 있다. 일반적인 자료 구조에서 Linked List와 같은 자료 구조라고 생각하면 된다.
3) Sets
Set 자료 구조는 집합이라고 생각하면 된다. Key에 대해서 Set을 저장할 수 있는데, List 구조와는 다르게 주의할점은 집합이기 때문에 같은 값이 들어갈 수 없다. 대신 집합의 특성을 이용한 집합 연산, 교집합, 합집합등의 연산이 가능하다.
4) Sorted Set
SortedSet은 Set과 동일하지만, 데이타를 저장할때, value 이외에, score 라는 값을 같이 저장한다. 그리고 이 score 라는 값에 따라서 데이타를 정렬(소팅)해서 저장한다. 순차성이나 순서가 중요한 데이타를 저장할때 유용하게 저장할 수 있다.
5) Hashes
마지막 자료형으로는 Hashes가 있는데, 해쉬 자료 구조를 생각하면 된다.Key에 해쉬 테이블을 저장하는데, 해쉬 테이블에 저장되는 데이타는 (field, value) 형태로 field를 해쉬의 키로 저장한다.
키가 있는 데이타를 군집하여 저장하는데 유용하며 데이타의 접근이 매우 빠르다. 순차적이지 않고 비순차적인 랜덤 액세스 데이타에 적절하다.
설명한 자료 구조를 Redis에 저장되는 형태로 표현하면 다음과 같다.
Figure 36 redis의 자료 구조
기본적으로 키/밸류 (Key/Value) 형태로 데이타가 저장되며, 밸류에 해당하는 데이타 타입은 앞서 언급하 String, List, Sets, SortedSets, Hashes가 있다.
Redis에 대한 설명은 여기서는 자세하게 하지 않는다. 독립적인 제품인 만큼 가지고 있는 기능과 운영에 신경써야할 부분이 많다. Redis에 대한 자세한 설명은 http://redis.io 홈페이지를 참고하거나 정경석씨가 쓴 “이것이 레디스다” http://www.yes24.com/24/Goods/11265881?Acode=101 라는 책을 추천한다. 단순히 redis에 대한 사용법뿐만 아니라, 레디스의 데이타 모델 설계에 대한 자세한 가이드를 제공하고 있다.
Redis 설치하기
개발환경 구성을 위해서 redis를 설치해보자.
맥
맥의 경우 애플리케이션 설치 유틸리티인 brew를 이용하면 간단하게 설치할 수 있다.
%brew install redis
윈도우즈
안타깝게도 redis는 공식적으로는 윈도우즈 인스톨을 지원하지 않는다. http://redis.io에서 소스 코드를 다운 받아서 컴파일을 해서 설치를 해야 하는데, 만약에 이것이 번거롭다면, https://github.com/rgl/redis/downloads 에서 다운로드 받아서 설치할 수 있다. 그렇지만 이경우에는 최신 버전을 지원하지 않는다.
그래서 vagrant를 이용하여 우분투 리눅스로 개발환경을 꾸미고 그 위에 redis를 설치하거나 https://redislabs.com/pricing 나 https://www.compose.io 같은 클라우드 redis 환경을 사용하기를 권장한다. ( 클라우드 서비스의 경우 일정 용량까지 무료 또는 일정 기간까지 무료로 서비스를 제공한다.)
리눅스
리눅스의 경우 설치가 매우 간단하다. 우분투의 경우 패키지 메니저인 apt-get을 이용해서 다음과 같이 설치하면 된다.
%sudo apt-get install redis-server
설치가 끝났으면 편하게 redis를 사용하기 위해서 redis 클라이언트를 설치해보자.
여러 GUI 클라이언트들이 많지만, 편하게 사용할 수 있는 redis desktop을 설치한다. http://redisdesktop.com/ 에서 다운 받은 후에 간단하게 설치할 수 있다.
이제 환경 구성이 끝났으니, redis를 구동하고 제대로 동작하는지 테스트해보자
%redis-server
명령을 이용해서 redis 서버를 구동한다.
Figure 37 redis 기동 화면
redis desktop을 이용해서 localhost 호스트에 Host 주소는 localhost로 TCP 포트는 6379로 새로운 Connection을 추가하여 연결한다.
Figure 38 redis desktop에서 연결을 설정하는 화면
연결이 되었으면 redis desktop에서 Console을 연다.
Figure 39 redis desktop에서 콘솔을 여는 화면
Console에서 다음과 같이 명령어를 입력해보자
localhost:0>set key1 myvalue OK
localhost:0>set key2 myvalue2 OK
localhost:0>get key2 myvalue2
localhost:0> |
Figure 40 redis desktop에서 간단한 명령을 통해서 redis를 테스트 하는 화면
위의 명령은 key1에 myvalue라는 값을 입력하고, key2에 myvalue2라는 값을 입력한 후에, key2에 입력된 값을 조회하는 명령이다.
Redis desktop에서, 디비를 조회해보면, 앞서 입력한 키/밸류 값이 저장되어 있는 것을 다음과 같이 확인할 수 있다.
\
Figure 41 redis에 저장된 데이타를 redis desktop을 이용해서 조회하기
node.js에서 redis 접근하기
이제 node.js에서 redis를 사용하기 위한 준비가 끝났다. 간단한 express API를 만들어서 redis를 캐쉬로 사용하여 데이타를 저장하고 조회하는 예제를 작성해보자
node.js 용 redis 클라이언트는 여러 종류가 있다. http://redis.io/clients#nodejs
가장 널리 쓰는 클라이언트 모듈로는 node-redis https://github.com/NodeRedis/node_redis 가 있는데, 이 예제는 node-redis 클라이언트를 기준으로 설명한다.
이 예제는 profile URL에서 사용자 데이타를 JSON/POST로 받아서 redis에 저장하고, TTL(Time to Leave) 방식의 캐쉬 처럼 10초 후에 삭제되도록 하였다.
그리고 GET /profile/{사용자 이름} 으로 redis에 저장된 데이타를 조회하도록 하였다.
먼저 node-redis 모듈과, json 문서를 처리하기 위해서 JSON 모듈을 사용하기 때문에, 이 두 모듈을 설치하자
% npm install redis
% npm install JSON
package.json 에 위 두 모듈의 의존성을 다음과 같이 정의한다.
{ "name": "RedisCache", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", "jade": "~1.11.0", "morgan": "~1.6.1", "serve-favicon": "~2.3.0", "redis":"~2.6.0", "JSON":"~1.0.0" } }
|
Figure 42 redis와 JSON 모듈의 의존성이 추가된 package.json
다음으로 express로 간단한 웹 프로젝트를 만든 후에, app.js에 다음과 같은 코드를 추가한다.
// redis example var redis = require('redis'); var JSON = require('JSON'); client = redis.createClient(6379,'127.0.0.1');
app.use(function(req,res,next){ req.cache = client; next(); }) app.post('/profile',function(req,res,next){ req.accepts('application/json');
var key = req.body.name; var value = JSON.stringify(req.body);
req.cache.set(key,value,function(err,data){ if(err){ console.log(err); res.send("error "+err); return; } req.cache.expire(key,10); res.json(value); //console.log(value); }); }) app.get('/profile/:name',function(req,res,next){ var key = req.params.name;
req.cache.get(key,function(err,data){ if(err){ console.log(err); res.send("error "+err); return; }
var value = JSON.parse(data); res.json(value); }); });
|
Figure 43 app.js에 redis에 데이타를 쓰고 읽는 부분
redis 클라이언트와, JSON 모듈을 로딩한후, createClient 메서드를 이용해서, redis에 대한 연결 클라이언트를 생성하자.
client = redis.createClient(6379,'127.0.0.1');
app.use(function(req,res,next){
req.cache = client;
next();
})
다음 연결 객체를 express router에서 쉽게 가져다 쓸 수 있도록, 미들웨어를 이용하여 req.cache 객체에 저장하도록 하자.
HTTP POST /profile에 의해서 사용자 프로파일 데이타를 저장하는 부분을 보면
req.accepts('application/json'); 를 이용하여 JSON 요청을 받아드리도록 한다.
JSON내의 name 필드를 키로, 하고, JSON 전체를 밸류로 한다. JSON을 객체 형태로 redis에 저장할 수 도 있겠지만 이 경우 redis에서 조회를 하면 객체형으로 나오기 때문에 운영이 불편하다. 그래서 JSON.stringfy를 이용하여 JSON 객체를 문자열로 변환하여 value 객체에 저장하였다.
다음 req.cache.set(key,value,function(err,data) 코드에서 redis에 저장하기 위해서 redis 클라이언트를 req 객체에서 조회해온후, set 명령을 이용해서 키/밸류 값을 저장한다. 저장이 끝나면 뒤에 인자로 전달된 콜백함수 가 호출 되는데, 이 콜백함수에서, req.cache.expire(key,10); 를 호출하여, 이 키에 대한 데이타 저장 시간을 10초로 설정한다. (10초 후에는 이 데이타가 삭제된다.) 마지막으로 res.json(value); 을 이용하여 HTTP 응답에 JSON 문자열을 리턴한다.
HTTP GET으로 /profile/{사용자 이름} 요청을 받아서 키가 사용자 이름은 JSON 데이타를 조회하여 리턴하는 코드이다.
app.get('/profile/:name',function(req,res,next) 으로 요청을 받은 후, URL에서 name 부분을 읽어서 키값으로 하고,
req.cache.get(key,function(err,data){ 를 이용하여, 키를 가지고 데이타를 조회한다. 콜백 함수 부분에서, 데이타가 문자열 형태로 리턴되는데, 이를 var value = JSON.parse(data); 를 이용하여, JSON 객체로 변환한 후에, res.json(value); 를 통해서 JSON 문자열로 리턴한다.
코드 작성이 끝났으면 테스트를 해보자 HTTP JSON/POST로 REST 호출을 보내야 하기 때문에, 별도의 클라이언트가 필요한데, 클라이언트는 구글 크롬 브라우져의 플러그인인 포스트맨(POSTMAN)을 사용하겠다. https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop
포스트맨 설치가 끝났으면, 포스트맨에서 HTTP POST/JSON 방식으로 http://localhost:3000/profile에 아래와 같이 요청을 보낸다.
Figure 44 포스트맨에서 HTTP POST로 profile 데이타를 삽입하는 화면
요청을 보낸후 바로 HTTP GET으로 http://localhost:3000/profile/terry 로 조회를 하면 아래와 같이 앞에서 입력한 데이타가 조회됨을 확인할 수 있다. 이때 위의 POST 요청을 보낸지 10초 내에 조회를 해야 한다. 10초가 지나면 앞서 지정한 expire에 의해서 자동으로 삭제가된다.
Figure 45 포스트맨에서 사용자 이름이 terry인 데이타를 조회하는 화면
Redisdesktop에서 확인을 해보면 아래와 같이 문자열로 terry 사용자에 대한 데이타가 저장되어 있는 것을 확인할 수 있다.
Figure 46 redis desktop 에서 입력된 데이타를 확인하는 화면
10초후에, 다시 조회를 해보면, terry를 키로 가지는 데이타가 삭제된 것을 확인할 수 있다.
지금까지 가장 기본적인 redis에 대한 소개와 사용법에 대해서 알아보았다. redis는 뒤에 나올 node.js 클러스터링의 HTTP 세션을 저장하는 기능이나, Socket.IO 등에서도 계속해서 사용되는 중요한 솔루션이다. Redis 자체를 다루는 것이 아니라서 자세하게 파고 들어가지는 않았지만, 다소 운영이 까다롭고 특성을 잘 파악해서 설계해야 하는 만큼 반드시 시간을 내서 redis 자체에 대해서 조금 더 자세하게 살펴보기를 권장한다.
'클라우드 컴퓨팅 & NoSQL > Vert.x & Node.js' 카테고리의 다른 글
빠르게 훝어 보는 node.js - 구글 앱앤진에 node.js 애플리케이션을 배포해보자. (1) | 2016.07.26 |
---|---|
빠르게 훝어 보는 node.js - redis 사용하기 (ioredis 클라이언트 버전) (0) | 2016.03.30 |
빠르게 훝어 보는 node.js - heapdump를 이용한 메모리 누수 추적 (0) | 2016.03.29 |
빠르게 훝어 보는 node.js - mongoose 스키마와 유용한 기능 (0) | 2016.03.29 |
빠르게 훝어 보는 node.js - mongoose ODM 을 이용한 MongoDB 연동 (0) | 2016.03.25 |