1 2 3 4 5 6 L

Page Header > Subtitle

[Node.js] clustering node + socket.io + redis 사용법

nodejs는 싱글 쓰레드 기반으로 동작한다.

싱글 쓰레드 기반의 한계점을 극복 하기 위해 node자체적으로 clustering을 지원을 한다

 

사용법은 간단하다

 

var http = require('http');

var cluster = require('cluster');

//멀티 코어 클러스터

if (cluster.isMaster) {

    // 클러스터 워커 cpu 갯수 만큼 프로세스  포크 한다

    for (var i = 0; i < numCPUs; i++) {

        cluster.fork();

    }

    //프로세스가 죽게 되면 받는 이벤트

    cluster.on('exit', function(worker, code, signal) {

        console.log('worker ' + worker.process.pid + ' died');

    });

} else {

//작업 시작

 

}

간단한 구분 으로 cluster를 사용할 수 있다

 

하지만 cluster 환경에서 node js 모듈인 socket io는 정상 작동하지 않는다 

이유는 cpu갯수 만큼 할당된 프로세스들은 소켓 정보를 공유 하지 못하기 때문에 

적상적으로 작동 될 수 없다.

이런 부분을 해소 하기위해서 redis서버와 redis 모듈을 설치 한 후 socket 정보들을

redis에서 공유 할 수 있도록 해주면 cluster 환경에서도 적상적인 socket io를

사용 할 수 있다

-----------------------------------------------소스

var http = require('http');

var cluster = require('cluster');

var numCPUs = require('os').cpus().length;

var cluster = require('cluster');

var httpServer;

 

if (cluster.isMaster) {

    // 클러스터 워커 프로세스 포크

    for (var i = 0; i < numCPUs; i++) {

        cluster.fork();

    }

 

    cluster.on('exit', function(worker, code, signal) {

        console.log('worker ' + worker.process.pid + ' died');

    });

} else {

httpServer = http.createServer(function(req, res) {

}).listen(1337);

 

var io = require('socket.io').listen(httpServer);

var redis = require('socket.io-redis');                     //npm install  socket.io-redis

io.adapter(redis({ host: 'localhost', port: 6379 }));     

console.log('Server running at http://localhost:1337/');

io.sockets.on('connection', function(socket) {

});

}

이렇게 소스만 추가 하면 

Error: Redis connection to localhost:6379 failed - connect ECONNREFUSED 127.0.0.

1:6379

    at Object.exports._errnoException (util.js:890:11)

    at exports._exceptionWithHostPort (util.js:913:20)

    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1059:14)

이런 에러를 볼 수 있다

 

redis 서버를 띄워야 한다

http://github.com/dmajkic/redis/downloads   //redis 설치 파일 경로

binary 형태로 exe 파일 실행시 바로 서버를 띄울 수 있다

 

[9044] 14 Apr 21:55:39 # Warning: no config file specified, using the default co

nfig. In order to specify a config file use 'redis-server /path/to/redis.conf'

[9044] 14 Apr 21:55:39 * Server started, Redis version 2.4.5

[9044] 14 Apr 21:55:39 # Open data file dump.rdb: No such file or directory

[9044] 14 Apr 21:55:39 * The server is now ready to accept connections on port 6

379

[9044] 14 Apr 21:55:39 - 0 clients connected (0 slaves), 1179896 bytes in use

[9044] 14 Apr 21:55:41 - Accepted 127.0.0.1:52918

 

redis 서버를 띄우면 자동으로 127.0.0.1 6379포트로 서버가 실행이 된다 

redis 정상 실행 후 노드를 다시 실행 하면 정상 동작하는 걸 확인 할 수 있다.

 

=======================================================================================================

 

node.js 노드가 하나가 아니라 여러개의 프로세스를 이용해서 운영할 때,socket.io를 어떻게 사용해야 할까? 이런 멀티 프로세스를 지원하기 위해서, 

node.js는 내부적으로 redis store를 지원한다. redis에는 publish/subscribe라는 기능이 있는데, 마치 메세지 큐처럼 메세지를 subscriber로 보낼 수 있는 기능이다.

 

아래 그림을 보자,하나의 node프로세스에서 메세지를 보내면, 다른 프로세스로 redis를 통해서 메세지를 전달한다. 

이때 메세지를 보내는 프로세스는 redis에 메세지를 “publish”하고 나머지 프로세스들은  “subscribe”를 이용하여 메세지를 읽어드린다. 이때, 메세지를 전달하는 채널은 “dispatch”라는 이름의 채널을 이용한다.

 

bcd1380a5b9ba93a52c94ecb1772d008.png
 

 

그러면 실제로, socket.io에서 redis store를 사용하려면 어떻게 해야 할까? 간단한 설정만으로 가능하다. 아래와 같이 redis client를 생성한 후에, socket.io에 set 명령을 이용하여 store를 redis client로만 지정해주면 된다.

 

var httpServer =http.createServer(app).listen(process.argv[2], function(req,res){
    console.log('Socket IO server has been started listen:'+process.argv[2]);
});
// upgrade http server to socket.io server
var io = socketio.listen(httpServer);
var pub = redis.createClient(6379,'127.0.0.1');
var sub = redis.createClient(6379,'127.0.0.1');
var store = redis.createClient(6379,'127.0.0.1');
 
io.set('store',new socketio.RedisStore({
    redis: redis
    ,redisPub : pub
    ,redisSub : sub
    ,redisClient : store
}));

