Skalieren von SignalR Service mit mehreren Instanzen

Das SignalR Service SDK unterstützt mehrere Endpunkte für SignalR Service-Instanzen. Sie können dieses Feature zum Skalieren der gleichzeitigen Verbindungen oder für das regionsübergreifende Messaging verwenden.

Für ASP.NET Core

Hinzufügen mehrerer Endpunkte über die Konfiguration

Verwenden Sie für die Konfiguration den Schlüssel Azure:SignalR:ConnectionString oder Azure:SignalR:ConnectionString: als SignalR Service-Verbindungszeichenfolge.

Wenn der Schlüssel mit Azure:SignalR:ConnectionString: beginnt, sollte er das Format Azure:SignalR:ConnectionString:{Name}:{EndpointType} aufweisen. Hierbei sind Name und EndpointType Eigenschaften des ServiceEndpoint-Objekts, die über den Code zugänglich sind.

Sie können Verbindungszeichenfolgen für mehrere Instanzen hinzufügen, indem Sie die folgenden dotnet-Befehle verwenden:

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>

Hinzufügen mehrerer Endpunkte über Code

Eine ServiceEndpoint-Klasse beschreibt die Eigenschaften eines Azure SignalR Service-Endpunkts. Sie können mehrere Instanzen für Endpunkte konfigurieren, wenn Sie das Azure SignalR Service SDK verwenden:

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

Anpassen des Endpunktrouters

Standardmäßig wird vom SDK das DefaultEndpointRouter-Element verwendet, um Endpunkte zu erfassen.

Standardverhalten

  1. Routing von Clientanforderungen:

    Wird verwendet, wenn Clients die Aushandlung (/negotiate) mit dem App-Server durchführen. Standardmäßig nimmt das SDK eine zufällige Auswahl eines Endpunkts aus den verfügbaren Dienstendpunkten vor.

  2. Routing von Servernachrichten:

    Wenn eine Nachricht an eine bestimmte Verbindung gesendet und die Zielverbindung an den aktuellen Server geleitet wird, geht die Nachricht direkt an diesen verbundenen Endpunkt. Andernfalls werden die Nachrichten an jeden Azure SignalR-Endpunkt übertragen.

Anpassen des Routingalgorithmus

Sie können Ihre eigenen Router erstellen, wenn Sie über spezielle Kenntnisse verfügen und ermitteln können, an welche Endpunkte die Nachrichten gesendet werden sollen.

Im folgenden Beispiel wird ein benutzerdefinierter Router definiert, der Nachrichten mit einer Gruppe, die mit east- beginnt, an den Endpunkt namens east weiterleitet:

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

Im folgenden Beispiel wird das Standardverhalten für die Aushandlung außer Kraft gesetzt und der Endpunkt abhängig vom Standort des App-Servers ausgewählt.

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

Vergessen Sie nicht, den Router wie folgt für den DI-Container zu registrieren:

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

Hinzufügen mehrerer Endpunkte über die Konfiguration

Verwenden Sie für die Konfiguration den Schlüssel Azure:SignalR:ConnectionString oder Azure:SignalR:ConnectionString: als SignalR Service-Verbindungszeichenfolge.

Wenn der Schlüssel mit Azure:SignalR:ConnectionString: beginnt, sollte er das Format Azure:SignalR:ConnectionString:{Name}:{EndpointType} aufweisen. Hierbei sind Name und EndpointType Eigenschaften des ServiceEndpoint-Objekts, die über den Code zugänglich sind.

Sie können web.config Verbindungszeichenfolgen für mehrere Instanzen hinzufügen:

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

Hinzufügen mehrerer Endpunkte über Code

Eine ServiceEndpoint-Klasse beschreibt die Eigenschaften eines Azure SignalR Service-Endpunkts. Sie können mehrere Instanzen für Endpunkte konfigurieren, wenn Sie das Azure SignalR Service SDK verwenden:

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

