sgcWebSockets Clustering — Scale WebSocket Servers Across Multiple Nodes | eSeGeCe Blog

sgcWebSockets Clustering — Scale WebSocket Servers Across Multiple Nodes

· Components
sgcWebSockets Clustering — Scale WebSocket Servers Across Multiple Nodes

A WebSocket server running on a single process is easy. The moment you put two or more server instances behind a load balancer, something breaks quietly: each client connects to exactly one node, so a message published on node A never reaches the subscribers sitting on node B. Channels, broadcasts and Presence all go half-blind. This is the single most common reason teams outgrow a WebSocket library and migrate elsewhere.

The new TsgcWSCluster component closes that gap. Drop it next to your server, point the nodes at each other, and a publish or Presence event on any node reaches subscribers connected to every node, with your existing Publish / channel / Presence code unchanged. This post walks through the two backplane engines, the configuration, and ready-to-paste Delphi and .NET examples.

Two backplane engines

Clustering works through a backplane every node connects to. When a client publishes on a node, that node delivers the message to its own local subscribers and forwards it to the backplane; every other node receives it and fans it out to its local subscribers. Loops are prevented by tagging each message with the origin node id.

You pick the backplane with the EngineType property:

Mesh backplane (zero infrastructure)

The mesh engine is the quickest way to cluster. Give each node a ClusterPort to listen on and the host:port of its peers, then Attach the sgc protocol so its channel pub/sub (and Presence) is clustered:

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;

That is the whole change. A client connected to this node can Publish to a channel and clients on the other two nodes receive it, exactly as if they were all on one server. No sticky sessions required.

Redis backplane

For larger deployments, switch the engine to clusterRedis and point it at your Redis server. Everything above the backplane — channels, Presence, your application code — stays the same:

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

The managed sgcWebSockets edition exposes the same component. Attach the cluster to the server's sgc protocol and start it — a publish on one node reaches subscribers on the others:

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;

In this release the .NET edition ships the mesh engine; the Redis backplane is available on the Delphi / C++Builder edition.

Cluster-wide Presence

Presence — "who is online in this channel" — is the feature that suffers most when a server scales out, because each node only sees its own members. TsgcWSCluster fixes that: Attach the Presence protocol the same way you attach the sgc protocol, and the member roster becomes the union across all nodes. Join / leave events propagate cluster-wide, and a node that goes down has its members purged automatically so you never show ghost members.

oCluster.Attach(oPresenceProtocol);   // TsgcWSPServer_Presence
// GetMembers now returns the cluster-wide roster, not just this node's.

Knowing when the cluster is ready

Each cluster exposes its connectivity so you can wait for the backplane before you start publishing, or surface node health in a dashboard:

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

On .NET the same signals are OnPeerConnected / OnPeerDisconnected, the ConnectedPeerCount property and IsReady.

How it composes with the rest of the library

Clustering sits below your protocol code, so nothing else changes. The same Publish, channel subscriptions, QoS acknowledgements and Presence APIs you already use keep working, now across every node. The mesh engine needs no external service, which makes a two or three node deployment trivial; Redis is there for when you scale bigger. A two-node demo ships with the library (02.WebSocket_Protocols\14.MultiNode_Clustering on Delphi, samples\ClusterDemo on .NET) so you can watch a message cross nodes on your own machine.

Availability

Multi-node clustering is an Enterprise edition feature and compiles across Delphi 7 through 13 (Win32/Win64, Linux64, macOS, Android and iOS) and on the managed .NET edition.

Customers with an active subscription can download the new build from the customer area. Trial users can grab the updated installer at esegece.com/products/websockets/download.

Questions, feedback or help wiring this into your deployment? Get in touch — you will get a reply from the people who wrote the code.