Skala SignalR Service med flera instanser

SignalR Service SDK stöder flera slutpunkter för SignalR Service-instanser. Du kan använda den här funktionen för att skala de samtidiga anslutningarna eller använda den för meddelanden mellan regioner.

För ASP.NET Core

Lägga till flera slutpunkter från konfigurationen

Konfigurera med nyckel Azure:SignalR:ConnectionString eller Azure:SignalR:ConnectionString: för SignalR Service-anslutningssträng.

Om nyckeln börjar med Azure:SignalR:ConnectionString:ska den vara i formatet Azure:SignalR:ConnectionString:{Name}:{EndpointType}, där Name och EndpointType är egenskaperna för ServiceEndpoint objektet och är tillgängliga från kod.

Du kan lägga till flera instanser anslutningssträng med hjälp av följande dotnet kommandon:

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>

Lägga till flera slutpunkter från kod

En ServicEndpoint klass beskriver egenskaperna för en Azure SignalR Service-slutpunkt. Du kan konfigurera flera instansslutpunkter när du använder Azure SignalR Service SDK via:

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

Anpassa slutpunktsrouter

Som standard använder SDK DefaultEndpointRouter för att hämta slutpunkter.

Standardbeteende

  1. Routning av klientbegäran:

    När klienten /negotiate är med appservern. Som standard väljer SDK slumpmässigt en slutpunkt från uppsättningen med tillgängliga tjänstslutpunkter.

  2. Routning av servermeddelande:

    När du skickar ett meddelande till en specifik anslutning och målanslutningen dirigeras till den aktuella servern går meddelandet direkt till den anslutna slutpunkten. Annars skickas meddelandena till varje Azure SignalR-slutpunkt.

Anpassa routningsalgoritm

Du kan skapa en egen router när du har särskilda kunskaper för att identifiera vilka slutpunkter meddelandena ska gå till.

I följande exempel definieras en anpassad router som dirigerar meddelanden med en grupp som börjar med till slutpunkten med east- namnet 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);
    }
}

I följande exempel åsidosätts standardbeteendet för förhandlingar och slutpunkten väljs beroende på appserverns plats.

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

Glöm inte att registrera routern till DI-containern med hjälp av:

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

För ASP.NET

Lägga till flera slutpunkter från konfigurationen

Konfiguration med nyckel Azure:SignalR:ConnectionString eller Azure:SignalR:ConnectionString: för SignalR Service-anslutningssträng.

Om nyckeln börjar med Azure:SignalR:ConnectionString:ska den vara i format Azure:SignalR:ConnectionString:{Name}:{EndpointType}, där Name och EndpointType är egenskaperna för ServiceEndpoint objektet och är tillgängliga från kod.

Du kan lägga till flera instanser anslutningssträng i 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>

Lägga till flera slutpunkter från kod

En ServiceEndpoint klass beskriver egenskaperna för en Azure SignalR Service-slutpunkt. Du kan konfigurera flera instansslutpunkter när du använder Azure SignalR Service SDK via:

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

Anpassa en router

Den enda skillnaden mellan ASP.NET SignalR och ASP.NET Core SignalR är http-kontexttypen för GetNegotiateEndpoint. För ASP.NET SignalR är den av typen IOwinContext .

Följande kod är ett anpassat förhandlingsexempel för 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
    }
}

Glöm inte att registrera routern till DI-containern med hjälp av:

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ått för tjänstslutpunkt

För att aktivera en avancerad router tillhandahåller SignalR Server SDK flera mått som hjälper servern att fatta smarta beslut. Egenskaperna finns under ServiceEndpoint.EndpointMetrics.

Måttnamn Description
ClientConnectionCount Totalt antal samtidiga klientanslutningar på alla hubbar för tjänstslutpunkten
ServerConnectionCount Totalt antal samtidiga serveranslutningar på alla hubbar för tjänstslutpunkten
ConnectionCapacity Total anslutningskvot för tjänstslutpunkten, inklusive klient- och serveranslutningar

