Resiliência e recuperação de desastres no Serviço Azure SignalR

A resiliência e a recuperação de desastres são uma necessidade comum dos sistemas online. O Serviço Azure SignalR já fornece 99,9% de disponibilidade, no entanto, ainda é um serviço regional. Quando há uma interrupção em toda a região, sua instância de serviço não faz failover para outra região porque está sempre em execução em uma região.

Para a recuperação de desastres regionais, recomendamos as duas abordagens a seguir:

  • Habilite a replicação geográfica (maneira fácil). Esse recurso lida com failover regional para você automaticamente. Quando habilitado, há apenas uma instância do Azure SignalR e nenhuma alteração de código é introduzida. Verifique a replicação geográfica para obter detalhes.
  • Utilize vários pontos de extremidade no Service SDK. Nosso SDK de serviço suporta várias instâncias de serviço SignalR e alterna automaticamente para outras instâncias quando algumas delas não estão disponíveis. Com esse recurso, você pode se recuperar quando ocorre um desastre, mas precisa configurar a topologia do sistema certa sozinho. Você aprende como fazer isso neste documento.

Alta arquitetura disponível para o serviço SignalR

Para garantir a resiliência entre regiões para o serviço SignalR, você precisa configurar várias instâncias de serviço em regiões diferentes. Assim, quando uma região está inativa, as outras podem ser usadas como backup. Quando os servidores de aplicativos se conectam a várias instâncias de serviço, há duas funções, primária e secundária. Primary é uma instância responsável por receber tráfego online, enquanto secondary serve como uma instância de fallback que é totalmente funcional. Em nossa implementação do SDK, negociar retorna apenas pontos de extremidade primários, para que os clientes só se conectem aos pontos de extremidade primários em casos normais. Mas quando a instância primária está inativa, a negociação retorna pontos de extremidade secundários para que o cliente ainda possa fazer conexões. A instância primária e o servidor de aplicativos são conectados por meio de conexões normais de servidor, mas a instância secundária e o servidor de aplicativos são conectados por meio de um tipo especial de conexão chamado conexão fraca. Uma característica distintiva de uma conexão fraca é que ela não pode aceitar o roteamento de conexão do cliente devido à localização da instância secundária em outra região. Rotear um cliente para outra região não é uma escolha ideal (aumenta a latência).

Uma instância de serviço pode ter funções diferentes ao se conectar a vários servidores de aplicativos. Uma configuração típica para cenários entre regiões é ter dois ou mais pares de instâncias de serviço SignalR e servidores de aplicativos. Dentro de cada par o servidor de aplicativos e o serviço SignalR estão localizados na mesma região, e o serviço SignalR está conectado ao servidor de aplicativos como uma função principal. Entre cada par o servidor de aplicativos e o serviço SignalR também estão conectados, mas o SignalR se torna secundário ao se conectar ao servidor em outra região.

Com essa topologia, a mensagem de um servidor ainda pode ser entregue a todos os clientes, pois todos os servidores de aplicativos e instâncias de serviço SignalR estão interconectados. Mas quando um cliente está conectado, ele é direcionado para o servidor de aplicativos na mesma região para obter a latência de rede ideal.

O diagrama a seguir ilustra essa topologia:

Diagram shows two regions each with an app server and a SignalR service, where each server is associated with the SignalR service in its region as primary and with the service in the other region as secondary.

Configurar várias instâncias de serviço do SignalR

Há suporte para várias instâncias de serviço do SignalR nos servidores de aplicativos e no Azure Functions.

Depois de criar o serviço SignalR e os servidores de aplicativos/Azure Functions em cada região, você pode configurar seus servidores de aplicativo/Azure Functions para se conectar a todas as instâncias de serviço do SignalR.

Configurar em servidores de aplicativos

Existem duas formas de o fazer:

Através da configuração

Você já deve saber como definir a cadeia de conexão do serviço SignalR por meio de variáveis de ambiente/configurações do aplicativo/web.cofig, em uma entrada de configuração chamada Azure:SignalR:ConnectionString. Se você tiver vários pontos de extremidade, poderá defini-los em várias entradas de configuração, cada uma no seguinte formato:

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

Em ConnectionString, <name> é o nome do ponto de extremidade e <role> é sua função (primária ou secundária). O nome é opcional, mas é útil se você quiser personalizar ainda mais o comportamento de roteamento entre vários pontos de extremidade.

Através do código

Se preferir armazenar as cadeias de conexão em outro lugar, você também pode lê-las em seu código e usá-las como parâmetros ao chamar AddAzureSignalR() (em ASP.NET Core) ou MapAzureSignalR() (em ASP.NET).

Aqui está o código de exemplo:

ASP.NET Núcleo:

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"),
    };