Anpassen eines Routers

Der einzige Unterschied zwischen ASP.NET SignalR und ASP.NET Core SignalR ist der HTTP-Kontexttyp für GetNegotiateEndpoint. Für ASP.NET SignalR lautet der Typ IOwinContext.

Der folgende Code ist ein Beispiel für die benutzerdefinierte Aushandlung 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
    }
}

Vergessen Sie nicht, den Router wie folgt für den DI-Container zu registrieren:

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

Dienstendpunktmetriken

Zum Aktivieren eines erweiterten Routers bietet das SignalR Server SDK mehrere Metriken, die einem Server das Treffen intelligenter Entscheidungen ermöglichen. Die Eigenschaften befinden sich unter ServiceEndpoint.EndpointMetrics.

Metrikname Beschreibung
ClientConnectionCount Gesamtanzahl gleichzeitiger Clientverbindungen auf allen Hubs für den Dienstendpunkt
ServerConnectionCount Gesamtanzahl gleichzeitiger Serververbindungen auf allen Hubs für den Dienstendpunkt
ConnectionCapacity Gesamtverbindungskontingent für den Dienstendpunkt, einschließlich Client- und Serververbindungen

Der folgende Code ist ein Beispiel für das Anpassen eines Routers gemäß 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
    }
}

Dienstendpunkte (ServiceEndpoints) mit dynamischer Skalierung

Ab SDK Version 1.5.0 aktivieren wir zuerst Dienstendpunkte (ServiceEndpoints) mit dynamischer Skalierung für die ASP.NET Core-Version. Daher müssen Sie den App-Server nicht neu starten, wenn Sie ein ServiceEndpoint-Element hinzufügen/entfernen müssen. Da ASP.NET Core die Standardkonfiguration wie appsettings.json mit reloadOnChange: true unterstützt, müssen Sie keinen Code ändern, er wird automatisch unterstützt. Wenn Sie eine benutzerdefinierte Konfiguration hinzufügen und Hot Reload nutzen möchten, lesen Sie Konfiguration in ASP.NET Core.

Hinweis

Die Dauer der Verbindungseinrichtung zwischen Server/Dienst und Client/Dienst kann variieren. Daher gibt es einen Bereitstellungszeitraum, der abgewartet wird, damit die Serververbindungen bereit sind, bevor der neue Dienstendpunkt (ServiceEndpoint) für Clients geöffnet wird. Somit wird sichergestellt, dass während der Skalierung keine Nachrichten verloren gehen. In der Regel dauert es wenige Sekunden, bis der Vorgang abgeschlossen ist und ein Protokollmeldung wie Succeed in adding endpoint: '{endpoint}' angezeigt wird, die angibt, dass der Vorgang abgeschlossen ist.

In einigen zu erwartenden Situationen, etwa bei regionsübergreifenden Netzwerkproblemen oder Konfigurationsinkonsistenzen auf verschiedenen App-Servern, kann der Bereitstellungszeitraum jedoch möglicherweise nicht ordnungsgemäß abgeschlossen werden. In diesen Fällen wird empfohlen, den App-Server neu zu starten, wenn Sie feststellen, dass der Skalierungsprozess nicht ordnungsgemäß funktioniert.

Der standardmäßige Timeoutzeitraum für die Skalierung beträgt fünf Minuten und kann durch Änderung des Werts ServiceOptions.ServiceScaleTimeout angepasst werden. Wenn Sie viele App-Server besitzen, wird empfohlen, den Wert etwas mehr zu erhöhen.

Hinweis

Das Feature für mehrere Endpunkte wird derzeit nur für den Transporttyp Persistent unterstützt.

Für SignalR-Funktionserweiterungen

Konfiguration

