Skalierung des SignalR-Diensts 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 aus der Konfiguration
Konfigurieren Mit Schlüssel Azure:SignalR:ConnectionString
oder Azure:SignalR:ConnectionString:
für SignalR-Dienst-Verbindungszeichenfolge.
Wenn der Schlüssel mit Azure:SignalR:ConnectionString:
dem Schlüssel beginnt, sollte er sich im Format Azure:SignalR:ConnectionString:{Name}:{EndpointType}
befinden, in dem Name
es sich um Eigenschaften des ServiceEndpoint
Objekts handelt EndpointType
und über Code darauf zugreifen kann.
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 aus Code
Eine ServicEndpoint
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
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.Servernachrichtenweiterleitung:
Beim Senden einer Nachricht an eine bestimmte Verbindung und die Zielverbindung wird an den aktuellen Server weitergeleitet, wird die Nachricht direkt an diesen verbundenen Endpunkt weitergeleitet. 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 leitet, beginnend mit east-
dem Endpunkt namens 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);
}
}
Im folgenden Beispiel wird das Standard-Aushandlungsverhalten außer Kraft gesetzt und der Endpunkt abhängig vom Speicherort 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 aus der Konfiguration
Konfiguration mit Schlüssel Azure:SignalR:ConnectionString
oder Azure:SignalR:ConnectionString:
für 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 aus 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 benutzerdefiniertes Aushandlungsbeispiel 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
Um einen erweiterten Router zu aktivieren, stellt das SignalR-Server-SDK mehrere Metriken bereit, mit denen der Server intelligente Entscheidungen treffen kann. Die Eigenschaften befinden sich unter ServiceEndpoint.EndpointMetrics
.
Metrikname | Beschreibung |
---|---|
ClientConnectionCount |
Gesamtanzahl der gleichzeitigen Clientverbindungen auf allen Hubs für den Dienstendpunkt |
ServerConnectionCount |
Gesamtanzahl der gleichzeitigen 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 ClientConnectionCount
gemäß .
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
In Anbetracht der Zeit der Verbindungseinrichtung zwischen Server/Dienst und Client/Dienst kann unterschiedlich sein, um sicherzustellen, dass während des Skalierungsprozesses kein Nachrichtenverlust besteht, haben wir einen Stagingzeitraum, der darauf wartet, dass Serververbindungen bereit sind, bevor der neue ServiceEndpoint für Clients geöffnet wird. In der Regel dauert es Sekunden, bis der Vorgang abgeschlossen ist, und Sie können eine Protokollmeldung Succeed in adding endpoint: '{endpoint}'
sehen, die angibt, dass der Vorgang abgeschlossen ist.
In einigen erwarteten Situationen, z. B. regionsübergreifende Netzwerkprobleme oder Konfigurationsinkonsistenzen auf verschiedenen App-Servern, wird der Stagingzeitraum möglicherweise nicht ordnungsgemäß abgeschlossen. In diesen Fällen wird empfohlen, den App-Server neu zu starten, wenn 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.
Konfiguration in regionsübergreifenden Szenarien
Das ServiceEndpoint
-Objekt verfügt über eine EndpointType
-Eigenschaft mit dem Wert primary
oder secondary
.
Primäre Endpunkte sind bevorzugte Endpunkte, um Clientdatenverkehr zu empfangen, da sie zuverlässigere Netzwerkverbindungen haben. Sekundäre Endpunkte verfügen über weniger zuverlässige Netzwerkverbindungen und werden nur für Server-zu-Client-Datenverkehr verwendet. Sekundäre Endpunkte werden z. B. zum Übertragen von Nachrichten anstelle des Client-zu-Server-Datenverkehrs verwendet.
In regionenübergreifenden Fällen kann das Netzwerk instabil sein. Für einen App-Server in Ost-US befindet primary
sich der SignalR-Dienstendpunkt in derselben Region ost-US und Endpunkte in anderen Regionen, die als secondary
gekennzeichnet sind. In dieser Konfiguration können Dienstendpunkte in anderen Regionen Nachrichten von diesem Ost-US-App-Server empfangen, aber keine regionsübergreifenden Clients werden an diesen App-Server weitergeleitet. Das folgende Diagramm veranschaulicht diese Architektur:
Wenn ein Client mit dem App-Server mit einem Standardrouter versucht/negotiate
, wählt das SDK zufällig einen Endpunkt aus der Gruppe der verfügbaren primary
Endpunkte aus. Wenn der primäre Endpunkt nicht verfügbar ist, wählt das SDK zufällig aus allen verfügbaren secondary
Endpunkten aus. Der Endpunkt wird als verfügbar gekennzeichnet, wenn die Verbindung zwischen Server und Dienstendpunkt aktiv ist.
Wenn ein Client in einem regionsübergreifenden Szenario mit dem in Ost-USA gehosteten App-Server versucht/negotiate
, gibt er standardmäßig immer den primary
Endpunkt zurück, der sich in derselben Region befindet. Wenn alle OST-US-Endpunkte nicht verfügbar sind, leitet der Router den Client an Endpunkte in anderen Regionen um. Im folgenden Failoverabschnitt wird das Szenario ausführlich beschrieben.
Failover
Wenn kein primary
Endpunkt verfügbar ist, wählt der Client /negotiate
aus den verfügbaren secondary
Endpunkten aus. Dieser Failovermechanismus erfordert, dass jeder Endpunkt als primary
Endpunkt für mindestens einen App-Server dient.
Nächste Schritte
Sie können mehrere Endpunkte in Szenarien mit hoher Verfügbarkeit und Notfallwiederherstellung verwenden.