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:
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.
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.config, 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:
- Se houver pelo menos uma instância primária online, retorne uma instância online primária aleatória.
- Se todas as instâncias primárias estiverem inativas, retorne uma instância online secundária aleatória.
Para ligações do Azure Functions SignalR
Para habilitar várias instâncias do Serviço SignalR, você deve:
Use
Persistent
o tipo de transporte.O tipo de transporte padrão é
Transient
modo. Você deve adicionar a seguinte entrada ao seulocal.settings.json
arquivo ou à configuração do aplicativo no Azure.{ "AzureSignalRServiceTransportType":"Persistent" }
Nota
Ao alternar de modo para
Persistent
modo, pode haver alteração de comportamento deTransient
serialização JSON, porque emTransient
modo,Newtonsoft.Json
biblioteca é usada para serializar argumentos de métodos de hub, no entanto, em modo,System.Text.Json
bibliotecaPersistent
é usada como padrão.System.Text.Json
tem algumas diferenças importantes no comportamento padrão comNewtonsoft.Json
o . Se quiser usarNewtonsoft.Json
noPersistent
modo, você pode adicionar um item de configuração:"Azure:SignalR:HubProtocol":"NewtonsoftJson"
nolocal.settings.json
arquivo ouAzure__SignalR__HubProtocol=NewtonsoftJson
no portal do Azure.Configure várias entradas de pontos de extremidade do Serviço SignalR em sua configuração.
Usamos um
ServiceEndpoint
objeto para representar uma instância do Serviço SignalR. Você pode definir um ponto de extremidade de serviço com seu<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 o padrão éprimary
. Veja exemplos abaixo:{ "Azure:SignalR:Endpoints:EastUs":"<ConnectionString>", "Azure:SignalR:Endpoints:EastUs2:Secondary":"<ConnectionString>", "Azure:SignalR:Endpoints:WestUs:Primary":"<ConnectionString>" }
Nota
Ao configurar 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 obter os motivos, consulte Variáveis de ambiente.A cadeia de conexão configurada com a chave
{ConnectionStringSetting}
(padrão "AzureSignalRConnectionString") também é reconhecida como um ponto de extremidade de serviço primário com nome vazio. Mas esse estilo de configuração não é recomendado para vários pontos de extremidade.
Para SDK de gerenciamento
Adicionar vários pontos de extremidade a partir da configuração
Configure com chave Azure:SignalR:Endpoints
para a cadeia de conexão do Serviço SignalR. A chave deve estar no formato Azure:SignalR:Endpoints:{Name}:{EndpointType}
, onde Name
e EndpointType
são propriedades do objeto, e são acessíveis a ServiceEndpoint
partir do código.
Você pode adicionar várias cadeias de conexão de instância usando os seguintes dotnet
comandos:
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 ServiceEndpoint
classe descreve as propriedades de um ponto de extremidade do Serviço 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 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):
- A instância de serviço principal está inativa, todas as conexões de servidor nessa instância caem.
- 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.
- 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.
- 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.
- 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
Fig.2 Após failover
Fig.3 Pouco tempo após a recuperação primária
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:
- 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).
- 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:
- 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.
- 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.