sgcWebSockets Clustering — WebSocket-Server über mehrere Knoten skalieren | eSeGeCe Blog

sgcWebSockets Clustering — WebSocket-Server über mehrere Knoten skalieren

· Komponenten

Ein WebSocket-Server, der in einem einzigen Prozess läuft, ist einfach. Sobald Sie jedoch zwei oder mehr Server-Instanzen hinter einen Load Balancer stellen, bricht still und leise etwas zusammen: Jeder Client verbindet sich mit genau einem Knoten, sodass eine auf Knoten A veröffentlichte Nachricht die Abonnenten auf Knoten B nie erreicht. Kanäle, Broadcasts und Presence werden allesamt halb blind. Das ist der mit Abstand häufigste Grund, warum Teams aus einer WebSocket-Bibliothek herauswachsen und zu etwas anderem migrieren.

Die neue Komponente TsgcWSCluster schließt diese Lücke. Platzieren Sie sie neben Ihrem Server, richten Sie die Knoten aufeinander aus, und ein Publish- oder Presence-Ereignis auf einem beliebigen Knoten erreicht Abonnenten, die mit jedem Knoten verbunden sind, ohne dass Ihr bestehender Publish-/Kanal-/Presence-Code geändert werden muss. Dieser Beitrag führt durch die beiden Backplane-Engines, die Konfiguration sowie direkt einfügbare Delphi- und .NET-Beispiele.

Zwei Backplane-Engines

Clustering funktioniert über ein Backplane, mit dem sich jeder Knoten verbindet. Wenn ein Client auf einem Knoten veröffentlicht, liefert dieser Knoten die Nachricht an seine eigenen lokalen Abonnenten aus und leitet sie an das Backplane weiter; jeder andere Knoten empfängt sie und verteilt sie an seine lokalen Abonnenten. Schleifen werden verhindert, indem jede Nachricht mit der ID des Ursprungsknotens gekennzeichnet wird.

Das Backplane wählen Sie über die Eigenschaft EngineType:

Mesh-Backplane (keine Infrastruktur)

Die Mesh-Engine ist der schnellste Weg zum Clustering. Geben Sie jedem Knoten einen ClusterPort, auf dem er lauscht, sowie das host:port seiner Peers, und Attach Sie dann das sgc-Protokoll, damit dessen Kanal-Pub/Sub (und Presence) geclustert wird:

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;

Das ist die gesamte Änderung. Ein mit diesem Knoten verbundener Client kann auf einem Kanal Publishen, und Clients auf den beiden anderen Knoten empfangen die Nachricht, genau so, als befänden sie sich alle auf einem einzigen Server. Es sind keine Sticky Sessions erforderlich.

Redis-Backplane

Für größere Deployments schalten Sie die Engine auf clusterRedis um und richten sie auf Ihren Redis-Server aus. Alles oberhalb des Backplanes — Kanäle, Presence, Ihr Anwendungscode — bleibt gleich:

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

Die verwaltete sgcWebSockets-Edition stellt dieselbe Komponente bereit. Hängen Sie das Cluster an das sgc-Protokoll des Servers an und starten Sie es — ein Publish auf einem Knoten erreicht Abonnenten auf den anderen:

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 dieser Version liefert die .NET-Edition die Mesh-Engine; das Redis-Backplane ist in der Delphi-/C++Builder-Edition verfügbar.

Clusterweites Presence

Presence — "wer ist gerade in diesem Kanal online" — ist die Funktion, die am stärksten leidet, wenn ein Server horizontal skaliert wird, weil jeder Knoten nur seine eigenen Mitglieder sieht. TsgcWSCluster behebt das: Attach Sie das Presence-Protokoll auf die gleiche Weise, wie Sie das sgc-Protokoll anhängen, und die Mitgliederliste wird zur Vereinigung über alle Knoten hinweg. Join-/Leave-Ereignisse werden clusterweit propagiert, und bei einem ausfallenden Knoten werden dessen Mitglieder automatisch entfernt, sodass Sie nie Geistermitglieder anzeigen.

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

Erkennen, wann das Cluster bereit ist

Jedes Cluster gibt seine Konnektivität preis, sodass Sie auf das Backplane warten können, bevor Sie mit dem Veröffentlichen beginnen, oder den Knotenzustand in einem Dashboard sichtbar machen können:

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

In .NET lauten dieselben Signale OnPeerConnected / OnPeerDisconnected, die Eigenschaft ConnectedPeerCount sowie IsReady.

Wie es sich mit dem Rest der Bibliothek zusammensetzt

Clustering liegt unterhalb Ihres Protokollcodes, sodass sich sonst nichts ändert. Dieselben Publish-, Kanalabonnement-, QoS-Bestätigungs- und Presence-APIs, die Sie bereits verwenden, funktionieren weiterhin, jetzt über jeden Knoten hinweg. Die Mesh-Engine benötigt keinen externen Dienst, was ein Deployment mit zwei oder drei Knoten trivial macht; Redis steht bereit, wenn Sie größer skalieren. Eine Demo mit zwei Knoten wird mit der Bibliothek ausgeliefert (02.WebSocket_Protocols\14.MultiNode_Clustering bei Delphi, samples\ClusterDemo bei .NET), sodass Sie auf Ihrem eigenen Rechner beobachten können, wie eine Nachricht zwischen Knoten wechselt.

Verfügbarkeit

Multi-Node-Clustering ist eine Funktion der Enterprise-Edition und kompiliert über Delphi 7 bis 13 hinweg (Win32/Win64, Linux64, macOS, Android und iOS) sowie in der verwalteten .NET-Edition.

Kunden mit einem aktiven Abonnement können den neuen Build aus dem Kundenbereich herunterladen. Testbenutzer erhalten das aktualisierte Installationsprogramm unter esegece.com/products/websockets/download.

Fragen, Feedback oder Hilfe bei der Integration in Ihr Deployment? Nehmen Sie Kontakt auf — Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.