단일 프로세스에서 실행되는 WebSocket 서버는 간단합니다. 하지만 두 개 이상의 서버 인스턴스를 로드 밸런서 뒤에 두는 순간, 조용히 무언가가 깨집니다. 각 클라이언트는 정확히 하나의 노드에만 연결되므로, 노드 A에서 publish된 메시지는 노드 B에 있는 구독자에게 결코 도달하지 못합니다. 채널, 브로드캐스트, Presence 모두 절반은 눈이 먼 상태가 됩니다. 이것이 팀이 WebSocket 라이브러리의 한계에 부딪혀 다른 곳으로 이전하게 되는 가장 흔한 이유입니다.
새로운 TsgcWSCluster 컴포넌트가 그 격차를 메웁니다. 서버 옆에 배치하고 노드들이 서로를 가리키도록 설정하기만 하면, 어떤 노드에서 발생한 publish 또는 Presence 이벤트라도 모든 노드에 연결된 구독자에게 도달하며, 기존의 Publish / 채널 / Presence 코드는 변경할 필요가 없습니다. 이 글에서는 두 가지 백플레인 엔진, 설정 방법, 그리고 바로 붙여넣을 수 있는 Delphi 및 .NET 예제를 살펴봅니다.
두 가지 백플레인 엔진
클러스터링은 모든 노드가 연결되는 백플레인을 통해 작동합니다. 클라이언트가 한 노드에서 publish하면, 그 노드는 메시지를 자신의 로컬 구독자에게 전달하고 백플레인으로 전달합니다. 다른 모든 노드가 이를 받아 자신의 로컬 구독자에게 퍼뜨립니다. 각 메시지에 출발 노드 id를 태그함으로써 루프를 방지합니다.
EngineType 속성으로 백플레인을 선택합니다:
- Mesh (
clusterMesh) — 외부 인프라가 전혀 필요 없습니다. 각 노드는 클러스터 포트에서 수신 대기하며 피어에 직접 연결합니다. 추가로 설치할 것 없이 "그냥 작동"해야 하는 소규모 클러스터에 적합합니다. - Redis (
clusterRedis) — 더 큰 규모의 배포를 위해 이미 운영 중인 Redis 서버를 Pub/Sub 백플레인으로 사용합니다.
Mesh 백플레인 (인프라 불필요)
mesh 엔진은 클러스터를 구성하는 가장 빠른 방법입니다. 각 노드에 수신 대기할 ClusterPort와 피어의 host:port를 지정한 다음, sgc 프로토콜을 Attach하여 해당 채널 pub/sub(및 Presence)를 클러스터링합니다:
uses
sgcWebSocket, sgcWebSocket_Protocols, sgcWebSocket_Cluster;
var
oServer: TsgcWebSocketServer;
oProtocol: TsgcWSPServer_sgc;
oCluster: TsgcWSCluster;
begin
oServer := TsgcWebSocketServer.Create(nil);
oServer.Port := 8080;
oProtocol := TsgcWSPServer_sgc.Create(nil);
oProtocol.Server := oServer;
oCluster := TsgcWSCluster.Create(nil);
oCluster.EngineType := clusterMesh; // zero-infrastructure backplane
oCluster.ClusterPort := 5410; // this node's mesh listener
oCluster.Peers.Add('192.168.1.101:5410'); // the other nodes
oCluster.Peers.Add('192.168.1.102:5410');
oCluster.Attach(oProtocol); // cluster this protocol's pub/sub
oCluster.Start;
oServer.Active := True;
end;
이것이 변경 사항의 전부입니다. 이 노드에 연결된 클라이언트가 채널에 Publish하면 다른 두 노드의 클라이언트가 마치 모두 하나의 서버에 있는 것처럼 그대로 메시지를 받습니다. 스티키 세션은 필요하지 않습니다.
Redis 백플레인
더 큰 규모의 배포에서는 엔진을 clusterRedis로 전환하고 Redis 서버를 가리키도록 설정합니다. 백플레인 위의 모든 것 — 채널, Presence, 애플리케이션 코드 — 은 그대로 유지됩니다:
oCluster.EngineType := clusterRedis;
oCluster.RedisHost := '127.0.0.1';
oCluster.RedisPort := 6379;
oCluster.RedisPassword := ''; // optional
oCluster.RedisChannel := 'sgccluster'; // the Pub/Sub channel
oCluster.Attach(oProtocol);
oCluster.Start;
.NET
관리되는(managed) sgcWebSockets 에디션도 동일한 컴포넌트를 제공합니다. 클러스터를 서버의 sgc 프로토콜에 attach하고 시작하면 — 한 노드의 publish가 다른 노드들의 구독자에게 도달합니다:
var server = new TsgcWSServer { Port = 8080 };
var protocol = new TsgcWSPServer_sgc { Server = server };
var cluster = new TsgcWSCluster {
EngineType = ClusterEngineType.Mesh, // zero-infrastructure backplane
ClusterPort = 5414,
Protocol = protocol
};
cluster.Peers.Add("192.168.1.101:5414");
cluster.Peers.Add("192.168.1.102:5414");
cluster.Start();
server.Active = true;
이번 릴리스에서 .NET 에디션은 mesh 엔진을 제공하며, Redis 백플레인은 Delphi / C++Builder 에디션에서 사용할 수 있습니다.
클러스터 전체 Presence
Presence — "이 채널에 누가 온라인인가" — 는 서버가 확장될 때 가장 큰 영향을 받는 기능입니다. 각 노드가 자신의 멤버만 볼 수 있기 때문입니다. TsgcWSCluster가 이를 해결합니다. sgc 프로토콜을 attach하는 것과 동일한 방식으로 Presence 프로토콜을 Attach하면, 멤버 명단이 모든 노드에 걸친 합집합이 됩니다. 입장 / 퇴장 이벤트가 클러스터 전체로 전파되며, 다운된 노드의 멤버는 자동으로 제거되므로 유령 멤버가 표시되는 일이 없습니다.
oCluster.Attach(oPresenceProtocol); // TsgcWSPServer_Presence
// GetMembers now returns the cluster-wide roster, not just this node's.
클러스터가 준비되었는지 알기
각 클러스터는 연결 상태를 노출하므로, publish를 시작하기 전에 백플레인을 기다리거나 노드 상태를 대시보드에 표시할 수 있습니다:
oCluster.OnPeerConnected := procedure(Sender: TObject; const aPeer: string)
begin
// a peer link came up
end;
if oCluster.Ready then // at least one peer connected (or no peers configured)
// ConnectedPeerCount tells you how many links are up
.NET에서는 동일한 신호가 OnPeerConnected / OnPeerDisconnected, ConnectedPeerCount 속성, 그리고 IsReady입니다.
라이브러리의 나머지 부분과의 결합 방식
클러스터링은 프로토콜 코드 아래에 위치하므로 다른 것은 아무것도 바뀌지 않습니다. 이미 사용 중인 동일한 Publish, 채널 구독, QoS 확인 응답, Presence API가 이제 모든 노드에 걸쳐 그대로 작동합니다. mesh 엔진은 외부 서비스가 필요 없어 두세 개 노드 배포가 매우 간단하며, Redis는 더 크게 확장할 때를 위한 것입니다. 두 노드 데모가 라이브러리에 포함되어 있어(Delphi는 02.WebSocket_Protocols\14.MultiNode_Clustering, .NET은 samples\ClusterDemo) 자신의 머신에서 메시지가 노드를 넘나드는 것을 직접 확인할 수 있습니다.
제공 범위
멀티 노드 클러스터링은 Enterprise 에디션 기능이며, Delphi 7부터 13까지(Win32/Win64, Linux64, macOS, Android 및 iOS)와 관리되는 .NET 에디션에서 컴파일됩니다.
활성 구독을 보유한 고객은 고객 영역에서 새 빌드를 다운로드할 수 있습니다. 평가판 사용자는 esegece.com/products/websockets/download에서 업데이트된 설치 프로그램을 받을 수 있습니다.
질문, 피드백이 있거나 배포 환경에 이를 연동하는 데 도움이 필요하신가요? 문의하기 — 코드를 작성한 사람들로부터 직접 답변을 받으실 수 있습니다.
