Clustering en sgcWebSockets — Escala servidores WebSocket en varios nodos | Blog de eSeGeCe

Clustering en sgcWebSockets — Escala servidores WebSocket en varios nodos

· Componentes

Un servidor WebSocket que se ejecuta en un solo proceso es sencillo. En el momento en que pones dos o más instancias de servidor detrás de un balanceador de carga, algo se rompe en silencio: cada cliente se conecta exactamente a un nodo, de modo que un mensaje publicado en el nodo A nunca llega a los suscriptores que están en el nodo B. Los canales, las difusiones y Presence se quedan medio ciegos. Esta es la razón más común por la que los equipos superan las capacidades de una biblioteca WebSocket y migran a otra.

El nuevo componente TsgcWSCluster cierra esa brecha. Colócalo junto a tu servidor, haz que los nodos se apunten entre sí, y un evento de publicación o de Presence en cualquier nodo llega a los suscriptores conectados a cada nodo, sin cambiar tu código actual de Publish / canales / Presence. Esta entrada recorre los dos motores de backplane, la configuración y ejemplos en Delphi y .NET listos para pegar.

Dos motores de backplane

El clustering funciona a través de un backplane al que se conecta cada nodo. Cuando un cliente publica en un nodo, ese nodo entrega el mensaje a sus propios suscriptores locales y lo reenvía al backplane; cada uno de los demás nodos lo recibe y lo distribuye a sus suscriptores locales. Los bucles se evitan etiquetando cada mensaje con el id del nodo de origen.

Eliges el backplane con la propiedad EngineType:

Backplane de malla (sin infraestructura)

El motor de malla es la forma más rápida de hacer clustering. Da a cada nodo un ClusterPort en el que escuchar y el host:port de sus pares, y luego haz Attach del protocolo sgc para que su pub/sub de canales (y Presence) quede en clúster:

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;

Ese es todo el cambio. Un cliente conectado a este nodo puede hacer Publish a un canal y los clientes de los otros dos nodos lo reciben, exactamente como si estuvieran todos en un mismo servidor. No se requieren sesiones persistentes (sticky sessions).

Backplane Redis

Para despliegues más grandes, cambia el motor a clusterRedis y apúntalo a tu servidor Redis. Todo lo que está por encima del backplane — canales, Presence, el código de tu aplicación — permanece igual:

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

La edición gestionada de sgcWebSockets expone el mismo componente. Haz Attach del clúster al protocolo sgc del servidor e inícialo — una publicación en un nodo llega a los suscriptores de los otros:

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;

En esta versión la edición .NET incluye el motor mesh; el backplane Redis está disponible en la edición Delphi / C++Builder.

Presence en todo el clúster

Presence — "quién está en línea en este canal" — es la funcionalidad que más sufre cuando un servidor escala horizontalmente, porque cada nodo solo ve sus propios miembros. TsgcWSCluster lo soluciona: haz Attach del protocolo Presence de la misma forma que adjuntas el protocolo sgc, y la lista de miembros se convierte en la unión de todos los nodos. Los eventos de entrada / salida se propagan por todo el clúster, y un nodo que se cae tiene sus miembros purgados automáticamente, de modo que nunca muestras miembros fantasma.

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

Saber cuándo el clúster está listo

Cada clúster expone su conectividad para que puedas esperar al backplane antes de empezar a publicar, o mostrar el estado de los nodos en un panel:

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

En .NET las mismas señales son OnPeerConnected / OnPeerDisconnected, la propiedad ConnectedPeerCount y IsReady.

Cómo se integra con el resto de la biblioteca

El clustering se sitúa por debajo de tu código de protocolo, así que no cambia nada más. Las mismas APIs de Publish, suscripciones a canales, confirmaciones QoS y Presence que ya usas siguen funcionando, ahora a través de cada nodo. El motor de malla no necesita ningún servicio externo, lo que hace que un despliegue de dos o tres nodos sea trivial; Redis está ahí para cuando escales más. Con la biblioteca se incluye una demo de dos nodos (02.WebSocket_Protocols\14.MultiNode_Clustering en Delphi, samples\ClusterDemo en .NET) para que puedas ver cómo un mensaje cruza nodos en tu propia máquina.

Disponibilidad

El clustering multinodo es una característica de la edición Enterprise y compila desde Delphi 7 hasta 13 (Win32/Win64, Linux64, macOS, Android e iOS) y en la edición gestionada .NET.

Los clientes con una suscripción activa pueden descargar la nueva versión desde el área de clientes. Los usuarios de la versión de prueba pueden obtener el instalador actualizado en esegece.com/products/websockets/download.

¿Preguntas, comentarios o ayuda para integrar esto en tu despliegue? Ponte en contacto — recibirás respuesta de las personas que escribieron el código.