Resistencia y recuperación ante desastres en Azure SignalR Service

La resistencia y la recuperación ante desastres son necesidades comunes de los sistemas en línea. Azure SignalR Service ya proporciona una disponibilidad del 99,9 %, pero sigue siendo un servicio regional. Cuando se produce una interrupción en toda la región, la instancia de servicio no se desplaza a otra región porque siempre se ejecuta en una región.

Para la recuperación ante desastres regional, se recomiendan los dos siguientes enfoques:

  • Habilitar la replicación geográfica (manera sencilla). Esta característica controla automáticamente la conmutación por error regional. Cuando está habilitada, solo hay una instancia de Azure SignalR y no se introduce ningún cambio de código. Consulte replicación geográfica para obtener más información.
  • Usar varios puntos de conexión en el SDK de servicio. Nuestro SDK de servicio admite varias instancias de servicio de SignalR y cambia automáticamente a otras instancias cuando algunas de ellas no están disponibles. Con esta característica, podrá recuperarse cuando se produzca un desastre, pero debe configurar la topología adecuada del sistema por su cuenta. Aprenderá a hacerlo en este documento.

Arquitectura de alta disponibilidad para SignalR Service

Para garantizar la resistencia entre regiones para SignalR Service, deberá configurar varias instancias de servicio en diferentes regiones. De manera que cuando una región esté inactiva, las demás se puedan usar como reserva. Cuando los servidores de aplicaciones se conectan a varias instancias de servicio, hay dos roles: principal y secundario. La principal es una instancia responsable de recibir tráfico en línea, mientras que la secundaria actúa como una instancia de reserva que es totalmente funcional. En nuestra implementación del SDK, negociar solo devuelve puntos de conexión principales, por lo que los clientes solo se conectan a los puntos de conexión principales en casos normales. Pero cuando la instancia principal está inactiva, la negociación devuelve puntos de conexión secundarios para que el cliente pueda continuar realizando conexiones. La instancia principal y el servidor de aplicaciones están conectados mediante conexiones de servidor normales, pero la instancia secundaria y el servidor de aplicaciones están conectados a través de una conexión débil, que es un tipo especial de conexión. Una característica distintiva de una conexión débil es que no puede aceptar el enrutamiento de conexión de cliente debido a la ubicación de la instancia secundaria en otra región. El enrutamiento de un cliente a otra región no es una opción óptima (aumenta la latencia).

Una instancia del servicio puede tener distintos roles cuando se conecta a varios servidores de aplicaciones. Una configuración típica de un escenario de regiones cruzadas tiene dos o más pares de instancias de servicio de SignalR y servidores de aplicaciones. En cada par, el servidor de aplicaciones y SignalR Service se encuentran en la misma región y este último se conecta al servidor de aplicaciones como rol principal. Entre los pares, el servidor de aplicaciones y SignalR Service también están conectados, pero este último se vuelve secundario al conectarse al servidor de otra región.

Con esta topología, todavía se puede entregar el mensaje de un servidor a todos los clientes, ya que todos los servidores de aplicaciones e instancias de servicio de SignalR están interconectados. Pero cuando se conecta un cliente, se enruta al servidor de aplicaciones de la misma región para lograr la latencia de red óptima.

En el siguiente diagrama se muestra esta topología:

Diagrama en el que se muestran dos regiones, cada una con un servidor de aplicaciones y un servicio Signalr, donde cada servidor está asociado con el servicio Signalr de su región como principal y con el servicio de la otra región como secundario.

Configurar varias instancias de servicio de SignalR

En los servidores de aplicaciones y Azure Functions se admiten varias instancias de servicio de SignalR.

Una vez que tenga el servicio de SignalR y los servidores de aplicaciones/Azure Functions creados en cada región, puede configurar los servidores de aplicaciones/Azure Functions para que se conecten a todas las instancias de servicio de SignalR.

Mediante configuración

Ya debe saber cómo configurar la cadena de conexión de SignalR Service mediante variables de entorno o configuración de aplicaciones o web.cofig, mediante una entrada de configuración denominada Azure:SignalR:ConnectionString. Si tiene varios puntos de conexión, puede establecerlos en varias entradas de configuración, cada una de ellas con el siguiente formato:

Azure:SignalR:ConnectionString:<name>:<role>

En ConnectionString, <name> es el nombre del punto de conexión y <role> es su rol (principal o secundario). El nombre es opcional, pero resulta útil si desea personalizar aún más el comportamiento de enrutamiento entre varios puntos de conexión.

Mediante código

Si prefiere almacenar la cadena de conexión en alguna otra parte, también puede leerla en el código y usarla como parámetros al llamar a AddAzureSignalR() (en ASP.NET Core) o MapAzureSignalR() (en ASP.NET).

Este es el código de ejemplo:

ASP.NET Core:

services.AddSignalR()
        .AddAzureSignalR(options => options.Endpoints = new ServiceEndpoint[]
        {
            new ServiceEndpoint("<connection_string1>", EndpointType.Primary, "region1"),
            new ServiceEndpoint("<connection_string2>", EndpointType.Secondary, "region2"),
        });

