Ridimensionare Servizio SignalR con più istanze

Servizio SignalR SDK supporta più endpoint per le istanze di Servizio SignalR. È possibile usare questa funzionalità per ridimensionare le connessioni simultanee o usarla per la messaggistica tra aree.

Per ASP.NET Core

Aggiungere più endpoint dalla configurazione

Configurare con la chiave Azure:SignalR:ConnectionString o Azure:SignalR:ConnectionString: per Servizio SignalR stringa di connessione.

Se la chiave inizia con Azure:SignalR:ConnectionString:, deve essere nel formato Azure:SignalR:ConnectionString:{Name}:{EndpointType}, dove Name e EndpointType sono proprietà dell'oggetto ServiceEndpoint e sono accessibili dal codice.

È possibile aggiungere più stringa di connessione di istanza usando i comandi seguentidotnet:

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>

Aggiungere più endpoint dal codice

Una ServiceEndpoint classe descrive le proprietà di un endpoint Servizio Azure SignalR. È possibile configurare più endpoint di istanza quando si usa Servizio Azure SignalR SDK tramite:

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

Personalizzare il router endpoint

Per impostazione predefinita, l'SDK usa DefaultEndpointRouter per prelevare gli endpoint.

Comportamento predefinito

  1. Routing delle richieste client:

    Quando il client /negotiate con il server app. Per impostazione predefinita, SDK seleziona in modo casuale un endpoint dal set di endpoint di servizio disponibili.

  2. Routing dei messaggi del server:

    Quando si invia un messaggio a una connessione specifica e la connessione di destinazione viene instradata al server corrente, il messaggio passa direttamente all'endpoint connesso. In caso contrario, i messaggi vengono trasmessi a ogni endpoint di Azure SignalR.

Personalizzare l'algoritmo di routing

È possibile creare un router personalizzato quando si hanno conoscenze speciali per identificare gli endpoint a cui devono essere inviati i messaggi.

L'esempio seguente definisce un router personalizzato che instrada i messaggi con un gruppo a partire dall'endpoint east- denominato 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);
    }
}

Nell'esempio seguente viene eseguito l'override del comportamento di negoziazione predefinito e viene selezionato l'endpoint a seconda del percorso del server app.

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
    }
}

Non dimenticare di registrare il router nel contenitore di inserimento delle dipendenze 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>")
                };
            });

Per ASP.NET

Aggiungere più endpoint dalla configurazione

Configurazione con chiave Azure:SignalR:ConnectionString o Azure:SignalR:ConnectionString: per Servizio SignalR stringa di connessione.

Se la chiave inizia con Azure:SignalR:ConnectionString:, deve essere nel formato Azure:SignalR:ConnectionString:{Name}:{EndpointType}, dove Name e EndpointType sono proprietà dell'oggetto ServiceEndpoint e sono accessibili dal codice.

È possibile aggiungere più stringa di connessione di istanza 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>

Aggiungere più endpoint dal codice

Una ServiceEndpoint classe descrive le proprietà di un endpoint Servizio Azure SignalR. È possibile configurare più endpoint di istanza quando si usa Servizio Azure SignalR SDK tramite:

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

Personalizzare un router

L'unica differenza tra ASP.NET SignalR e ASP.NET Core SignalR è il tipo di contesto http per GetNegotiateEndpoint. Per ASP.NET SignalR, è di tipo IOwinContext .

Il codice seguente è un esempio di negoziazione personalizzato per ASP.NET SignalR:

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(IOwinContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Override the negotiate behavior to get the endpoint from query string
        var endpointName = context.Request.Query["endpoint"];
        if (string.IsNullOrEmpty(endpointName))
        {
            context.Response.StatusCode = 400;
            context.Response.Write("Invalid request.");
            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
    }
}

Non dimenticare di registrare il router nel contenitore di inserimento delle dipendenze 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>")
                };
});

Metriche degli endpoint di servizio

Per abilitare un router avanzato, SignalR SERVER SDK fornisce più metriche per consentire al server di prendere decisioni intelligenti. Le proprietà sono in ServiceEndpoint.EndpointMetrics.

