본문 바로가기

web

[node][socket.io][redis] cluster사용시 socket.io와 redis

node에는 cluster라는 것이 있습니다. node는 sigle thread이지만, cluster를 사용하여, 다수의 프로세스에서 서버를 동작시킬 수 있습니다.

하지만 cluster간에는 데이터의 공유가 불가능 합니다. 이렇게 분리된 cluster환경에서 socket.io 을 이용한 프로그래밍을 하다보면, cluster끼리 socket.io 객체를 공유해야 하는 상황이 발생할 수 있습니다. socket.io에서는 redis를 이용한 store를 제공합니다.


이에대해서 (조대협님의 블로그)에서 자세히 다루었지만, socket.io 최신버전에서는 링크된 블로그에서 사용하는 io.set을 통해 redis설정을 할 수 없습니다. 

본 글에서는 최신버전에서 적용방법을 다루었습니다. (1.4.8 버전기준)



redis를 적용하지 않은 상태에서, io.emit과 같이 모든 클라이언트에 메시지를 전송할 경우, 실제로 모든 클라이언트로 전송되는 것이 아닌

해당 프로세스에 접속한 클라이언트에만 전송이 되게 됩니다.

이러한 문제를 해결하기 위해 redis스토어를 사용하게 되면, 모든 프로세스의 클라이언트에게 메시지를 보내게 됩니다.


socket.io에서 제공하는 방법들 입니다.

http://socket.io/docs/using-multiple-nodes/

위의 방법들중, 가장마지막 방법인 redis를 사용한 방법을 다룹니다.


redis를 스토어로 사용하기 위해서는 우선 redis가 필요합니다.

window에서 redis설치 (hwigyeom님의 블로그)


그후, npm모듈 socket.io-redis를 인스톨해야 합니다.

socket.io-redis(npmjs)


이제 준비가 되었습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var express = require('express'),
  cluster = require('cluster'),
  redis = require('socket.io-redis');
 
if (cluster.isMaster) {
  var cpus = require('os').cpus().length;
  for (var i = 0; i < cpus; i++) {
    cluster.fork();
  }
else {
  var app = express(),
  server = require('http').createServer(app),
  io = require('socket.io').listen(server);
 
  io.adapter(redis({
    host: 'localhost',
    port: 6379
  }));
}
cs


위와같이 adapter를 통해 간단하게 redis를 적용할 수 있습니다.


실제로 프로젝트에 적용한 결과는 아래와 같습니다.


1
2
//server
io.emit("allEmit""io emit test = "+process.pid);
cs


서버에서 소켓 접속시마다, 현재 접속해있는 프로세스의 ID를 모든 클라이언트에 보내도록 하였습니다.



1
2
3
4
//client
socket.on("allEmit",(data) => {
  console.log(data);
})
cs

클라이언트에서 프로스세스의 ID를 받으면 출력하게끔 하였습니다.



위는 콘솔 출력 결과입니다. 다야한 프로세스의 ID를 출력 하시는 모습을 보실 수 있습니다.



위는 redis를 적용한 코드를 주석처리 한 뒤의 콘솔 출력 결과입니다. 아까와는 다르게 1개의 프로세스 ID가 출력되는 모습을 보실 수 있습니다.


지금까지 cluster환경에서 socket.io와 redis적용 방법에 대해 알아보았습니다.