멀티 서버 환경에서 Socket.io 사용하기
서버 인스턴스가 하나로 이뤄진 환경에서는 클라이언트와 서버간의 소켓 통신은 그림 1 처럼 하나의 서버에서 모든 소켓 세션을 관리하는 형태로 구현된다. Server1 이 클라이언트와 연결된 모든 소켓 세션을 갖고 있기 때문에 모든 클라이언트에게 Event를 전달할 수 있다.
그런데 그림 1에서 서버를 하나 늘리면 클라이언트와 서버간의 소켓 통신은 그림 2처럼 된다. 클라이언트는 최초에 접속한 서버에 대해서 소켓 세션을 유지하게 되므로 Server1와 Server2 모두 별도의 소켓 세션을 갖게 된다.
그림 2와 같은 형태에서 Server1 에서 모든 클라이언트에게 직접 이벤트를 보내는 것은 불가능하다. 그림 3에서도 알 수 있듯이 Server1과 Client 2 간의 소켓 연결 세션이 없으므로 Server1이 Client 2에게 메시지를 보내려면 일반 소켓 통신으로는 불가능하고 Server2에 요청을 보내 우회하는 방법만 가능하다. 그런데 이런 방식은 서버의 개수가 늘어날 수록 유지 관리가 어려워진다.
그래서 Socket.io 에서는 멀티 서버 환경에서 소켓 통신을 가능하게 하고자 Adapter 라는 것을 뒀다. Adapter는 서버 쪽에 있는 컴포넌트로 모든 클라이언트나 일부 클라이언트에게 메시지를 보내는 역할을 한다. 따로 Adapter를 선언 하지 않으면 In Memory Adapter를 사용하나 이처럼 멀티 프로세서 환경에서 클라이언트 소켓 세션을 관리하기 위해선 별도의 Custom Adapter를 사용해야 한다. Custom Adapter로는 DB 별로 Redis, MongoDB, Postgres 가 있는데 나는 이미 Redis 환경을 구축해둔 상황이라 Redis Adapter를 사용했다.
그림 4는 Redis Adapter를 사용한 서버 아키텍처를 나타낸 것이다. Redis Adapter를 이용하면 Redis에게 이벤트 정보를 구독하고 이벤트를 전달 받으면 이를 서버와 연결된 클라이언트 소켓에 전달하게 된다. Redis가 Publisher고 Server1,2 에 위치한 Redis Adapter가 구독자라고 볼 수 있다. 이벤트를 Broadcast 하는 역할을 Redis에서 전담하기 때문에 서버의 개수가 늘어나도 서버에 Redis Adapter만 연결해주면 되기 때문에 확장성이 용이하다. Redis Adapter는 Redis 의 Pub/Sub 메카니즘에 기반해서 만들어졌다고 한다.
그림 4의 Emitter는 Redis Adapter에게 새로운 이벤트를 추가하는 역할을 하는 컴포넌트다. 보기 쉽게 만들기 위해 따로 빼둔거고 Server 1, Server2에 있어도 문제는 없다.
설치 방법은 아래 링크를 참조하자.