Beim Aktivieren mehrerer SignalR Service-Instanzen müssen Sie Folgendes beachten:

  1. Verwenden Sie den Transporttyp Persistent.

    Der Standardtransporttyp ist der Transient-Modus. Fügen Sie Ihrer local.settings.json-Datei oder der Anwendungseinstellung in Azure den folgenden Eintrag hinzu:

    {
        "AzureSignalRServiceTransportType":"Persistent"
    }
    

    Hinweis

    Wenn Sie vom Transient-Modus in den Persistent-Modus wechseln, kann sich das JSON-Serialisierungsverhalten ändern, da im Transient-Modus die Newtonsoft.Json-Bibliothek verwendet wird, um Argumente von Hubmethoden zu serialisieren, die System.Text.Json-Bibliothek wird jedoch im Persistent-Modus als Standard verwendet. System.Text.Json weist einige wichtige Unterschiede beim Standardverhalten im Vergleich zu Newtonsoft.Json auf. Wenn Sie Newtonsoft.Json im Persistent-Modus verwenden möchten, können Sie ein Konfigurationselement hinzufügen: "Azure:SignalR:HubProtocol":"NewtonsoftJson" in der local.settings.json-Datei oder Azure__SignalR__HubProtocol=NewtonsoftJson im Azure-Portal.

  2. Konfigurieren Sie mehrere SignalR Service-Endpunkteinträge in Ihrer Konfiguration.

    Wir verwenden ein ServiceEndpoint-Objekt, um eine SignalR Service-Instanz zu repräsentieren. Sie können einen Dienstendpunkt mit <EndpointName> und <EndpointType> im Eintragsschlüssel und der Verbindungszeichenfolge im Eintragswert definieren. Die Schlüssel haben das folgende Format:

    Azure:SignalR:Endpoints:<EndpointName>:<EndpointType>
    

    <EndpointType> ist optional und standardmäßig auf primary festgelegt. Beispiele finden Sie hier:

    {
        "Azure:SignalR:Endpoints:EastUs":"<ConnectionString>",
    
        "Azure:SignalR:Endpoints:EastUs2:Secondary":"<ConnectionString>",
    
        "Azure:SignalR:Endpoints:WestUs:Primary":"<ConnectionString>"
    }
    

    Hinweis

    • Wenn Sie Azure SignalR-Endpunkte in App Service im Azure-Portal konfigurieren, vergessen Sie nicht, ":" durch "__" zu ersetzen, den doppelten Unterstrich in den Schlüsseln. Die Begründung finden Sie unter Umgebungsvariablen.

    • Die mit dem Schlüssel {ConnectionStringSetting} konfigurierte Verbindungszeichenfolge (Standardeinstellung „AzureSignalRConnectionString“) wird auch als primärer Dienstendpunkt mit leerem Namen erkannt. Dieser Konfigurationsstil wird jedoch für mehrere Endpunkte nicht empfohlen.

Routing

Standardverhalten

Standardmäßig wird von der Funktionsbindung das DefaultEndpointRouter-Element verwendet, um Endpunkte zu erfassen.

  • Clientrouting: Wählen Sie nach dem Zufallsprinzip einen Endpunkt aus den primären Onlineendpunkten aus. Wenn alle primären Endpunkte offline sind, wählen Sie nach dem Zufallsprinzip einen sekundären Onlineendpunkt aus. Wenn die Auswahl wieder nicht erfolgreich war, wird die Ausnahme ausgelöst.

  • Servernachrichtenrouting: Alle Dienstendpunkte werden zurückgegeben.

Anpassung

C#-In-Process-Modell

Gehen Sie wie folgt vor:

  1. Implementieren Sie einen benutzerdefinierten Router. Sie können von ServiceEndpoint bereitgestellte Informationen nutzen, um eine Routingentscheidung zu treffen. Einen Leitfaden finden Sie hier: customize-route-algorithm. Beachten Sie, dass der HTTP-Trigger in der Aushandlungsfunktion erforderlich ist, wenn Sie HttpContext in der benutzerdefinierten Aushandlungsmethode benötigen.

  2. Registrieren Sie den Router für den DI-Container.

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>();
        }
    }
}
Modell mit isolierten Prozessen