Följande kod är ett exempel på hur du anpassar en router enligt 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 för dynamisk skalning

Från SDK version 1.5.0 aktiverar vi ServiceEndpoints i dynamisk skala för ASP.NET Core-versionen först. Så du behöver inte starta om appservern när du behöver lägga till/ta bort en ServiceEndpoint. Eftersom ASP.NET Core stöder en standardkonfiguration som appsettings.json med reloadOnChange: truebehöver du inte ändra kod och den stöds av naturen. Och om du vill lägga till en anpassad konfiguration och arbeta med frekvent omläsning läser du in konfigurationen i ASP.NET Core.

Kommentar

Med tanke på tiden för anslutningen mellan server/tjänst och klient/tjänst kan vara annorlunda, för att säkerställa att inga meddelandeförluster uppstår under skalningsprocessen, har vi en mellanlagringsperiod som väntar på att serveranslutningarna ska vara klara innan den nya ServiceEndpoint öppnas för klienter. Vanligtvis tar det några sekunder att slutföra och du kan se ett loggmeddelande som Succeed in adding endpoint: '{endpoint}' anger att processen är klar.

I vissa förväntade situationer, till exempel problem med nätverk mellan regioner eller inkonsekvenser i konfigurationen på olika appservrar, kanske mellanlagringsperioden inte slutförs korrekt. I dessa fall rekommenderar vi att du startar om appservern när du upptäcker att skalningsprocessen inte fungerar korrekt.

Standardtidsgränsen för skalan är 5 minuter och kan anpassas genom att ändra värdet i ServiceOptions.ServiceScaleTimeout. Om du har många appservrar föreslås det att du utökar värdet lite mer.

Konfiguration i scenarier mellan regioner

Objektet ServiceEndpoint har en EndpointType egenskap med värdet primary eller secondary.

Primära slutpunkter är prioriterade slutpunkter för att ta emot klienttrafik eftersom de har mer tillförlitliga nätverksanslutningar. Sekundära slutpunkter har mindre tillförlitliga nätverksanslutningar och används endast för server-till-klienttrafik. Till exempel används sekundära slutpunkter för att sända meddelanden i stället för klient till servertrafik.

I fall mellan regioner kan nätverket vara instabilt. För en appserver i USA, östra är primary SignalR Service-slutpunkten i samma region usa, östra och slutpunkter i andra regioner markerade som secondary. I den här konfigurationen kan tjänstslutpunkter i andra regioner ta emot meddelanden från den här appservern usa, östra , men inga klienter mellan regioner dirigeras till den här appservern. Följande diagram visar arkitekturen:

Cross-Geo Infra

När en klient försöker /negotiate med appservern med en standardrouter väljer SDK:et slumpmässigt en slutpunkt från uppsättningen tillgängliga primary slutpunkter. När den primära slutpunkten inte är tillgänglig väljer SDK:t slumpmässigt från alla tillgängliga secondary slutpunkter. Slutpunkten markeras som tillgänglig när anslutningen mellan servern och tjänstslutpunkten är aktiv.

I ett scenario mellan regioner, när en klient försöker /negotiate med appservern i USA, östra, returnerar den som standard alltid slutpunkten primary som finns i samma region. När alla slutpunkter i USA , östra inte är tillgängliga omdirigerar routern klienten till slutpunkter i andra regioner. I följande redundansavsnitt beskrivs scenariot i detalj.

Normal Negotiate

Redundans

När ingen primary slutpunkt är tillgänglig väljer klienten /negotiate från de tillgängliga secondary slutpunkterna. Den här redundansmekanismen kräver att varje slutpunkt fungerar som en primary slutpunkt till minst en appserver.

Diagram showing the Failover mechanism process.

Nästa steg

Du kan använda flera slutpunkter i scenarier med hög tillgänglighet och haveriberedskap.