Compartilhar via


Dimensionar o Serviço do SignalR com várias instâncias

O SDK do Serviço do SignalR dá suporte a vários pontos de extremidade para instâncias de Serviço do SignalR. Você pode usar esse recurso para escalar as conexões simultâneas ou para mensagens entre regiões.

Importante

As cadeias de conexão brutas aparecem neste artigo somente para fins de demonstração.

Uma cadeia de conexão inclui as informações de autorização necessárias para que o seu aplicativo acesse o serviço Azure Web PubSub. A chave de acesso dentro da cadeia de conexão é semelhante a uma senha raiz para o serviço. Em ambientes de produção, sempre proteja suas chaves de acesso. Use o Azure Key Vault para gerenciar e girar suas chaves com segurança e proteger sua cadeia de conexão usando o Microsoft Entra ID e autorizar o acesso com o Microsoft Entra ID.

Evite distribuir chaves de acesso para outros usuários, fazer hard-coding com elas ou salvá-las em qualquer lugar em texto sem formatação que seja acessível a outras pessoas. Gire suas chaves se você acredita que elas podem ter sido comprometidas.

Para ASP.NET Core

Adicionar vários pontos de extremidade da configuração

As cadeias de conexão brutas aparecem neste artigo apenas para fins de demonstração. Em ambientes de produção, sempre proteja suas chaves de acesso. Use o Azure Key Vault para gerenciar e girar suas chaves com segurança e proteger sua cadeia de conexão usando o Microsoft Entra ID e autorizar o acesso com o Microsoft Entra ID.

Configure com a chave Azure:SignalR:ConnectionString ou Azure:SignalR:ConnectionString: para a cadeia de conexão do Serviço SignalR.

Se a chave começar com Azure:SignalR:ConnectionString:, ela deverá estar no formato Azure:SignalR:ConnectionString:{Name}:{EndpointType}, onde Name e EndpointType são propriedades do objeto ServiceEndpoint e estão acessíveis a partir do 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:ConnectionString:east-region-a <ConnectionString1>
dotnet user-secrets set Azure:SignalR:ConnectionString:east-region-b:primary <ConnectionString2>
dotnet user-secrets set Azure:SignalR:ConnectionString: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 usando o SDK do Serviço do Azure SignalR por meio de:

services.AddSignalR()
        .AddAzureSignalR(options =>
        {
            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"),
            };
        });

Personalizar o roteador de ponto de extremidade

Por padrão, o SDK usa o DefaultEndpointRouter para escolher os pontos de extremidade.

Comportamento padrão

  1. Roteamento de solicitação do cliente:

    Quando o cliente /negotiate com o servidor de aplicativos. Por padrão, o SDK seleciona aleatoriamente um ponto de extremidade do conjunto de pontos de extremidade de serviço disponíveis.

  2. Roteamento de mensagens do servidor:

    Ao enviar uma mensagem para uma conexão específica com a conexão de destino roteada para o servidor atual, a mensagem vai diretamente para esse ponto de extremidade conectado. Caso contrário, as mensagens são transmitidas para todos os pontos de extremidade do Azure SignalR.

Personalizar o algoritmo de roteamento

Você pode criar seu próprio roteador se você tem um conhecimento especial para identificar para quais pontos de extremidade as mensagens devem ir.

O exemplo a seguir define um roteador personalizado que roteia mensagens com um grupo começando com east- para o ponto de extremidade chamado east:

private class CustomRouter : EndpointRouterDecorator
{
    public override IEnumerable<ServiceEndpoint> GetEndpointsForGroup(string groupName, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the group broadcast behavior, if the group name starts with "east-", only send messages to endpoints inside east
        if (groupName.StartsWith("east-"))
        {
            return endpoints.Where(e => e.Name.StartsWith("east-"));
        }

        return base.GetEndpointsForGroup(groupName, endpoints);
    }
}

O exemplo a seguir substitui o comportamento de negociação padrão e seleciona o ponto de extremidade dependendo do local do servidor de aplicativos.

