Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

12,013 views

Published on

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

Published in: Software
  • Login to see the comments

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

  1. 1. 박진호
  2. 2.  Node 및 Redis 시작  게임 순위표 만들기  메시지 큐 만들기  Express 애플리케이션에 Stats 미들웨어 추 가
  3. 3.  메모리 내의 키/ 값 저장소로 유명  Node는 Redis, Memcached,Cassandra 모두 지원
  4. 4.  빠른 액세스를 위해 데이터 쿼리를 메모리 상에 캐시하기 위해 사용  분산 컴퓨팅에도 적합  복잡한 데이터에 대해서는 제한된 지원만을 제공  대량의 쿼리를 처리하는 애플리케이션에는 유용하지만, 데이터를 읽고 쓰는 것이 많은 애플리케이션에서는 유용성이 떨어짐  http://memcached.org/
  5. 5.  MemCached 처럼 클러스터 지원  MemCached와 마찬가지로 지원하는 데이 터 구조가 제한  Redis에 적합하지 않은 임시 쿼리를 처리하 는데 알맞음  http://cassandra.apache.org/
  6. 6.  데이터를 읽고 쓰는 것이 많은 곳에 사용  영속적으로 저장 가능  다양한 유형의 데이터를 지원. (Memcached에 비해 더 많은 유연성 제공)  Cassandra에 비해 빠름.  단일 머신에서만 구동.  Http://redis.io/
  7. 7.  https://github.com/dmajkic/redis/downloads
  8. 8.  데이터베이스를 이용하면 데이터를 영속적으 로 관리할 수 있지만, 입출력에 다소 시간이 걸 리기 때문에 실시간 서비스에서는 더 적합한 저장소를 사용할 필요  Redis는 메모리 기반의 저장소이기 때문에 필 요한 정보를 빠르게 저장하고 가져올 수 있는 실시간 서비스에 적합한 저장소  멤버 id, 플레이어 이름, 게임이름, 마지막 플레 이한 날짜, 점수, 나머지 관련 정보 저장.  https://github.com/dmajkic/redis/downloads
  9. 9.  Redis를 사용하여 구현.  npm install redis  hiredis라는 공식적인 hiredis C 라이브러리를 바인딩하여 Non-Blocking의 빠른 모듈  npm install hiredis redis  Async 설치 (series 기능 사용하기 위함. 호출이 순서대로 호출되고 데이터 역시 순서대로 반환 보장)  npm install async
  10. 10.  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();
  11. 11.  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();
  12. 12.  Redis 해시 속성 설정 Client.hset(“hashid”, “propname”, “propvalue”, function(err, reply) { 오류 혹은 응답에 대해 무엇인가를 수행 } );  성공 확인 응답  Rredis.print ▪ 에러나 응답을 콘솔에 출력 후 반환  Client.hset (“hashid”, “propname”, “propvalue”, redis.print);
  13. 13. 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.remoteAddress + ' ' + 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.score, 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');
  14. 14.  var net = require('net'); var client = new net.Socket(); client.setEncoding('utf8'); // connect toTCP server client.connect ('8124','examples.burningbird.net', function () { console.log('connected to server'); }); // prepare for input from terminal process.stdin.resume(); // when receive data, send to server process.stdin.on('data', function (data) { client.write(data); }); // when receive data back, print to console client.on('data',function(data) { console.log(data); }); // when server closed client.on('close',function() { console.log('connection is closed'); });
  15. 15.  두개의 다른 데이터 저장소가 업데이트 됨.  개별적인 점수 정보(이름, 점수, 날짜를 포 함)은 hash에 저장  Client.hset ( obj.member, “first_name”, obj.first_name, redis.print );  멤버 id 와 점수는 sorted set에 저장  Client.zadd( “Zowie!”, parseInt(obj.score), obj.member );
  16. 16.  Score.jade  Doctype 5  doctype html
  17. 17.  doctype html html(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}
  18. 18.  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; }
  19. 19.  var http = require('http'); var async = require('async'); var redis = require('redis'); var jade = require('jade'); // set up Jade template var layout = require('fs').readFileSync(__dirname + '/score.jade', 'utf8'); var fn = jade.compile(layout, {filename: __dirname + '/score.jade'}); // start Redis client var client = redis.createClient(); // select fifth database client.select(5); // helper function function 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; }
  20. 20.  // create array of callback functions for Async.series call var callFunctions = new Array(); // process results with makeCallbackFunc, push newly returned // callback into array for (var i = 0; i < result.length; i++) { callFunctions.push(makeCallbackFu nc(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 engine var str = fn({scores : result}); res.end(str); }); }); }).listen(3000); console.log('Server running on 3000/');
  21. 21.  메시지 큐  특정한 통신 형식을 입력으로 받아 큐에 저장하 는 애플리케이션  메시지는 메시지 수신자가 가져갈 때 까지 저장 되었다가 해당 시점에 큐에서 뽑혀져서 수신자 에게 전송(한번에 하나씩 혹은 대량))  통신은 비동기로 이루어짐
  22. 22.  메시지 큐를 보여주기 위해 여러 개의 다양한 하위 도메인에 대한 웹 로그 파일에 접근하는 애플리케이 션  메시지 큐 애플리케이션이 수행하는 것은 3000번에 서 메시지를 수신대기하다가 전송된 항목을 Redis 데이터 저장소로 저장  로그 항목을 받은 후 로그 데이터에서 이미지 리소 스(jpg, gif 등)가 접근되었는지를 찾아보는 정규식 검사를 수행. 일치하는 패턴이 발견되면 리소스 URL 을 메시지 큐 애플리케이션에 전송
  23. 23.  Redis 클라이언트를 만들어서 애플리케이션이 종료될 때 까지 지속?  Redis 클라이언트를 만든 후 Redis 명령어를 실행하자 마 자 바로 해제?  영구적이 좋은가? 즉시 해제하는 것이 좋은가?  클라이언트 연결유지가 더 빠를것이라는 예상 맞음. 연결을 유지하는 경우를 테스트 하는 도중 애플리케이션이 잠시 동 안 상당히 느려졌다가 상대적으로 빠른 속도를 회복  Redis 데이터베이스에 대해 대기 중인 요청들이 큐가 해제도 리 때 까지 Node 애플리케이션을 일시적으로 차단시켰기 때 문. 매번 요청할 때마다 연결을 열고 닫는 경우에는 동일한 상 황을 겪지 않았는데, 열고 닫는 과정에 들어가는 추가 오버헤 드가 애플리케이션의 성능을 저하시켜서 동시 사용자 상한선 에 도달하지 않았기 때문
  24. 24.  이전 장들에서 만들어본 위젯 애플리케이션 에 통계를 추가하기 위해 Redis를 사용  통계는 위젯 애플리케이션의 페이지에 접근 하는 모든 ip 주소들의 집합과 각 리소스가 접근된 횟수라는 두개로 제한  두 개의 분리된 데이터 컬렉션을 한번에 가 져오기 위해 redis 트랜잭션을 제어하는 multi 사용
  25. 25.  1. Redis 데이터 베이스에 접근 정보를 기록 하기 위한 새로운 미들웨어 추가  Ip 주소를 추가 ▪ Client.sadd(‘ip’, req.socket.remoteAddress);  리소스 카운트 증가 ▪ Client.hincrby(‘myurls’, req.url, 1);
  26. 26.  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); });
  27. 27. 감사합니다

×