Resiliência e recuperação de desastre no Serviço do Azure SignalR
Resiliência e recuperação de desastre são necessidades comuns de sistemas online. O Serviço do 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, a 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 desastre regional, recomendamos as duas seguintes abordagens:
- Habilitar a replicação geográfica (maneira fácil). Esse recurso lida com o failover regional para você automaticamente. Quando habilitado, há apenas uma instância do Azure SignalR e nenhuma alteração de código é introduzida. Verifique Replicação geográfica para obter detalhes.
- Utilize vários pontos de extremidade no SDK de serviço. Nosso SDK de serviço dá suporte a várias instâncias do Serviço do SignalR e alterna automaticamente para outras instâncias quando algumas delas não estão disponíveis. Com esse recurso, você poderá se recuperar quando ocorrer um desastre, mas precisará configurar a topologia de sistema certa por conta própria. Você aprenderá a fazer isso neste documento.
Arquitetura de alta disponibilidade para o Serviço do SignalR
Para garantir resiliência entre regiões para o Serviço do SignalR, você precisa configurar várias instâncias do serviço em diferentes regiões. Assim, quando uma região estiver inativa, as outras poderão 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. A primária é uma instância responsável por receber o tráfego online, enquanto a secundária serve como uma instância de fallback totalmente funcional. Em nossa implementação do SDK, “negociate” só retorna os pontos de extremidade primários, de modo que os clientes se conectam apenas aos pontos de extremidade primários em casos normais. No entanto, quando a instância primária está inativa, “negociate” 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 de servidor normais, mas a instância secundária e o servidor de aplicativos são conectados por meio de um tipo especial de conexão chamada conexão fraca. Um diferencial de uma conexão fraca é que não é possível aceitar o roteamento de conexão do cliente devido ao local da instância secundária em outra região. Fazer o roteamento de um cliente para outra região não é a opção ideal (fazer isso 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 do cenário com várias regiões é ter dois ou mais pares de instâncias do Serviço do SignalR e servidores de aplicativos. Dentro de cada par, o servidor de aplicativos e o Serviço do SignalR estão localizados na mesma região, e o Serviço do SignalR está conectado ao servidor de aplicativos como uma função primária. Entre cada par, o servidor de aplicativos e o Serviço do SignalR também estão conectados, mas o SignalR se torna secundário ao se conectar ao servidor em outra região.
Com esta topologia, mensagens de um servidor ainda podem ser entregues a todos os clientes, uma vez que todos os servidores de aplicativos e instâncias do Serviço do SignalR são interconectados. No entanto, quando um cliente é conectado, ele é roteado para o servidor de aplicativos na mesma região para alcançar a latência de rede ideal.
O seguinte diagrama ilustra uma topologia desse tipo:
Configurar várias instâncias do serviço do SignalR
Várias instâncias do serviço do SignalR têm suporte em servidores de aplicativos e no Azure Functions.
Depois que você tiver o serviço do SignalR e os servidores de aplicativo/Azure Functions criados em cada região, você poderá configurar seus servidores de aplicativo/Azure Functions para se conectar a todas as instâncias de serviço do SignalR.
Usando a configuração
Você já deve saber como definir a cadeia de conexão do Serviço do SignalR por meio de variáveis de ambiente/configurações de aplicativo/web.config, usando uma entrada de configuração chamada Azure:SignalR:ConnectionString
.
Se você tiver vários pontos de extremidade, você poderá defini-los em várias entradas de configuração, cada uma no seguinte formato:
Azure:SignalR:ConnectionString:<name>:<role>
Na ConnectionString, <name>
é o nome do ponto de extremidade e <role>
é a função dele (primária ou secundária).
O nome é opcional, mas ele será útil se você quiser personalizar ainda mais o comportamento de roteamento entre vários pontos de extremidade.
Usando código
Se preferir armazenar a cadeia de conexão em outro lugar, você também poderá lê-la em seu código e usá-la como parâmetro ao chamar AddAzureSignalR()
(no ASP.NET Core) ou MapAzureSignalR()
(no ASP.NET).
Veja o código de exemplo:
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"),
};
Você pode configurar várias instâncias primárias ou secundárias. Se houver várias instâncias primárias e/ou secundárias, “negotiate” retornará um ponto de extremidade na seguinte ordem:
- Se houver pelo menos uma instância primária online, retorne uma instância online aleatória.
- Se todas as instâncias primárias estiverem inativas, retorne uma instância online secundária aleatória.
Para associações do SignalR do Azure Functions
Para habilitar várias instâncias do Serviço do SignalR, você deve:
Use o tipo de transporte
Persistent
.O tipo de transporte padrão é o modo
Transient
. Você deve adicionar a entrada a seguir ao arquivolocal.settings.json
ou à configuração do aplicativo no Azure.{ "AzureSignalRServiceTransportType":"Persistent" }
Observação
Na alternância do modo
Transient
para o modoPersistent
, pode haver uma alteração de comportamento de serialização JSON, pois no modoTransient
, a bibliotecaNewtonsoft.Json
é usada para serializar argumentos de métodos de hub. No entanto, no modoPersistent
, a bibliotecaSystem.Text.Json
é usada como padrão.System.Text.Json
tem algumas diferenças importantes no comportamento padrão em relação aNewtonsoft.Json
. Se quiser usarNewtonsoft.Json
no modoPersistent
, você poderá adicionar um item de configuração:"Azure:SignalR:HubProtocol":"NewtonsoftJson"
no arquivolocal.settings.json
ouAzure__SignalR__HubProtocol=NewtonsoftJson
no portal do Azure.Configure várias entradas de pontos de extremidade do Serviço do SignalR em sua configuração.
Usamos um objeto
ServiceEndpoint
para representar uma instância do Serviço do SignalR. Você pode definir um ponto de extremidade de serviço com os respectivos<EndpointName>
e<EndpointType>
na chave de entrada e a cadeia de conexão no valor da entrada. As chaves estão no seguinte formato:Azure:SignalR:Endpoints:<EndpointName>:<EndpointType>
<EndpointType>
é opcional e usaprimary
como padrão. Confira as amostras abaixo:{ "Azure:SignalR:Endpoints:EastUs":"<ConnectionString>", "Azure:SignalR:Endpoints:EastUs2:Secondary":"<ConnectionString>", "Azure:SignalR:Endpoints:WestUs:Primary":"<ConnectionString>" }
Observação
Quando você configurar os pontos de extremidade do Azure SignalR no Serviço de Aplicativo no portal do Azure, não se esqueça de substituir
":"
por"__"
, o sublinhado duplo nas chaves. Para ver os motivos, confira Variáveis de ambiente.A cadeia de conexão configurada com a chave
{ConnectionStringSetting}
(usa “AzureSignalRConnectionString” como padrão) também é reconhecida como um ponto de extremidade de serviço primário com o nome vazio. No entanto, esse estilo de configuração não é recomendado para vários pontos de extremidade.
Em SDK de Gerenciamento
Adicionar vários pontos de extremidade da configuração
Faça a configuração com a chave Azure:SignalR:Endpoints
para a cadeia de conexão do Serviço do SignalR. A chave deve estar no formato Azure:SignalR:Endpoints:{Name}:{EndpointType}
, em que Name
e EndpointType
são propriedades do objeto ServiceEndpoint
e podem ser acessadas pelo código.
Você pode adicionar várias cadeias de conexão de instância usando os seguintes 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>
Adicionar vários pontos de extremidade do código
Uma classe ServiceEndpoint
descreve as propriedades de um ponto de extremidade do Serviço do Azure SignalR.
Você pode configurar vários pontos de extremidade de instância ao usar o SDK de Gerenciamento do Azure SignalR por meio de:
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();
Sequência de failover e melhor prática
Agora, você tem a topologia de sistema certa configurada. Sempre que uma instância do Serviço do SignalR estiver inativa, o tráfego online será roteado para outras instâncias. Veja o que acontece quando uma instância primária fica inativa (e se recupera após algum tempo):
- A instância de serviço primária está inativa e todas as conexões dessa instância são descartadas.
- Todos os servidores conectados a essa instância a marcarão como offline e “negotiate” deixará de retornar esse ponto de extremidade e começará a retornar o ponto de extremidade secundário.
- Todas as conexões de cliente dessa instância também são fechadas e, em seguida, os clientes se reconectarão. Como os servidores de aplicativos já retornam o ponto de extremidade secundário, os clientes se conectarão à instância secundária.
- 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 ponto de extremidade secundário está conectado a todos os servidores de aplicativos. No entanto, as mensagens do cliente para o servidor são roteadas apenas para o servidor de aplicativos na mesma região.
- Após a instância primária ser recuperada e voltar a ficar online, o servidor de aplicativos restabelecerá conexões com ela e a marcará como online. Agora, “negotiate” retorna o ponto de extremidade primário, de modo que os clientes serão conectados novamente ao primário. No entanto, os clientes existentes não são removidos e ainda são encaminhados para o secundário até se desconectarem.
Os diagramas abaixo ilustram como o failover é feito no Serviço do SignalR:
Fig. 1: antes do failover
Fig. 2: após o failover
Fig. 3: pouco tempo após a recuperação primária
Você pode ver que, no funcionamento normal, somente o servidor de aplicativos e o Serviço do SignalR primários têm tráfego online (em azul). Após o failover, o servidor de aplicativos e o Serviço do SignalR secundários também se tornam ativos. Após o Serviço do SignalR primário voltar a ficar online, novos clientes se conectam a ele. No entanto, clientes existentes ainda se conectam ao serviço secundário, de modo que as duas instâncias têm tráfego. Após todos os clientes existentes se desconectarem, o sistema voltará ao normal (Fig.1).
Há dois padrões principais para implementar uma arquitetura entre regiões de alta disponibilidade:
- O primeiro é ter um par de servidor de aplicativos e instância do Serviço do SignalR que recebe todo o tráfego online e ter outro par como backup (chamado de ativo/passivo, ilustrado na Fig.1).
- O outro padrão é ter dois pares (ou mais) de servidores de aplicativos e instâncias do Serviço do SignalR, cada um deles recebendo parte do tráfego online e servindo como backup para os outros pares (chamado de ativo/ativo, semelhante à Fig.3).
O Serviço do SignalR pode dar suporte aos dois padrões, a principal diferença é como você implementa os servidores de aplicativos. Se os servidores de aplicativos forem do tipo ativo/passivo, o Serviço do SignalR também será ativo/passivo (pois o servidor de aplicativos primário retorna apenas a instância primária do Serviço do SignalR). Se os servidores de aplicativos forem do tipo ativo/ativo, o Serviço do SignalR também será ativo/ativo (pois todos os servidores de aplicativos retornarão instâncias primárias próprias do SignalR, para que todos eles possam receber o tráfego).
Observe que, independentemente dos padrões que você optar por usar, você precisará conectar cada instância do Serviço do SignalR a um servidor de aplicativos como primário.
Além disso, devido à natureza da conexão do SignalR (trata-se de uma conexão longa), os clientes enfrentam quedas de conexão quando há um desastre e o failover ocorre. Você precisa lidar com esses casos no lado do cliente para torná-los transparentes para os clientes finais. Por exemplo, reconecte-se após uma conexão ser encerrada.
Como testar um failover
Siga as etapas para disparar o failover:
- Na guia Rede do recurso primário no portal, desabilite o acesso à rede pública. Se o recurso tiver a rede privada habilitada, use as regras de controle de acesso para negar todo o tráfego.
- Reinicie o recurso primário.
Próximas etapas
Neste artigo, você aprendeu a configurar seu aplicativo para ter resiliência para o Serviço do SignalR. Para obter mais detalhes sobre a conexão de cliente/servidor e o roteamento de conexão no Serviço do SignalR, você pode ler este artigo sobre recursos internos do Serviço do SignalR.
Para cenários de escala, como fragmentação, que usam várias instâncias em conjunto para lidar com um grande número de conexões, leia Como escalar várias instâncias.
Para obter detalhes sobre como configurar Azure Functions com várias instâncias de serviço do SignalR, leia suporte para várias instâncias do serviço do Azure SignalR em Azure Functions.