private class CustomRouter : EndpointRouterDecorator
{    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
          // Sample code showing how to choose endpoints based on the incoming request endpoint query
          var endpointName = context.Request.Query["endpoint"].FirstOrDefault() ?? "";
          // Select from the available endpoints, don't construct a new ServiceEndpoint object here
          return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Não se esqueça de registrar o roteador para o contêiner DI usando:

services.AddSingleton(typeof(IEndpointRouter), typeof(CustomRouter));
services.AddSignalR()
        .AddAzureSignalR(
            options =>
            {
                options.Endpoints = new ServiceEndpoint[]
                {
                    new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
                    new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
                    new ServiceEndpoint("<connectionString3>")
                };
            });

ServiceOptions.Endpoints também dá suporte à recarga dinâmica. O código de exemplo abaixo mostra como carregar cadeias de conexão de uma seção de configuração e URL pública expostas por proxies reversos de outra e, desde que a configuração dê suporte à recarga dinâmica, os pontos de extremidade poderão ser atualizados em tempo real.

services.Configure<ServiceOptions>(o =>
{
        o.Endpoints = [
            new ServiceEndpoint(Configuration["ConnectionStrings:AzureSignalR:East"], name: "east")
            {
                ClientEndpoint = new Uri(Configuration.GetValue<string>("PublicClientEndpoints:East"))
            },
            new ServiceEndpoint(Configuration["ConnectionStrings:AzureSignalR:West"], name: "west")
            {
                ClientEndpoint = new Uri(Configuration.GetValue<string>("PublicClientEndpoints:West"))
            },
        ];
});

Para ASP.NET

Adicionar vários pontos de extremidade da configuração

Configuração com chave Azure:SignalR:ConnectionString ou Azure:SignalR:ConnectionString: para a cadeia de conexão do Serviço SignalR.

Se a chave começar com Azure:SignalR:ConnectionString:, ela deverá estar no formato Azure:SignalR:ConnectionString:{Name}:{EndpointType}, em que Name e EndpointType são propriedades do objeto ServiceEndpoint e poderão ser acessadas do código.

Você pode adicionar várias cadeias de conexão de instância a web.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="Azure:SignalR:ConnectionString" connectionString="<ConnectionString1>"/>
    <add name="Azure:SignalR:ConnectionString:en-us" connectionString="<ConnectionString2>"/>
    <add name="Azure:SignalR:ConnectionString:zh-cn:secondary" connectionString="<ConnectionString3>"/>
    <add name="Azure:SignalR:ConnectionString:Backup:secondary" connectionString="<ConnectionString4>"/>
  </connectionStrings>
  ...
</configuration>

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 usando o SDK do Serviço do Azure SignalR por meio de:

app.MapAzureSignalR(
    this.GetType().FullName,
    options => {
            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("<ConnectionString1>"),
                new ServiceEndpoint("<ConnectionString2>"),
                new ServiceEndpoint("<ConnectionString3>"),
            }
        });

Personalizar um roteador

A única diferença entre o SignalR do ASP.NET e o SignalR do ASP.NET Core é o tipo de contexto de http para GetNegotiateEndpoint. Para o SignalR do ASP.NET, o tipo é IOwinContext.