그리고, cluster 모듈을 이용하거나, 앞단에 nginx(http:// http://nginx.org/ ) haproxy (http://haproxy.1wt.eu/)  로드밸런서를 이용하여

여러개의 node.js 프로세스에 대한 end point를 하나로 묶으면, 대규모 분산 서비스를 할 수 있는 socket.io 클러스터를 구성할 수 있다.

 

=========================================================================================================

 

Node.js 노드가 하나가 아니라 여러개의 프로세스를 이용해서 운영할 때,

Socket.io를 어떻게 사용해야 할까? 이런 멀티 프로세스를 지원하기 위해서

Node.js는 내부적으로 RedisStore를 지원한다. 

Redis에는 Publish/Subscribe라는 기능이 있는데, 

마치 메시지 큐처럼 메시지를 subscriber로 보낼 수 있는 기능이다.

아래 그림을 보자, 하나의 node 프로세스에서 메시지를 보내면,

다른 프로세스로 Redis를 통해서 메시지를 전달한다. 이때 메시지를 보내는 프로세스는

Redis에게 메시지를 "Publish"하고 나머지 프로세스들은 "Subscribe"를 이용하여

메시지를 읽어드린다.

이때, 메시지를 전달하는 채널은 "dispatch"라는 이름의 채널을 이용한다. 

 

777ed4e7d209335d9db27e1fcc585896.png
 

npm install socket.io

npm install socket.io-redis 

 

var redisInfo = {
    host: '127.0.0.1',
    port: 6379
};
var app = require('http').createServer(handler);
var fs = require('fs');
var io = require('socket.io').listen(app);
var redis = require('socket.io-redis');
 
 
if (process.argv.length < 3){
    console.log('ex) node app <port>');
    process.exit(1);
}
app.listen(process.argv[2]);
console.log(process.argv[2] +' Server Started!! ')
 
function handler(req, res) {
    fs.readFile(__dirname + '/index.html',
        function (err, data) {
            if (err) {
                res.writeHead(500);
                return res.end('Error loading index.html');
            }
            res.writeHead(200);
            data = data.toString('utf-8').replace('<%=host%>', req.headers.host);
            res.end(data);
        });
}
io.adapter(redis({host:'localhost',port:6379}));
 
io.sockets.on('connection', function (socket) {
    socket.on('message', function(data){
        socket.broadcast.emit('message', data);
    });
});​ 

 

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>socket io redis store</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <script>
        var socket = io.connect('http://<%=host%>');
        $(document).ready(function(){
            socket.on('message',function(data){
                $('#chat').append('<li>'+data.message+'</li>');
            });
 
            $('#btnSend').click(function(){
                send();
            });
            $('#inputText').keyup(function(e){
                if(e.keyCode == 13)
                    send();
            });
        });
        function send() {
            var message = $('#inputText').val();
            if (message.length < 1) return;
            socket.emit('message',{message:message});
            $('#chat').append('<li>'+message+'</li>');
            $('#inputText').val('');
        }
    </script>
</head>
<body>
    socketio redis store...<br/>
    <input type="text" id="inputText" />
    <button id="btnSend">보내기</button>
    <ul id="chat"></ul>
</body>
</html>
 

 

위와 같이 코드를 구성한 후

node app.js 7000
node app.js 7001
node app.js 7002
이렇게 서버를 3개를 구동 시킨다.
이후 브라우저에서 
localhost:7000
localhost:7001
localhost:7002

로 각각 접속하면 3개의 서버가 같은 방에 있는 거처럼 채팅할 수 있다. 

 

87aa1b7c61b9fe964a85b9a071d311d5.png
 

그리고 cluster 모듈을 이용하거나 앞단에 nginx, haproxy 로드 밸런서를 이용하여 여러개의 node.js 프로세스에 대한 endpoint를 하나로 묶으면, 대규모 분산 서비스를 할수 있는 socket.io 클러스터를 구성할 수 있다.

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기
captcha
자동등록방지 숫자입력

JS/Node.js

번호 제목 글쓴이 날짜 조회수
39 javascript [javascript] async, await를 사용하여 비동기 javascript를 동기식으로 만들자 미도어묵 02-18 1,022
38 javascript JavaScript 합집합, 교집합, 차집합, 대칭차 미도어묵 11-23 1,270
37 javascript jQuery 플러그인 부트스트랩의 콤포넌트(modal) 미도어묵 10-04 1,132
36 javascript Javascript 숫자에 천단위로 콤마(,) 찍기 미도어묵 08-20 791
35 javascript 함수형 프로그래밍 - 함수형으로 전환 미도어묵 08-09 856
34 Node.js nodejs & api call example 미도어묵 06-25 814
33 javascript jQuery 핸드폰 번호 체크하기 미도어묵 06-25 843
32 Node.js Node.js 업그레이드 미도어묵 04-23 761
31 Node.js node.js cross 도메인 header 처리 미도어묵 03-12 803
30 javascript hls.js 및 데모 미도어묵 02-22 795
29 Node.js node.js memcached_guide 미도어묵 01-02 799
28 Node.js clustering node + socket.io + redis 사용법 미도어묵 09-29 1,597
27 javascript script sample 예제 관리자 09-20 818
26 Node.js 커넥션 연결 확인 관리자 09-01 754
25 javascript [문법] [TypeScript] Electron + Vue.js 예제 관리자 07-24 1,082
24 javascript 웹 풀스택 입문을 위한 약 500페이지 분량의 교재 관리자 07-11 903
23 javascript [TypeScript] 타입스크립트 기초 세미나 자료 관리자 06-10 876
22 javascript javascript 함수 지향 관리자 04-08 787
21 Node.js Node.js 로 웹 사이트 데이터 가져오기 관리자 04-06 826
20 Node.js [MongoDB] Application / Mongoose를 이용하여 간단한 채팅 프로그램 개발 관리자 03-30 877