Nome misurazione Descrizione
ClientConnectionCount Numero totale di connessioni client simultanee in tutti gli hub per l'endpoint di servizio
ServerConnectionCount Numero totale di connessioni server simultanee in tutti gli hub per l'endpoint di servizio
ConnectionCapacity Quota totale di connessione per l'endpoint di servizio, incluse le connessioni client e server

Il codice seguente è un esempio di personalizzazione di un router in base a 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
    }
}

Servizio di scalabilità dinamicaEndpoint

A partire dall'SDK versione 1.5.0, è possibile abilitare serviceEndpoint con scalabilità dinamica per ASP.NET versione Core. Non è quindi necessario riavviare il server app quando è necessario aggiungere/rimuovere un ServiceEndpoint. Poiché ASP.NET Core supporta una configurazione predefinita come appsettings.json con reloadOnChange: true, non è necessario modificare il codice ed è supportato per natura. Se si vuole aggiungere una configurazione personalizzata e usare il ricaricamento rapido, vedere Configurazione in ASP.NET Core.

Nota

Considerando il tempo di configurazione della connessione tra server/servizio e client/servizio, è possibile che non si verifichi alcuna perdita di messaggi durante il processo di scalabilità, è previsto un periodo di staging in attesa che le connessioni server siano pronte prima di aprire il nuovo ServiceEndpoint ai client. In genere sono necessari secondi per il completamento e sarà possibile visualizzare un messaggio di log simile Succeed in adding endpoint: '{endpoint}' al quale indica il processo completato.

In alcune situazioni previste, ad esempio problemi di rete tra aree o incoerenze di configurazione in server app diversi, il periodo di gestione temporanea potrebbe non terminare correttamente. In questi casi, è consigliabile riavviare il server app quando il processo di ridimensionamento non funziona correttamente.

Il periodo di timeout predefinito per la scala è di 5 minuti e può essere personalizzato modificando il valore in ServiceOptions.ServiceScaleTimeout. Se si dispone di un sacco di server app, è consigliabile estendere il valore un po 'di più.

Configurazione in scenari tra aree

L'oggetto ServiceEndpoint ha una EndpointType proprietà con valore primary o secondary.

Gli endpoint primari sono endpoint preferiti per ricevere traffico client perché hanno connessioni di rete più affidabili. Gli endpoint secondari hanno connessioni di rete meno affidabili e vengono usati solo per il traffico da server a client. Ad esempio, gli endpoint secondari vengono usati per la trasmissione di messaggi anziché per il traffico da client a server.

Nei casi tra aree, la rete può essere instabile. Per un server app che si trova negli Stati Uniti orientali, l'endpoint Servizio SignalR che si trova nella stessa area Stati Uniti orientali è primary e gli endpoint in altre aree contrassegnate come secondary. In questa configurazione, gli endpoint di servizio in altre aree possono ricevere messaggi da questo server app Stati Uniti orientali, ma non vengono instradati client tra aree a questo server app. Il diagramma seguente illustra l'architettura:

Cross-Geo Infra

Quando un client prova /negotiate con il server app con un router predefinito, l'SDK seleziona in modo casuale un endpoint dal set di endpoint disponibili primary . Quando l'endpoint primario non è disponibile, l'SDK seleziona in modo casuale da tutti gli endpoint disponibili secondary . L'endpoint è contrassegnato come disponibile quando la connessione tra il server e l'endpoint di servizio è attiva.

In uno scenario tra aree, quando un client prova /negotiate con il server app ospitato negli Stati Uniti orientali, per impostazione predefinita restituisce sempre l'endpoint primary che si trova nella stessa area. Quando tutti gli endpoint degli Stati Uniti orientali non sono disponibili, il router reindirizza il client agli endpoint in altre aree. Nella sezione failover seguente viene descritto in dettaglio lo scenario.

Negoziazione normale

Failover

Quando non è disponibile alcun primary endpoint, il client /negotiate sceglie gli endpoint disponibili secondary . Questo meccanismo di failover richiede che ogni endpoint funzioni come primary endpoint per almeno un server app.

Diagramma che mostra il processo del meccanismo di failover.

Passaggi successivi

È possibile usare più endpoint in scenari di disponibilità elevata e ripristino di emergenza.