Skip to content

Redis Pub&Sub를 이용한 Scale Out

hyelie edited this page Oct 28, 2022 · 6 revisions

읽기 전에

Redis Pub/Sub 구조에 대해 이해하고 있어야 합니다. Redis 공식 문서, Socket.IO

Pub/Sub 구조는 비동기 메시징 패러다임으로써, Publisher가 메시지를 송신할 때 특정 수신자를 타겟으로 하지 않습니다. 대신, Publisher를 구독한 Subscript에게만 전달됩니다.


Scale out의 필요성

Node.js는 비동기 처리로 많은 사용량을 처리할 수 있지만 사용자가 늘어나면 결국 부하를 분산시켜야만 합니다. 미어캣은 Node.js로 구현되었기 때문에 부하분산을 위해서는 Node가 지원하는 Cluster 기능을 이용해 여러 개의 Worker를 만들어 서버를 실행해야 합니다.

그러나 socket.io는 동일한 Worker가 아닌 경우 같은 room에 있더라도 데이터 통신이 불가능합니다. 각 Worker들은 단절되어 있기 때문입니다. 이를 해결하기 위해 Redis의 Pub/Sub 구조를 이용합니다.


Redis Pub/Sub 구조를 이용한 Scale out

Socket.IO는 Pub/Sub 구조를 구현하기 위해 Redis adapter를 사용합니다. 이를 이용할 경우 broadcast나 io.to().emit() 또는 socket.broadcast.emit()와 같이 여러 클라이언트에게 메시지를 전송할 때 유용합니다.

먼저 어떤 클라이언트가 서버에 접속할 경우, load balancer가 적당한 Worker를 할당해 줍니다. 클라이언트는 할당받은 Worker에 있는 socket에 접속됩니다.

이 상태에서 클라이언트가 socket 이벤트를 emit하면 접속되어 있는 Worker가 Redis Channel로 이벤트 발생 여부를 알립니다. Redis Channel은 모든 Worker에 붙어 있는 Redis adapter에게 이벤트 발생 여부를 알려주고, 이벤트를 수신받은 각 Worker의 socket.io가 해당하는 클라이언트에게 이벤트를 전송합니다.

이 상태에서 메시지를 발송했을 때 프로토콜을 아래 그림을 예시로 들어 설명하겠습니다.


load balancer가 사용자 A가 2번 Worker에 할당되었다고 가정하겠습니다.

  1. 사용자 A가 어떤 room에서 메시지를 전송하면 Redis Channel로 이벤트 발생 여부가 날아갑니다.
  2. Redis Channel에서는 모든 Cluster의 Worker에게 해당 이벤트를 전송합니다.
  3. 각 Worker은 자신의 socket에 해당 room이 있는지 봅니다. 있으면 이벤트를 전송하고, 없다면 전송하지 않습니다.