Scale Out 가능한 Socket.io 서버 구축하기

이번에 신규 서비스를 런칭하면서 webPush를 이용한 알림 시스템을 구축했으나, Ios에서 webPush를 지원을 하지 않는다는 문제로 Socket.io를 이용하여 실시간 알림 시스템을 구축을 하면서 제일 고민한 Scale Out에 대한 부분이다.

Socket.io

기본적으로 Socket.io는 클라이언트에서 직접적으로 커넥션을 연결해주고, 그 연결된 커넥션으로 서버에서 메세지를 받고 보내는 동작을 한다.

문제는 서버를 구축시 대부분의 이벤트가 하나의 클라이언트가 다른 모든 클라이언트에게 메세지를 보내는 브로드캐스팅이 대부분이라는 것이다. 만약 서버가 여러대 일경우 모든클라이언트에게 전달이 되는것이 아닌 같은 서버와 커넥션이 연결된 클라이언트에게만 이벤트가 전달되고 다른서버와 연결된 클라이언트에게는 전달이 되지 않는 문제가 생긴다.

해결 방안

이 문제를 해결하기 위해서는 이벤트가 발생시 이 이벤트를 다른 서버에 전파를 해줘야하는데 이 부분에서 가장 간단하면서 빠른 방법은 redis를 이용하여 Socket서버간 Pub/Sub해주는 게 좋아 보였다.

이와 관련된 redis를 찾아보니, socket.io-redis 라는 라이브러리가 있어서 사용을 하니 매우 간단하게 redis를 이용하여 Socket 서버간 전파가 가능했다.

참고 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as http from 'http';
import socket from 'socket.io';
import socketRedis from 'socket.io-redis';
import express from 'express';
const app=express();

const server: http.Server = new http.Server(app);
server.listen(3000||`environment.port`);

const socket = socket(server);

const redisAdapter = socketRedis({ host: `environment.redis.uri`, port: `environment.redis.port` });

socket.adapter(redisAdapter);
socket
.of('/')
.adapter
.on('error', error =>
logger.error('socket Redis Error ', { error }),
);

간단한 코드로, 위 부분만 되면 Scale-out에 대비된 Socket 서버 구축이 완료된다.

참고 사항

구현시 참고할 사항들은 배달의민족 포스트 에 잘 소개 되어있으며, AWS ELB를 이용하는 경우 대상 그룹 설정에서 Stickiness 을 체크해주고 Stickiness duration을 넉넉하게 정해줘야 한다. 만약 이부분이 제대로 되지 않으면, 클라이언트쪽에서 연결이 계속 끊어지는 문제가 발생한다

2019-2024 sungmun