O código a seguir é um exemplo de negociação personalizado para SignalR do ASP.NET:

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(IOwinContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Sample code showing how to choose endpoints based on the incoming request endpoint query
        var endpointName = context.Request.Query["endpoint"] ?? "";
        // Select from the available endpoints, don't construct a new ServiceEndpoint object here
        return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Não se esqueça de registrar o roteador para o contêiner DI usando:

var hub = new HubConfiguration();
var router = new CustomRouter();
hub.Resolver.Register(typeof(IEndpointRouter), () => router);
app.MapAzureSignalR(GetType().FullName, hub, options => {
    options.Endpoints = new ServiceEndpoint[]
                {
                    new ServiceEndpoint(name: "east", connectionString: "<connectionString1>"),
                    new ServiceEndpoint(name: "west", connectionString: "<connectionString2>"),
                    new ServiceEndpoint("<connectionString3>")
                };
});

Métricas do ponto de extremidade de serviço

Para habilitar um roteador avançado, o SDK do Servidor do SignalR fornece várias métricas para ajudar o servidor a tomar decisões inteligentes. As propriedades estão em ServiceEndpoint.EndpointMetrics.

Nome da métrica Descrição
ClientConnectionCount Contagem total de conexões de cliente simultâneas em todos os hubs para o ponto de extremidade de serviço
ServerConnectionCount Contagem total de conexões de servidor simultâneas em todos os hubs para o ponto de extremidade de serviço
ConnectionCapacity Cota total de conexão para o ponto de extremidade de serviço, incluindo conexões de cliente e servidor

O código a seguir é um exemplo de personalização de um roteador de acordo com ClientConnectionCount.

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        return endpoints.OrderBy(x => x.EndpointMetrics.ClientConnectionCount).FirstOrDefault(x => x.Online) // Get the available endpoint with minimal clients load
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

ServiceEndpoints de Escala Dinâmica

Do SDK versão 1.5.0, estamos habilitando primeiro ServiceEndpoints de escala dinâmica para a versão do ASP.NET Core. Portanto, você não precisa reiniciar o servidor de aplicativos quando precisar adicionar/remover um ServiceEndpoint. Como o ASP.NET Core é compatível com uma configuração padrão como appsettings.json com reloadOnChange: true, você não precisa alterar código e ele tem suporte por natureza. E se você quiser adicionar configurações personalizadas e trabalhar com a recarga dinâmica, confira Configuração no ASP.NET Core.

Observação

Considerando que o tempo de configuração de conexão entre o servidor/serviço e o cliente/serviço podem ser diferentes, para garantir que não haja perdas de mensagens durante o processo de escala, temos um período de preparo que aguarda que as conexões do servidor estejam prontas antes de abrir o novo ServiceEndpoint para os clientes. Normalmente, isso leva segundos para ser concluído e você poderá ver uma mensagem de log como Succeed in adding endpoint: '{endpoint}' indicando que o processo foi concluído.

Em algumas situações esperadas, como problemas de rede entre regiões ou inconsistências de configuração em servidores de aplicativos diferentes, o período de preparo pode não ser concluído corretamente. Nesses casos, é sugerido reiniciar o servidor de aplicativos quando você observar que o processo de colocação em escala não está funcionando corretamente.

O período de tempo limite padrão para a escala é de 5 minutos e pode ser personalizado alterando o valor em ServiceOptions.ServiceScaleTimeout. Se você tiver muitos servidores de aplicativos, sugere-se estender o valor um pouco mais.

Observação

Atualmente, o recurso de vários pontos de extremidade é suportado apenas no tipo de transporte Persistent.

Para extensões do SignalR Functions

Configuração

Para habilitar várias instâncias do Serviço do SignalR, você deve:

  1. Use o tipo de transporte Persistent.

    O tipo de transporte padrão é o modo Transient. Você deve adicionar a entrada a seguir ao arquivo local.settings.json ou à configuração do aplicativo no Azure.

    {
        "AzureSignalRServiceTransportType":"Persistent"
    }
    

    Observação

    Na alternância do modo Transient para o modo Persistent, pode haver uma alteração de comportamento de serialização JSON, pois no modo Transient, a biblioteca Newtonsoft.Json é usada para serializar argumentos de métodos de hub. No entanto, no modo Persistent, a biblioteca System.Text.Json é usada como padrão. System.Text.Json tem algumas diferenças importantes no comportamento padrão em relação a Newtonsoft.Json. Se quiser usar Newtonsoft.Json no modo Persistent, você poderá adicionar um item de configuração: "Azure:SignalR:HubProtocol":"NewtonsoftJson" no arquivo local.settings.json ou Azure__SignalR__HubProtocol=NewtonsoftJson no portal do Azure.

  2. 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 usa primary 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. Mas esse estilo de configuração não é recomendado para vários pontos de extremidade.

Roteamento

Comportamento padrão

Por padrão, a associação de funções usa o DefaultEndpointRouter para pegar os pontos de extremidade.

  • Roteamento de cliente: Seleciona aleatoriamente um ponto de extremidade entre os pontos de extremidade primários online. Se todos os pontos de extremidade primários estiverem offline, selecione aleatoriamente um ponto de extremidade secundário online. Se a seleção falhar novamente, será lançada uma exceção.

  • Roteamento de mensagens do servidor: Todos os pontos de extremidade de serviço são retornados.

Personalização

Modelo de C# em processo

Aqui estão as etapas para fazer isso:

  1. Implemente um roteador personalizado. Você pode aproveitar as informações fornecidas por ServiceEndpoint para tomar decisões de roteamento. Veja o guia aqui: customize-route-algorithm. Observe que o gatilho Http é necessário na função de negociação quando você precisar de HttpContext no método de negociação personalizado.

  2. Registre o roteador no contêiner de DI.

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.SignalR;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(SimpleChatV3.Startup))]
namespace SimpleChatV3
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<IEndpointRouter, CustomizedRouter>();
        }
    }
}
Modelo de processo isolado