Für Funktionen, die in einem Modell mit isolierten Prozessen ausgeführt werden, unterstützen wir die Angabe von Zielendpunkten in jeder Anforderung. Sie verwenden neue Bindungstypen, um Endpunktinformationen abzurufen.

Clientseitiges Routing

Die Bindung SignalRConnectionInfo wählt einen Endpunkt gemäß der Standardroutingregel aus. Wenn Sie die Routingregel anpassen möchten, sollten Sie die Bindung SignalRNegotiation anstelle der Bindung SignalRConnectionInfo verwenden.

Die Konfigurationseigenschaften der SignalRNegotiation-Bindung sind mit SignalRConnectionInfo identisch. Hier sehen Sie ein Beispiel für die Datei function.json:

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

Sie können auch weitere Bindungsdaten wie userId, idToken und claimTypeList genau wie SignalRConnectionInfo hinzufügen.

Das Objekt, das Sie aus der Bindung SignalRNegotiation abrufen, weist das folgende Format auf:

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

Hier sehen Sie ein JavaScript-Verwendungsbeispiel für die BindungSignalRNegotiation:

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

Beim Routing von Nachrichten oder Aktionen müssen zwei Bindungstypen zusammenarbeiten. Im Allgemeinen benötigen Sie zunächst einen neuen Eingabebindungstyp SignalREndpoints, um alle verfügbaren Endpunktinformationen abzurufen. Anschließend filtern Sie die Endpunkte und rufen ein Array ab, das alle Endpunkte enthält, an die Sie senden möchten. Zuletzt geben Sie die Zielendpunkte in der SignalR-Ausgabebindung an.

Hier sehen Sie die Konfigurationseigenschaften der SignalREndpoints-Bindung in der Datei functions.json:

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

Das Objekt, das Sie von SignalREndpoints abrufen, ist ein Array von Endpunkten, die jeweils als JSON-Objekt mit dem folgenden Schema dargestellt werden:

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

Fügen Sie nach dem Abrufen des Zielendpunktarrays dem Ausgabebindungsobjekt eine endpoints-Eigenschaft hinzu. Hier sehen Sie ein JavaScript-Beispiel:

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

Für das Management SDK

Hinzufügen mehrerer Endpunkte über die Konfiguration

Verwenden Sie für die Konfiguration den Schlüssel Azure:SignalR:Endpoints als SignalR Service-Verbindungszeichenfolge. Der Schlüssel sollte das Format Azure:SignalR:Endpoints:{Name}:{EndpointType} aufweisen. Hierbei sind Name und EndpointType Eigenschaften des ServiceEndpoint-Objekts, die über den Code zugänglich sind.

Sie können Verbindungszeichenfolgen für mehrere Instanzen hinzufügen, indem Sie die folgenden dotnet-Befehle verwenden:

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>

Hinzufügen mehrerer Endpunkte über Code

Eine ServiceEndpoint-Klasse beschreibt die Eigenschaften eines Azure SignalR Service-Endpunkts. Sie können Endpunkte mit mehreren Instanzen konfigurieren, wenn Sie das Azure SignalR Management SDK verwenden:

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

Anpassen des Endpunktrouters

Standardmäßig wird vom SDK das DefaultEndpointRouter-Element verwendet, um Endpunkte zu erfassen.

Standardverhalten

  • Routing von Clientanforderungen:

    Wird verwendet, wenn Clients die Aushandlung (/negotiate) mit dem App-Server durchführen. Standardmäßig nimmt das SDK eine zufällige Auswahl eines Endpunkts aus den verfügbaren Dienstendpunkten vor.

  • Routing von Servernachrichten:

    Wenn eine Nachricht an eine bestimmte Verbindung gesendet und die Zielverbindung an den aktuellen Server geleitet wird, geht die Nachricht direkt an diesen verbundenen Endpunkt. Andernfalls werden die Nachrichten an jeden Azure SignalR-Endpunkt übertragen.