ASP.NET:

app.MapAzureSignalR(GetType().FullName, hub,  options => options.Endpoints = new ServiceEndpoint[]
    {
        new ServiceEndpoint("<connection_string1>", EndpointType.Primary, "region1"),
        new ServiceEndpoint("<connection_string2>", EndpointType.Secondary, "region2"),
    };

Puede configurar varias instancias principales o secundarias. Si hay varias instancias principales o secundarias, la negociación devuelve un punto de conexión en el orden siguiente:

  1. Si hay al menos una instancia principal en línea, devuelve una instancia en línea principal aleatoria.
  2. Si todas las instancias principales están inactivas, devuelva una instancia en línea secundaria aleatoria.

Para enlaces de SignalR de Azure Functions

Para habilitar varias instancias de SignalR Service, debe:

  1. Usar el tipo de transporte Persistent.

    El tipo de transporte predeterminado es el modo Transient. Debe agregar la siguiente entrada al archivo local.settings.json o la configuración de la aplicación en Azure.

    {
        "AzureSignalRServiceTransportType":"Persistent"
    }
    

    Nota:

    Al cambiar del modo Transient al modo Persistent, puede haber un cambio de comportamiento de serialización JSON, ya que en el modo Transient, la biblioteca Newtonsoft.Json se usa para serializar argumentos de métodos concentradores, sin embargo, en el modo Persistent, se usa la biblioteca System.Text.Json como valor predeterminado. System.Text.Json tiene algunas diferencias clave en el comportamiento predeterminado con Newtonsoft.Json. Si quiere usar Newtonsoft.Json en el modo Persistent, puede agregar un elemento de configuración: "Azure:SignalR:HubProtocol":"NewtonsoftJson" en el archivo local.settings.json o Azure__SignalR__HubProtocol=NewtonsoftJson en Azure Portal.

  2. Configure varias entradas de puntos de conexión de SignalR Service en la configuración.

    Usamos un objeto ServiceEndpoint para representar una instancia de SignalR Service. Puede definir un punto de conexión de servicio con su <EndpointName> y <EndpointType> en la clave de entrada y la cadena de conexión en el valor de entrada. Las claves tienen el siguiente formato:

    Azure:SignalR:Endpoints:<EndpointName>:<EndpointType>
    

    <EndpointType> es opcional y el valor predeterminado es primary. Consulte los siguientes ejemplos:

    {
        "Azure:SignalR:Endpoints:EastUs":"<ConnectionString>",
    
        "Azure:SignalR:Endpoints:EastUs2:Secondary":"<ConnectionString>",
    
        "Azure:SignalR:Endpoints:WestUs:Primary":"<ConnectionString>"
    }
    

    Nota:

    • Al configurar puntos de conexión de Azure SignalR en App Service en Azure Portal, no olvide reemplazar ":" por "__", el doble guion bajo en las claves. Para obtener más información, consulte Variables de entorno.

    • La cadena de conexión configurada con la clave {ConnectionStringSetting} (el valor predeterminado es "AzureSignalRConnectionString") también se reconoce como punto de conexión de servicio principal con el nombre vacío. Pero este estilo de configuración no se recomienda para varios puntos de conexión.

Para Administración del SDK

Adición de varios puntos de conexión desde la configuración

Configure con la clave Azure:SignalR:Endpoints para la cadena de conexión de SignalR Service. La clave debe tener el formato Azure:SignalR:Endpoints:{Name}:{EndpointType}, donde Name y EndpointType son propiedades del objeto ServiceEndpoint y son accesibles desde el código.

Puede agregar varias cadenas de conexión de instancias con los siguientes comandos dotnet:

dotnet user-secrets set Azure:SignalR:Endpoints:east-region-a <ConnectionString1>
dotnet user-secrets set Azure:SignalR:Endpoints:east-region-b:primary <ConnectionString2>
dotnet user-secrets set Azure:SignalR:Endpoints:backup:secondary <ConnectionString3>

Adición de varios puntos de conexión desde el código

Una clase ServiceEndpoint describe las propiedades de un punto de conexión de Azure SignalR Service. Puede configurar varios puntos de conexión de instancia al usar el SDK de administración de Azure SignalR mediante:

var serviceManager = new ServiceManagerBuilder()
                    .WithOptions(option =>
                    {
                        options.Endpoints = new ServiceEndpoint[]
                        {
                            // Note: this is just a demonstration of how to set options.Endpoints
                            // Having ConnectionStrings explicitly set inside the code is not encouraged
                            // You can fetch it from a safe place such as Azure KeyVault
                            new ServiceEndpoint("<ConnectionString0>"),
                            new ServiceEndpoint("<ConnectionString1>", type: EndpointType.Primary, name: "east-region-a"),
                            new ServiceEndpoint("<ConnectionString2>", type: EndpointType.Primary, name: "east-region-b"),
                            new ServiceEndpoint("<ConnectionString3>", type: EndpointType.Secondary, name: "backup"),
                        };
                    })
                    .BuildServiceManager();

Secuencia de conmutación por error y procedimiento recomendado

Ahora tiene la configuración de la topología de sistema correcta. Cada vez que una instancia de servicio de SignalR está inactiva, el tráfico en línea se enruta a otras instancias. Esto es lo que ocurre cuando una instancia principal está inactiva (y se recupera tras algún tiempo):

  1. La instancia principal está inactiva, todas las conexiones a los servidores de esa instancia se interrumpen.
  2. Todos los servidores conectados a esta instancia se marcan como sin conexión y la negociación deja de devolver este punto de conexión y pasa a devolver el secundario.
  3. Todas las conexiones de los clientes en esta instancia también se cierran, los clientes vuelven a conectarse. Puesto que los servidores de aplicaciones ahora devuelven el punto de conexión secundario, los clientes se conectan a la instancia secundaria.
  4. Ahora la instancia secundaria toma todo el tráfico en línea. Todos los mensajes del servidor a los clientes pueden entregarse, ya que la instancia secundaria está conectada a todos los servidores de aplicaciones. Pero los mensajes del cliente al servidor solo se enrutan al servidor de aplicaciones de la misma región.
  5. Una vez recuperada y en línea la instancia principal, el servidor de aplicaciones restablecerá las conexiones a ella y la marcará como "en línea". La negociación ahora vuelve a devolver el punto de conexión principal, de manera que los clientes se vuelven a conectar a la instancia principal. Pero los clientes existentes no se desconectan y se enrutan a la secundaria hasta que se desconectan.

A continuación, los diagramas muestran cómo se realiza la conmutación por error en SignalR Service:

Fig.1 Antes de la conmutación por error Antes de la conmutación por error

Fig.2 Después de la conmutación por error Después de la conmutación por error

Fig.3 Poco tiempo después de que la principal se recupere Poco tiempo después de que la principal se recupere

Normalmente, solo el servidor de aplicaciones y SignalR Service principales tienen tráfico en línea (en azul). Después de la conmutación por error, el servidor de aplicaciones y SignalR Service secundarios también se activan. Cuando SignalR Service principal vuelve a estar en línea, los nuevos clientes se conectarán a él. Pero los clientes existentes se seguirán conectando a la instancia secundaria, por lo que ambas instancias tendrán tráfico. Una vez desconectados todos los clientes existentes, el sistema volverá a la normalidad (ilustración 1).

Hay dos patrones principales para implementar una arquitectura de alta disponibilidad entre regiones:

  1. La primera de ellas consiste en tener un par de servidor de aplicaciones e instancia de servicio de SignalR con todo el tráfico en línea y otro par como copia de seguridad (lo que se denomina "activo/pasivo" en la ilustración 1).
  2. El otro es tener dos (o más) pares de servidores de aplicaciones e instancias de servicio de SignalR y que cada uno tenga parte del tráfico en línea y sirva de copia de seguridad para los demás pares (lo que se denomina "activo/pasivo" en la ilustración 3).

SignalR Service admite ambos patrones, la principal diferencia es la manera de implementar los servidores de aplicaciones. Si estos son de tipo "activo/pasivo", SignalR también es "activo/pasivo" (ya que el servidor de aplicaciones principal solo devuelve la instancia de servicio de SignalR principal). Si los servidores de aplicaciones son "activo/activo", SignalR también es "activo/activo" (ya que todos los servidores de aplicaciones devuelven sus propias instancias de SignalR principales, por lo que todos pueden tener tráfico).

Tenga en cuenta que, independiente de los patrones que decida usar, necesita conectar cada instancia de servicio de SignalR a un servidor de aplicaciones como principal.

Además, por la naturaleza de la conexión de SignalR (es una conexión larga), los clientes experimentan interrupciones de conexión cuando se produce un desastre y una conmutación por error. Debe tratar con esos casos desde el cliente para que sea transparente para los clientes finales. Por ejemplo, vuelva a realizar la conexión cuando se cierre.

Prueba de una conmutación por error

Siga los pasos para desencadenar la conmutación por error:

  1. En la pestaña Redes del recurso principal del portal, deshabilite el acceso a la red pública. Si el recurso tiene habilitada la red privada, use las reglas de control de acceso para denegar todo el tráfico.
  2. Reinicie el recurso principal.

Pasos siguientes

En este artículo, ha aprendido a configurar la aplicación para lograr resistencia para SignalR Service. Para conocer más detalles acerca de la conexión cliente/servidor y el enrutamiento de conexión en SignalR Service, consulte este artículo para los aspectos internos de SignalR Service.

Para escalar escenarios como el particionamiento que usa varias instancias juntas para controlar un gran número de conexiones consulte cómo escalar varias instancias.

Para más información sobre cómo configurar Azure Functions con varias instancias de servicio de SignalR, consulte compatibilidad con varias instancias de Azure SignalR Service en Azure Functions.