node js와 redis를 사용한 구조화된 데이터

30
제제제 제제제 Node Js 9 제 Node 제 Redis 제 제제제 제제제제 제제제 박박박

Upload: jinojjan

Post on 27-Nov-2014

2.171 views

Category:

Software


1 download

DESCRIPTION

Node Js와 Redis를 사용한 구조화된 데이터

TRANSCRIPT

Page 1: Node Js와 Redis를 사용한 구조화된 데이터

제대로 배우는 Node Js 9 장 Node 와 Redis 를 사용한 구조화된 데이터

박진호

Page 2: Node Js와 Redis를 사용한 구조화된 데이터

목차

Node 및 Redis 시작 게임 순위표 만들기 메시지 큐 만들기 Express 애플리케이션에 Stats 미들웨어

추가

Page 3: Node Js와 Redis를 사용한 구조화된 데이터

Redis, Memcached, Cassan-dra

메모리 내의 키 / 값 저장소로 유명 Node 는 Redis, Memcached, Cassan-

dra 모두 지원

Page 4: Node Js와 Redis를 사용한 구조화된 데이터

Memcached

빠른 액세스를 위해 데이터 쿼리를 메모리 상에 캐시하기 위해 사용

분산 컴퓨팅에도 적합 복잡한 데이터에 대해서는 제한된 지원만을

제공 대량의 쿼리를 처리하는 애플리케이션에는

유용하지만 , 데이터를 읽고 쓰는 것이 많은 애플리케이션에서는 유용성이 떨어짐

http://memcached.org/

Page 5: Node Js와 Redis를 사용한 구조화된 데이터

Cassandra

MemCached 처럼 클러스터 지원 MemCached 와 마찬가지로 지원하는

데이터 구조가 제한 Redis 에 적합하지 않은 임시 쿼리를

처리하는데 알맞음 http://cassandra.apache.org/

Page 6: Node Js와 Redis를 사용한 구조화된 데이터

Redis

데이터를 읽고 쓰는 것이 많은 곳에 사용 영속적으로 저장 가능 다양한 유형의 데이터를 지원 .

(Memcached 에 비해 더 많은 유연성 제공 )

Cassandra 에 비해 빠름 .

단일 머신에서만 구동 . Http://redis.io/

Page 8: Node Js와 Redis를 사용한 구조화된 데이터

Redis 클라이언트 접속

Page 9: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기

데이터베이스를 이용하면 데이터를 영속적으로 관리할 수 있지만 , 입출력에 다소 시간이 걸리기 때문에 실시간 서비스에서는 더 적합한 저장소를 사용할 필요

Redis 는 메모리 기반의 저장소이기 때문에 필요한 정보를 빠르게 저장하고 가져올 수 있는 실시간 서비스에 적합한 저장소

멤버 id, 플레이어 이름 , 게임이름 , 마지막 플레이한 날짜 , 점수 , 나머지 관련 정보 저장 .

https://github.com/dmajkic/redis/downloads

Page 10: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – 기본 모듈

Redis 를 사용하여 구현 . npm install redis

hiredis 라는 공식적인 hiredis C 라이브러리를 바인딩하여 Non-Blocking 의 빠른 모듈 npm install hiredis redis

Async 설치 (series 기능 사용하기 위함 . 호출이 순서대로 호출되고 데이터 역시 순서대로 반환 보장 ) npm install async

Page 11: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – 기본 모듈 Redis 모듈 포함

Var redis = require(‘redis’);

Redis 클라이언트 생성 Var client = redis.createClient(); 3 개의 선택적인 파라미터▪ Port : 6379▪ Host : 127.0.0.1▪ 옵션 : parser, return_buffers, detect_buffers, socket_nodelay,

no_ready_check 연결 종료

Client.quit(); 강제 종료

Client.end();

Page 12: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – Redis 모듈

Redis 모듈 포함 Var redis = require(‘redis’);

Redis 클라이언트 생성 Var client = redis.createClient(); 3 개의 선택적인 파라미터▪ Port : 6379▪ Host : 127.0.0.1▪ 옵션 : parser, return_buffers, detect_buffers, socket_nodelay,

no_ready_check 연결 종료

Client.quit(); 강제 종료

Client.end();

Page 13: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – Redis 동작

Redis 해시 속성 설정Client.hset(“hashid”, “propname”, “propvalue”, function(err, reply){

오류 혹은 응답에 대해 무엇인가를 수행} );

