SignalR Service schalen met meerdere exemplaren

SignalR Service SDK ondersteunt meerdere eindpunten voor SignalR Service-exemplaren. U kunt deze functie gebruiken om de gelijktijdige verbindingen te schalen of te gebruiken voor berichten tussen regio's.

Voor ASP.NET Core

Meerdere eindpunten toevoegen vanuit de configuratie

Configureer met sleutel Azure:SignalR:ConnectionString of Azure:SignalR:ConnectionString: voor SignalR Service verbindingsreeks.

Als de sleutel begint met Azure:SignalR:ConnectionString:, moet deze de indeling Azure:SignalR:ConnectionString:{Name}:{EndpointType}hebben, waar Name en EndpointType eigenschappen van het ServiceEndpoint object zijn en toegankelijk zijn vanuit code.

U kunt meerdere exemplaren verbindingsreeks toevoegen met behulp van de volgende dotnet opdrachten:

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>

Meerdere eindpunten toevoegen vanuit code

Een ServicEndpoint klasse beschrijft de eigenschappen van een Azure SignalR Service-eindpunt. U kunt meerdere exemplaareindpunten configureren wanneer u azure SignalR Service SDK gebruikt 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"),
            };
        });

Eindpuntrouter aanpassen

De SDK gebruikt standaard de DefaultEndpointRouter om eindpunten op te halen.

Standaardgedrag

  1. Routering van clientaanvragen:

    Wanneer client /negotiate met de app-server. Standaard selecteert SDK willekeurig één eindpunt in de set beschikbare service-eindpunten.

  2. Routering van serverberichten:

    Wanneer u een bericht naar een specifieke verbinding verzendt en de doelverbinding naar de huidige server wordt gerouteerd, gaat het bericht rechtstreeks naar dat verbonden eindpunt. Anders worden de berichten uitgezonden naar elk Azure SignalR-eindpunt.

Routeringsalgoritmen aanpassen

U kunt uw eigen router maken wanneer u speciale kennis hebt om te bepalen naar welke eindpunten de berichten moeten gaan.

In het volgende voorbeeld wordt een aangepaste router gedefinieerd waarmee berichten worden gerouteerd met een groep die begint met east- het eindpunt met de naam 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);
    }
}

In het volgende voorbeeld wordt het standaardonderhandelingsgedrag overschreven en wordt het eindpunt geselecteerd, afhankelijk van de locatie van de app-server.

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

Vergeet niet om de router te registreren bij de DI-container met behulp van:

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

Voor ASP.NET

Meerdere eindpunten toevoegen vanuit de configuratie

Configuratie met sleutel Azure:SignalR:ConnectionString of Azure:SignalR:ConnectionString: voor SignalR Service verbindingsreeks.

Als de sleutel begint met Azure:SignalR:ConnectionString:, moet deze in indeling Azure:SignalR:ConnectionString:{Name}:{EndpointType}zijn, waar Name en EndpointType eigenschappen van het ServiceEndpoint object zijn en toegankelijk zijn vanuit code.

U kunt meerdere exemplaren verbindingsreeks s toevoegen aanweb.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>

Meerdere eindpunten toevoegen vanuit code

Een ServiceEndpoint klasse beschrijft de eigenschappen van een Azure SignalR Service-eindpunt. U kunt meerdere exemplaareindpunten configureren wanneer u azure SignalR Service SDK gebruikt 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>"),
            }
        });

Een router aanpassen

Het enige verschil tussen ASP.NET SignalR en ASP.NET Core SignalR is het http-contexttype voor GetNegotiateEndpoint. Voor ASP.NET SignalR is het van het type IOwinContext .

De volgende code is een aangepast onderhandelingsvoorbeeld voor 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
    }
}

Vergeet niet om de router te registreren bij de DI-container met behulp van:

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

Metrische gegevens voor service-eindpunt

Als u een geavanceerde router wilt inschakelen, biedt SignalR Server SDK meerdere metrische gegevens om de server te helpen slimme beslissingen te nemen. De eigenschappen bevinden zich onder ServiceEndpoint.EndpointMetrics.

Naam meetwaarde Omschrijving
ClientConnectionCount Totaal aantal gelijktijdige clientverbindingen op alle hubs voor het service-eindpunt
ServerConnectionCount Totaal aantal gelijktijdige serververbindingen op alle hubs voor het service-eindpunt
ConnectionCapacity Totaal verbindingsquotum voor het service-eindpunt, inclusief client- en serververbindingen