Para funções executadas no modelo de processo isolado, oferecemos suporte à especificação de pontos de extremidade alvo em cada solicitação. Você usará novos tipos de associação para obter informações de ponto de extremidade.

Roteamento do cliente

A associação SignalRConnectionInfo seleciona um ponto de extremidade de acordo com a regra de roteamento padrão. Se você quiser personalizar a regra de roteamento, você deverá usar a associação SignalRNegotiation em vez da associação SignalRConnectionInfo.

As propriedades de configuração da associação SignalRNegotiation são as mesmas da SignalRConnectionInfo. Aqui está um exemplo de arquivo function.json:

{
    "type": "signalRNegotiation",
    "name": "negotiationContext",
    "hubName": "<HubName>",
    "direction": "in"
}

Você também pode adicionar outros dados de associação, como userId, idToken e claimTypeList, assim como SignalRConnectionInfo.

O objeto que você obtém da associação SignalRNegotiation tem o seguinte formato:

{
    "endpoints": [
        {
            "endpointType": "Primary",
            "name": "<EndpointName>",
            "endpoint": "https://****.service.signalr.net",
            "online": true,
            "connectionInfo": {
                "url": "<client-access-url>",
                "accessToken": "<client-access-token>"
            }
        },
        {
            "...": "..."
        }
    ]
}

Aqui está um exemplo de uso de associação SignalRNegotiation em JavaScript:

module.exports = function (context, req, negotiationContext) {
    var userId = req.query.userId;
    if (userId.startsWith("east-")) {
        //return the first endpoint whose name starts with "east-" and status is online.
        context.res.body = negotiationContext.endpoints.find(endpoint => endpoint.name.startsWith("east-") && endpoint.online).connectionInfo;
    }
    else {
        //return the first online endpoint
        context.res.body = negotiationContext.endpoints.filter(endpoint => endpoint.online)[0].connectionInfo;
    }
}
Roteamento de mensagens

O roteamento de mensagens ou ações precisa de dois tipos de associação para cooperar. Em geral, primeiro você precisa de um novo tipo de associação de entrada SignalREndpoints para obter todas as informações de ponto de extremidade disponíveis. Em seguida, você filtra os pontos de extremidade e obtém uma matriz contendo todos os pontos de extremidade para os quais você deseja enviar. Por fim, você especifica os pontos de extremidade de destino na associação de saída SignalR.

Aqui estão as propriedades de configuração da associação SignalREndpoints no arquivo functions.json:

{
      "type": "signalREndpoints",
      "direction": "in",
      "name": "endpoints",
      "hubName": "<HubName>"
}

O objeto que você obtém de SignalREndpoints é uma matriz de pontos de extremidade, cada um deles representado como um objeto JSON com o seguinte esquema:

{
    "endpointType": "<EndpointType>",
    "name": "<EndpointName>",
    "endpoint": "https://****.service.signalr.net",
    "online": true
}

Depois de você obter a matriz de ponto de extremidade de destino, adicione uma propriedade endpoints ao objeto de vinculação de saída. Este é um exemplo em JavaScript:

module.exports = function (context, req, endpoints) {
    var targetEndpoints = endpoints.filter(endpoint => endpoint.name.startsWith("east-"));
    context.bindings.signalRMessages = [{
        "target": "chat",
        "arguments": ["hello-world"],
        "endpoints": targetEndpoints,
    }];
    context.done();
}

Para 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();

Personalizar o roteador de ponto de extremidade

Por padrão, o SDK usa o DefaultEndpointRouter para escolher os pontos de extremidade.

Comportamento padrão

  • Roteamento de solicitação do cliente:

    Quando o cliente /negotiate com o servidor de aplicativos. Por padrão, o SDK seleciona aleatoriamente um ponto de extremidade do conjunto de pontos de extremidade de serviço disponíveis.

  • Roteamento de mensagens do servidor:

    Ao enviar uma mensagem para uma conexão específica com a conexão de destino roteada para o servidor atual, a mensagem vai diretamente para esse ponto de extremidade conectado. Caso contrário, as mensagens são transmitidas para todos os pontos de extremidade do Azure SignalR.