성공 확인 응답 Rredis.print▪ 에러나 응답을 콘솔에 출력 후 반환

Client.hset (“hashid”, “propname”, “propvalue”, redis.print);

Page 14: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기

Page 15: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – 서버var net = require('net');var redis = require('redis');

var server = net.createServer(function(conn) {   console.log('connected');

   // create Redis client   var client = redis.createClient();

   client.on('error', function(err) {     console.log('Error ' + err);   });

   // fifth database is game score database

   client.select(5);

   conn.on('data', function(data) {      console.log(data + ' from ' + conn.re-moteAddress + ' ' +        conn.remotePort);      try {         var obj = JSON.parse(data);

         // add or overwrite score         client.hset(obj.member, "first_name", obj.first_name, redis.print);         client.hset(obj.member, "last_name", obj.last_name, redis.print);         client.hset(obj.member, "score", obj.s-core, redis.print);         client.hset(obj.member, "date", obj.-date, redis.print);

         // add to scores for Zowie!         client.zadd("Zowie!", parseInt(obj.score), obj.member);      } catch(err) {         console.log(err);      }   });   conn.on('close', function() {        console.log('client closed connection');        client.quit();   });

}).listen(8124);

console.log('listening on port 8124');

Page 16: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – 클라이언트 var net = require('net');

var client = new net.Socket();client.setEncoding('utf8');

// connect to TCP serverclient.connect ('8124','examples.burningbird.net', function () {    console.log('connected to server');});

// prepare for input from terminalprocess.stdin.resume();

// when receive data, send to serverprocess.stdin.on('data', function (data) {   client.write(data);});

// when receive data back, print to consoleclient.on('data',function(data) {    console.log(data);});

// when server closedclient.on('close',function() {    console.log('connection is closed');}); 

Page 17: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – Redis 동작

두개의 다른 데이터 저장소가 업데이트 됨 .

개별적인 점수 정보 ( 이름 , 점수 , 날짜를 포함 ) 은 hash 에 저장 Client.hset ( obj.member, “first_name”,

obj.first_name, redis.print );

멤버 id 와 점수는 sorted set 에 저장 Client.zadd( “Zowie!”, parseInt(obj.score),

obj.member );

Page 18: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – score.jade

Score.jade Doctype 5 doctype html

Page 19: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – 상위득점 서버

Page 20: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – Score.jade

doctype htmlhtml(lang="en")  head    title Zowie! Top Scores    meta(charset="utf-8")    | <style type="text/css">    include main.css    | </style>  body    table      caption Zowie! Top Scorers!        tr          th Score          th Name          th Date          if scores.length            each score in scores              if score                tr                  td #{score.score}                  td #{score.first_name} #{score.last_name}                  td #{score.date}

Page 21: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – main.css

body {  margin: 50px;}table {  width: 90%;  border-collapse: collapse;}table,td,th,caption {  border: 1px solid #000;}td {  padding: 20px;}

caption {  font-size: larger;  background-color: #ff0;  padding: 10px;}h1 {  font: 1.5em Georgia, serif;}ul {  list-style-type: none;}form {  margin: 20px;  padding: 20px;}

Page 22: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – topScore-Server9-3 var http = require('http');

var async = require('async');var redis = require('redis');var jade = require('jade');

// set up Jade templatevar layout = require('fs').readFileSync(__dirname + '/score.jade', 'utf8');var fn = jade.compile(layout, {file-name: __dirname + '/score.jade'});

// start Redis clientvar client = redis.createClient();

// select fifth databaseclient.select(5);

// helper functionfunction makeCallbackFunc(member) {   return function(callback) {      client.hgetall(member, function(err, obj) {         callback(err,obj);      });   };}

http.createServer(function(req,res) {

   // first filter out icon request   if (req.url === '/favicon.ico') {      res.writeHead(200, {'Content-Type': 'image/x-icon'} );      res.end();      return;   }

   // get scores, reverse order, top five only   client.zrevrange('Zowie!',0,4, function(err,result) {      var scores;      if (err) {         console.log(err);         res.end('Top scores not currently available, please check back');         return;      }

     

Page 23: Node Js와 Redis를 사용한 구조화된 데이터

게임 순위표 만들기 – topScore-Server9-3 // create array of callback func-

tions for Async.series call      var callFunctions = new Ar-ray();

      // process results with make-CallbackFunc, push newly re-turned      // callback into array      for (var i = 0; i < re-sult.length; i++) {         callFunctions.push(makeCallbackFunc(result[i]));      }

      // using Async series to process each callback in turn and return      // end result as array of objects      async.series(         callFunctions,         function (err, result) {            if (err) {               console.log(err);               res.end('Scores not available');               return;            }

            // pass object array to template en-gine            var str = fn({scores : result});            res.end(str);       });   });}).listen(3000);

console.log('Server running on 3000/');

Page 24: Node Js와 Redis를 사용한 구조화된 데이터

메시지 큐 만들기

메시지 큐 특정한 통신 형식을 입력으로 받아 큐에 저장하는

애플리케이션

메시지는 메시지 수신자가 가져갈 때 까지 저장되었다가 해당 시점에 큐에서 뽑혀져서 수신자에게 전송 ( 한번에 하나씩 혹은 대량 ))

통신은 비동기로 이루어짐

Page 25: Node Js와 Redis를 사용한 구조화된 데이터

메시지 큐 만들기

메시지 큐를 보여주기 위해 여러 개의 다양한 하위 도메인에 대한 웹 로그 파일에 접근하는 애플리케이션

메시지 큐 애플리케이션이 수행하는 것은 3000번에서 메시지를 수신대기하다가 전송된 항목을 Re-dis 데이터 저장소로 저장

로그 항목을 받은 후 로그 데이터에서 이미지 리소스(jpg, gif 등 ) 가 접근되었는지를 찾아보는 정규식 검사를 수행 . 일치하는 패턴이 발견되면 리소스 URL을 메시지 큐 애플리케이션에 전송

Page 26: Node Js와 Redis를 사용한 구조화된 데이터

Redis 클라이언트 생성 시점 Redis 클라이언트를 만들어서 애플리케이션이 종료될 때 까지

지속 ? Redis 클라이언트를 만든 후 Redis 명령어를 실행하자 마자

바로 해제 ?

영구적이 좋은가 ? 즉시 해제하는 것이 좋은가 ? 클라이언트 연결유지가 더 빠를것이라는 예상 맞음 . 연결을 유지하는

경우를 테스트 하는 도중 애플리케이션이 잠시 동안 상당히 느려졌다가 상대적으로 빠른 속도를 회복

Redis 데이터베이스에 대해 대기 중인 요청들이 큐가 해제도리 때 까지 Node 애플리케이션을 일시적으로 차단시켰기 때문 . 매번 요청할 때마다 연결을 열고 닫는 경우에는 동일한 상황을 겪지 않았는데 , 열고 닫는 과정에 들어가는 추가 오버헤드가 애플리케이션의 성능을 저하시켜서 동시 사용자 상한선에 도달하지 않았기 때문

Page 27: Node Js와 Redis를 사용한 구조화된 데이터

Express 애플리케이션에 Stats 미들웨어 추가 이전 장들에서 만들어본 위젯 애플리케이션에

통계를 추가하기 위해 Redis 를 사용

통계는 위젯 애플리케이션의 페이지에 접근하는 모든 ip 주소들의 집합과 각 리소스가 접근된 횟수라는 두개로 제한

두 개의 분리된 데이터 컬렉션을 한번에 가져오기 위해 redis 트랜잭션을 제어하는 multi 사용

Page 28: Node Js와 Redis를 사용한 구조화된 데이터

Express 애플리케이션에 Stats 미들웨어 추가 1. Redis 데이터 베이스에 접근 정보를

기록하기 위한 새로운 미들웨어 추가 Ip 주소를 추가▪ Client.sadd(‘ip’, req.socket.remoteAddress);

리소스 카운트 증가▪ Client.hincrby(‘myurls’, req.url, 1);

Page 29: Node Js와 Redis를 사용한 구조화된 데이터

Express 애플리케이션에 Stats 미들웨어 추가 2. routes/index.js

통계 애플리케이션에서 새로운 컨트롤러 코드를 가진 라우팅 색인 파일 통계 인터페이스는 최상위 도메인에서 접근되므로 routes 폴더에 추가 .

Express 4에서 에러나는 부분들… . 좀 더 찾아봐야… app.use(express.favicon()); app.use(express.logger('dev'));

app.use(express.staticCache({maxObjects: 100, maxLength: 512}));

app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.directory(__dirname + '/public')); app.use(function(req, res, next){ throw new Error(req.url + ' not

found'); }); app.use(function(err, req, res, next) { console.log(err); res.send(err.message); });

Page 30: Node Js와 Redis를 사용한 구조화된 데이터

감사합니다