Você pode configurar várias instâncias primárias ou secundárias. Se houver várias instâncias primárias e/ou secundárias, negociar retornará um ponto de extremidade na seguinte ordem:

  1. Se houver pelo menos uma instância primária online, retorne uma instância online primária aleatória.
  2. Se todas as instâncias primárias estiverem inativas, retorne uma instância online secundária aleatória.

Configurar no Azure Functions

Veja este artigo.

Sequência de failover e práticas recomendadas

Agora você tem a configuração correta da topologia do sistema. Sempre que uma instância de serviço do SignalR está inativa, o tráfego online é roteado para outras instâncias. Veja o que acontece quando uma instância principal está inativa (e se recupera depois de algum tempo):

  1. A instância de serviço principal está inativa, todas as conexões de servidor nessa instância caem.
  2. Todos os servidores conectados a essa instância a marcam como offline e negociam paradas de retorno desse ponto de extremidade e começam a retornar o ponto de extremidade secundário.
  3. Todas as conexões de cliente nesta instância também são fechadas, os clientes se reconectam. Como os servidores de aplicativos agora retornam o ponto de extremidade secundário, os clientes se conectam à instância secundária.
  4. Agora, a instância secundária recebe todo o tráfego online. Todas as mensagens do servidor para os clientes ainda podem ser entregues, pois o secundário está conectado a todos os servidores de aplicativos. Mas as mensagens de cliente para servidor só são roteadas para o servidor de aplicativos na mesma região.
  5. Depois que a instância principal for recuperada e colocada online novamente, o servidor de aplicativos restabelecerá as conexões com ela e a marcará como online. Negociar agora retorna o ponto de extremidade primário novamente para que novos clientes sejam conectados de volta ao principal. Mas os clientes existentes não caem e ainda são encaminhados para o secundário até se desconectarem.

Os diagramas abaixo ilustram como o failover é feito no serviço SignalR:

Fig.1 Antes do failover Before Failover

Fig.2 Após failover After Failover

Fig.3 Pouco tempo após a recuperação primária Short time after primary recovers

Você pode ver, em casos normais, apenas o servidor de aplicativo primário e o serviço SignalR têm tráfego online (em azul). Após o failover, o servidor de aplicativo secundário e o serviço SignalR também ficam ativos. Depois que o serviço SignalR principal estiver on-line novamente, novos clientes se conectarão ao SignalR principal. Mas os clientes existentes ainda se conectam ao secundário para que ambas as instâncias tenham tráfego. Depois que todos os clientes existentes se desconectarem, seu sistema voltará ao normal (Fig.1).

Existem dois padrões principais para implementar uma arquitetura de alta disponibilidade entre regiões:

  1. A primeira é ter um par de servidor de aplicativos e instância de serviço SignalR tomando todo o tráfego on-line, e ter outro par como backup (chamado ativo/passivo, ilustrado na Fig.1).
  2. A outra é ter dois (ou mais) pares de servidores de aplicativos e instâncias de serviço SignalR, cada um fazendo parte do tráfego online e servindo como backup para outros pares (chamados ativo/ativo, semelhante à Fig.3).

O serviço SignalR pode suportar ambos os padrões, a principal diferença é como você implementa servidores de aplicativos. Se os servidores de aplicativos estiverem ativos/passivos, o serviço SignalR também será ativo/passivo (pois o servidor de aplicativo primário retornará apenas sua instância de serviço SignalR primária). Se os servidores de aplicativos estiverem ativos/ativos, o serviço SignalR também estará ativo/ativo (pois todos os servidores de aplicativos retornam suas próprias instâncias primárias do SignalR, para que todos eles possam obter tráfego).

Não importa quais padrões você escolha usar, você precisa conectar cada instância do serviço SignalR a um servidor de aplicativos como principal.

Também devido à natureza da conexão SignalR (é uma conexão longa), os clientes experimentam quedas de conexão quando há um desastre e failover ocorrem. Você precisa lidar com esses casos do lado do cliente para torná-lo transparente para seus clientes finais. Por exemplo, reconecte-se depois que uma conexão for fechada.

Como testar um failover

Siga as etapas para acionar o failover:

  1. Na guia Rede do recurso principal no portal, desative o acesso à rede pública. Se o recurso tiver a rede privada habilitada, use regras de controle de acesso para negar todo o tráfego.
  2. Reinicie o recurso primário.

Próximos passos

Neste artigo, você aprendeu como configurar seu aplicativo para obter resiliência para o serviço SignalR. Para entender mais detalhes sobre a conexão servidor/cliente e o roteamento de conexão no serviço SignalR, você pode ler este artigo para os internos do serviço SignalR.

Para cenários de dimensionamento, como fragmentação que usa várias instâncias juntas para lidar com um grande número de conexões, leia como dimensionar várias instâncias.

Para obter detalhes sobre como configurar o Azure Functions com várias instâncias de serviço do SignalR, leia o suporte a várias instâncias do Serviço Azure SignalR no Azure Functions.