Personalizar o algoritmo de roteamento

Você pode criar seu próprio roteador se você tem um conhecimento especial para identificar para quais pontos de extremidade as mensagens devem ir.

O exemplo a seguir define um roteador personalizado que roteia mensagens com um grupo começando com east- para o ponto de extremidade chamado east:

private class CustomRouter : EndpointRouterDecorator
{
    public override IEnumerable<ServiceEndpoint> GetEndpointsForGroup(string groupName, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the group broadcast behavior, if the group name starts with "east-", only send messages to endpoints inside east
        if (groupName.StartsWith("east-"))
        {
            return endpoints.Where(e => e.Name.StartsWith("east-"));
        }

        return base.GetEndpointsForGroup(groupName, endpoints);
    }
}

O exemplo a seguir substitui o comportamento de negociação padrão e seleciona o ponto de extremidade dependendo do local do servidor de aplicativos.

private class CustomRouter : EndpointRouterDecorator
{    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the negotiate behavior to get the endpoint from query string
        var endpointName = context.Request.Query["endpoint"];
        if (endpointName.Count == 0)
        {
            context.Response.StatusCode = 400;
            var response = Encoding.UTF8.GetBytes("Invalid request");
            context.Response.Body.Write(response, 0, response.Length);
            return null;
        }

        return endpoints.FirstOrDefault(s => s.Name == endpointName && s.Online) // Get the endpoint with name matching the incoming request
               ?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
    }
}

Não se esqueça de registrar o roteador para o contêiner DI usando:

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"),
                        };
                    })
                    .WithRouter(new CustomRouter())
                    .BuildServiceManager();

Configuração em cenários entre regiões

O objeto ServiceEndpoint tem uma propriedade EndpointType com valor primary ou secondary.

Os pontos de extremidade primários são pontos de extremidade preferenciais para receber o tráfego do cliente porque eles têm conexões de rede mais confiáveis. Os pontos de extremidade secundários têm conexões de rede menos confiáveis e são usados apenas para o tráfego de servidor para cliente. Por exemplo, pontos de extremidade secundários são usados para transmitir mensagens em vez de tráfego de cliente para servidor.

Em casos entre regiões, a rede pode estar instável. Para um servidor de aplicativos localizado no Leste dos EUA, o ponto de extremidade do Serviço do SignalR localizado na mesma região Leste dos EUA é primary e pontos de extremidade em outras regiões são marcados como secondary. Nesta configuração, os pontos de extremidade de serviço em outras regiões podem receber mensagens desse servidor de aplicativos do Leste dos EUA, mas nenhum cliente entre regiões é roteado para este servidor de aplicativos. O seguinte diagrama mostra a arquitetura:

Infraestrutura entre áreas geográficas

Quando um cliente tenta /negotiate com o servidor de aplicativos com um roteador padrão, o SDK seleciona aleatoriamente um ponto de extremidade no conjunto de pontos de extremidade primary disponíveis. Quando o ponto de extremidade primário não está disponível, o SDK seleciona aleatoriamente entre todos os pontos de extremidade secondary disponíveis. O ponto de extremidade é marcado como disponível quando a conexão entre o servidor e o ponto de extremidade de serviço está ativa.

Em um cenário entre regiões, quando um cliente tenta /negotiate com o servidor de aplicativos hospedado no Leste dos EUA, por padrão, ele sempre retorna o ponto de extremidade primary localizado na mesma região. Quando nenhum ponto de extremidade do Leste dos EUA está disponível, o roteador redireciona o cliente para pontos de extremidade em outras regiões. A seção de failover a seguir descreve o cenário em detalhes.

Negociação normal

Failover

Quando nenhum ponto de extremidade primary está disponível, o /negotiate do cliente escolhe entre os pontos de extremidade secondary disponíveis. Este mecanismo de failover requer que cada ponto de extremidade sirva como um ponto de extremidade primary para pelo menos um servidor de aplicativo.

Diagrama mostrando o processo de mecanismo de failover.

Próximas etapas

Você pode usar vários pontos de extremidade em cenários de alta disponibilidade e recuperação de desastre.