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 (
clusterMesh) — zero external infrastructure. Each node listens on a cluster port and connects directly to its peers. Perfect for small clusters that should "just work" with nothing extra to install. - Redis (
clusterRedis) — uses a Redis server you already run as the Pub/Sub backplane, for larger deployments.
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.