De volgende code is een voorbeeld van het aanpassen van een router op ClientConnectionCountbasis van .

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

Dynamic Scale ServiceEndpoints

Vanaf SDK-versie 1.5.0 schakelen we ServiceEndpoints voor dynamische schaal in voor ASP.NET Core-versie. U hoeft de app-server dus niet opnieuw op te starten wanneer u een ServiceEndpoint wilt toevoegen of verwijderen. Omdat ASP.NET Core ondersteuning biedt voor een standaardconfiguratie zoals appsettings.json bij reloadOnChange: true, hoeft u geen code te wijzigen en wordt deze door de aard ondersteund. En als u een aangepaste configuratie wilt toevoegen en wilt werken met hot-reload, raadpleegt u Configuratie in ASP.NET Core.

Notitie

Gezien de tijd van het instellen van de verbinding tussen server/service en client/service kan verschillen, om ervoor te zorgen dat er tijdens het schaalproces geen berichten verloren gaan, hebben we een faseringsperiode die wacht tot serververbindingen gereed zijn voordat de nieuwe ServiceEndpoint voor clients wordt geopend. Meestal duurt het seconden om te voltooien en kunt u een logboekbericht zien, zoals Succeed in adding endpoint: '{endpoint}' dit aangeeft dat het proces is voltooid.

In sommige verwachte situaties, zoals netwerkproblemen tussen regio's of inconsistenties in de configuratie op verschillende app-servers, is de faseringsperiode mogelijk niet correct voltooid. In deze gevallen wordt aangeraden de app-server opnieuw op te starten wanneer het schaalproces niet goed werkt.

De standaardtime-outperiode voor de schaal is vijf minuten en kan worden aangepast door de waarde in ServiceOptions.ServiceScaleTimeoutte wijzigen. Als u veel app-servers hebt, wordt u aangeraden om de waarde iets meer uit te breiden.

Configuratie in scenario's tussen regio's

Het ServiceEndpoint object heeft een EndpointType eigenschap met waarde primary of secondary.

Primaire eindpunten zijn voorkeurseindpunten om clientverkeer te ontvangen, omdat ze betrouwbaardere netwerkverbindingen hebben. Secundaire eindpunten hebben minder betrouwbare netwerkverbindingen en worden alleen gebruikt voor server-naar-clientverkeer. Secundaire eindpunten worden bijvoorbeeld gebruikt voor het uitzenden van berichten in plaats van client-naar-serververkeer.

In gevallen tussen regio's kan het netwerk instabiel zijn. Voor een app-server in VS - oost is primary het SignalR Service-eindpunt in dezelfde regio VS - oost en eindpunten in andere regio's gemarkeerd als secondary. In deze configuratie kunnen service-eindpunten in andere regio's berichten ontvangen van deze app-server voor VS - oost, maar er worden geen clients tussen regio's doorgestuurd naar deze app-server. In het volgende diagram ziet u de architectuur:

Cross-Geo Infra

Wanneer een client probeert /negotiate met de app-server met een standaardrouter, selecteert de SDK willekeurig één eindpunt uit de set beschikbare primary eindpunten. Wanneer het primaire eindpunt niet beschikbaar is, selecteert de SDK willekeurig uit alle beschikbare secondary eindpunten. Het eindpunt wordt gemarkeerd als beschikbaar wanneer de verbinding tussen de server en het service-eindpunt actief is.

In een scenario tussen regio's, wanneer een client probeert /negotiate met de app-server die wordt gehost in VS - oost, wordt standaard altijd het primary eindpunt in dezelfde regio geretourneerd. Wanneer niet alle EINDPUNTen vs - oost beschikbaar zijn, stuurt de router de client om naar eindpunten in andere regio's. In de volgende failoversectie wordt het scenario gedetailleerd beschreven.

Normal Negotiate

Failover

Wanneer er geen primary eindpunt beschikbaar is, kiest de client /negotiate uit de beschikbare secondary eindpunten. Dit failovermechanisme vereist dat elk eindpunt als eindpunt primary fungeert voor ten minste één app-server.

Diagram showing the Failover mechanism process.

Volgende stappen

U kunt meerdere eindpunten gebruiken in scenario's met hoge beschikbaarheid en herstel na noodgevallen.