Anpassen des Routingalgorithmus

Sie können Ihre eigenen Router erstellen, wenn Sie über spezielle Kenntnisse verfügen und ermitteln können, an welche Endpunkte die Nachrichten gesendet werden sollen.

Im folgenden Beispiel wird ein benutzerdefinierter Router definiert, der Nachrichten mit einer Gruppe, die mit east- beginnt, an den Endpunkt namens east weiterleitet:

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

Im folgenden Beispiel wird das Standardverhalten für die Aushandlung außer Kraft gesetzt und der Endpunkt abhängig vom Standort des App-Servers ausgewählt.

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

Vergessen Sie nicht, den Router wie folgt für den DI-Container zu registrieren:

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

Konfiguration in regionsübergreifenden Szenarien

Das ServiceEndpoint-Objekt verfügt über eine EndpointType-Eigenschaft mit dem Wert primary oder secondary.

Primäre Endpunkte werden als Endpunkte zum Empfangen von Clientdatenverkehr bevorzugt, da sie zuverlässigere Netzwerkverbindungen aufweisen. Sekundäre Endpunkte verfügen über weniger zuverlässige Netzwerkverbindungen und werden nur für Datenverkehr vom Server zum Client verwendet. Beispielsweise werden sekundäre Endpunkte für Broadcastmeldungen und nicht für Datenverkehr vom Client zum Server verwendet.

In Fällen mit regionsübergreifender Nutzung kann das Netzwerk instabil sein. Für einen App-Server in der Region USA, Osten ist der SignalR Service-Endpunkt in derselben Region (also ebenfalls USA, Osten) primary, und die Endpunkte in anderen Regionen sind als secondary markiert. Bei dieser Konfiguration können Dienstendpunkte in anderen Regionen Nachrichten von diesem App-Server in der Region USA, Osten empfangen, aber es werden keine regionsübergreifenden Clients an diesen App-Server geleitet. Das folgende Diagramm veranschaulicht diese Architektur:

Regionsübergreifende Infrastruktur

Wenn ein Client versucht, per /negotiate die Aushandlung mit dem App-Server über den Standardrouter durchzuführen, wird vom SDK ein Endpunkt aus den verfügbaren primary-Endpunkten zufällig ausgewählt. Wenn der primäre Endpunkt nicht verfügbar ist, führt das SDK dann eine zufällige Auswahl aus allen verfügbaren Endpunkten vom Typ secondary durch. Der Endpunkt wird als verfügbar gekennzeichnet, wenn die Verbindung zwischen Server und Dienstendpunkt aktiv ist.

Wenn ein Client in einem regionsübergreifenden Szenario versucht, per /negotiate die Aushandlung mit dem App-Server durchzuführen, der in USA, Osten gehostet wird, wird standardmäßig immer der Endpunkt vom Typ primary zurückgegeben, der sich in derselben Region befindet. Falls alle Endpunkte der Region USA, Osten nicht verfügbar sind, leitet de Router den Client an die Endpunkte in anderen Regionen. Im folgenden Abschnitt Failover ist das Szenario ausführlich beschrieben.

Normale Aushandlung

Failover

Wenn kein Endpunkt vom Typ primary verfügbar ist, wird für den Client per /negotiate eine Auswahl aus den verfügbaren secondary-Endpunkten getroffen. Für diesen Failovermechanismus ist es erforderlich, dass jeder Endpunkt für mindestens einen App-Server als Endpunkt vom Typ primary dient.

Diagramm: Prozess des Failovermechanismus

Nächste Schritte

Sie können mehrere Endpunkte in Szenarien für Hochverfügbarkeit und Notfallwiederherstellung nutzen.