Socket.io 클러스터 환경에서 사용하기
socket.io 서버를 클러스터로 구성했을 때 가장 큰 문제는 각 노드에 어떤 클라이언트들이 커넥션을 맺었는지 서로 모르는 상태이기 때문에 메세지 전달이 제대로 이루어지지 않는다. redis pub/sub 기능을 이용해서 커넥션을 공유하는 방법을 알아보자.
Socket.io-redis 설정
const express = require('express');
const app = express();
const redis = require('redis');
const socketIoRedisAdapter = require('socket.io-redis');
const config = require('../conf');
const { redis: redisConfig } = config;
// Create HTTP Server
const server = require('http').createServer(app);
// Initialize SocketIO
const io = require('socket.io')(server, {
path: '/socket.io',
transports: ['websocket'],
});
// SocketIO - Redis configuration
if (redisConfig.enable) {
const { host, port, password } = redisConfig;
if (host && port > 0) {
const pubClient = redis.createClient({ host, port, password });
const subClient = redis.createClient({ host, port, password });
const redisAdapter = socketIoRedisAdapter({ pubClient, subClient });
io.adapter(redisAdapter);
redisAdapter.pubClient.on('connect', () => {
console.log('Redis adapter pubClient connected');
});
redisAdapter.subClient.on('connect', () => {
console.log('Redis adapter subClient connected');
});
}
}
// Listen
server.listen(8080, () => {
console.log(`listen ${8080}`);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
socket.io 서버에 redis pub/sub client를 설정했다. 이제 어떤 이벤트가 일어나면 redis를 통해 다른 노드로 이벤트가 전파된다.
Redis로 직접 메세지를 보내 Socket으로 전파하기
Socket.io 컨텍스트 바깥에서 메세지를 emit 해야 할 때 유용하게 쓸 수 있는 방법이다.
const io = require('socket.io-emitter')({ host: '127.0.0.1', port: 6379 });
io.emit('my-event', 'hello, world');
1
2
3
2
3
socket.io-emitter 패키지를 설치한다음, option 파라미터로 redis 커넥션 정보를 설정한 뒤, io 객체를 통해 redis pub/sub 채널에 연결된 모든 노드에 이벤트를 보낼 수 있다.
const io = require('socket.io-emitter')({ host: '127.0.0.1', port: 6379 });
// sending to all clients
io.emit('broadcast', /* ... */);
// sending to all clients in 'game' room
io.to('game').emit('new-game', /* ... */);
// sending to individual socketid (private message)
io.to(<socketid>).emit('private', /* ... */);
var nsp = io.of('/admin');
// sending to all clients in 'admin' namespace
nsp.emit('namespace', /* ... */);
// sending to all clients in 'admin' namespace and in 'notifications' room
nsp.to('notifications').emit('namespace', /* ... */);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
io 객체에서 지원하는 namespace, room을 세분화하여 이벤트를 보내는 것도 가능하다.