Partager via


Mettre à l’échelle SignalR Service avec plusieurs instances

Le SDK de SignalR Service prend en charge plusieurs points de terminaison pour les instances de SignalR Service. Vous pouvez utiliser cette fonctionnalité pour la messagerie multirégion ou pour mettre à l’échelle des connexions simultanées.

Important

Des chaînes de connexion brutes sont utilisées dans cet article à des fins de démonstration uniquement.

Une chaîne de connexion contient les informations d’autorisation requises pour que votre application accède au service Azure Web PubSub. La clé d’accès à l’intérieur dans la chaîne de connexion est semblable à un mot de passe racine pour votre service. Dans les environnements de production, protégez toujours vos clés d’accès. Utilisez Azure Key Vault pour gérer et faire pivoter vos clés en toute sécurité, et sécurisez votre chaîne de connexion en utilisant Microsoft Entra ID.

Évitez de distribuer des clés d’accès à d’autres utilisateurs, de les coder en dur ou de les enregistrer en texte brut dans un emplacement accessible à d’autres personnes. Effectuez une rotation de vos clés si vous pensez qu’elles ont pu être compromises.

Pour ASP.NET Core

Ajouter plusieurs points de terminaison à partir de la configuration

Des chaînes de connexion brutes sont utilisées dans cet article à des fins de démonstration uniquement. Dans les environnements de production, protégez toujours vos clés d’accès. Utilisez Azure Key Vault pour gérer et faire pivoter vos clés en toute sécurité, et sécurisez votre chaîne de connexion en utilisant Microsoft Entra ID.

Effectuez la configuration avec la clé Azure:SignalR:ConnectionString ou Azure:SignalR:ConnectionString: pour la chaîne de connexion de SignalR Service.

Si la clé commence par Azure:SignalR:ConnectionString:, elle doit être au format Azure:SignalR:ConnectionString:{Name}:{EndpointType}, où Name et EndpointType sont des propriétés de l’objet ServiceEndpoint et sont accessibles à partir du code.

Vous pouvez ajouter plusieurs chaînes de connexion d’instance à l’aide des commandes dotnet suivantes :

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>

Ajouter plusieurs points de terminaison à partir du code

Une classe ServiceEndpoint décrit les propriétés d’un point de terminaison Azure SignalR Service. Vous pouvez configurer plusieurs points de terminaison d’instance quand vous utilisez le SDK de Service Azure SignalR au moyen du code suivant :

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

Personnaliser le routeur de point de terminaison

Par défaut, le SDK utilise le DefaultEndpointRouter pour sélectionner les points de terminaison.

Comportement par défaut

  1. Routage des demandes du client :

    Quand le client négocie (/negotiate) avec le serveur d’applications, par défaut, le SDK sélectionne de manière aléatoire un point de terminaison dans l’ensemble de points de terminaison de service disponibles.

  2. Routage des messages de serveur :

    Quand un message est envoyé à une connexion spécifique et que la connexion cible est acheminée vers le serveur actuel, le message parvient directement à ce point de terminaison connectée. Sinon, les messages sont diffusés à chaque point de terminaison Azure SignalR.

Personnaliser l’algorithme de routage

Vous pouvez créer votre propre routeur si vous avez suffisamment de connaissances pour identifier les points de terminaison vers lesquels les messages doivent être envoyés.

L’exemple suivant définit un routeur personnalisé qui route les messages avec un groupe commençant par east- vers le point de terminaison nommé 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);
    }
}

L’exemple suivant remplace le comportement de négociation par défaut et sélectionne le point de terminaison en fonction de l’emplacement du serveur d’applications.

private class CustomRouter : EndpointRouterDecorator
{    public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
          // Sample code showing how to choose endpoints based on the incoming request endpoint query
          var endpointName = context.Request.Query["endpoint"].FirstOrDefault() ?? "";
          // Select from the available endpoints, don't construct a new ServiceEndpoint object here
          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
    }
}

N’oubliez pas d’inscrire le routeur sur le conteneur d’injection de dépendances comme suit :

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

ServiceOptions.Endpoints prend également en charge le rechargement à chaud. L’exemple de code ci-dessous montre comment charger des chaînes de connexion à partir d’une section de configuration et d’une URL publique exposées par des proxys inverses à partir d’un autre. Tant que la configuration prend en charge le rechargement à chaud, les points de terminaison peuvent être mis à jour à la volée.

services.Configure<ServiceOptions>(o =>
{
        o.Endpoints = [
            new ServiceEndpoint(Configuration["ConnectionStrings:AzureSignalR:East"], name: "east")
            {
                ClientEndpoint = new Uri(Configuration.GetValue<string>("PublicClientEndpoints:East"))
            },
            new ServiceEndpoint(Configuration["ConnectionStrings:AzureSignalR:West"], name: "west")
            {
                ClientEndpoint = new Uri(Configuration.GetValue<string>("PublicClientEndpoints:West"))
            },
        ];
});

Pour ASP.NET

Ajouter plusieurs points de terminaison à partir de la configuration

Configuration avec la clé Azure:SignalR:ConnectionString ou Azure:SignalR:ConnectionString: pour la chaîne de connexion de SignalR Service.

Si la clé commence par Azure:SignalR:ConnectionString:, elle doit être au format Azure:SignalR:ConnectionString:{Name}:{EndpointType}, où Name et EndpointType sont des propriétés de l’objet ServiceEndpoint et sont accessibles à partir du code.

Vous pouvez ajouter plusieurs chaînes de connexion d’instance à 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>

Ajouter plusieurs points de terminaison à partir du code

Une classe ServiceEndpoint décrit les propriétés d’un point de terminaison Azure SignalR Service. Vous pouvez configurer plusieurs points de terminaison d’instance quand vous utilisez le SDK de Service Azure SignalR au moyen du code suivant :

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

Personnaliser un routeur

La seule différence entre ASP.NET SignalR et ASP.NET Core SignalR est le type de contexte http pour GetNegotiateEndpoint. Pour ASP.NET SignalR, il s’agit du type IOwinContext.

Le code suivant est un exemple de négociation personnalisé pour ASP.NET SignalR :

private class CustomRouter : EndpointRouterDecorator
{
    public override ServiceEndpoint GetNegotiateEndpoint(IOwinContext context, IEnumerable<ServiceEndpoint> endpoints)
    {
        // Sample code showing how to choose endpoints based on the incoming request endpoint query
        var endpointName = context.Request.Query["endpoint"] ?? "";
        // Select from the available endpoints, don't construct a new ServiceEndpoint object here
        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
    }
}

N’oubliez pas d’inscrire le routeur sur le conteneur d’injection de dépendances comme suit :

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étriques de point de terminaison de service

Pour activer un routeur avancé, le Kit de développement logiciel (SDK) du serveur SignalR fournit plusieurs métriques pour aider le serveur à prendre des décisions intelligentes. Les propriétés sont sous ServiceEndpoint.EndpointMetrics.

Nom de métrique Description
ClientConnectionCount Nombre total de connexions clientes simultanées sur tous les hubs pour le point de terminaison de service
ServerConnectionCount Nombre total de connexions de serveur simultanées sur tous les hubs pour le point de terminaison de service
ConnectionCapacity Quota total de connexions pour le point de terminaison de service, y compris les connexions client et serveur

Le code suivant est un exemple de personnalisation d’un routeur en fonction de 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
    }
}

Points de terminaison de service de mise à l’échelle dynamique

À partir du kit de développement logiciel (SDK) version 1.5.0, nous allons commencer par activer les points de terminaison de service à l’échelle dynamique pour ASP.NET Core. Vous n’avez donc pas à redémarrer le serveur d’application lorsque vous devez ajouter/supprimer un point de terminaison de service. Comme ASP.NET Core prend en charge la configuration par défaut, comme appsettings.json avec reloadOnChange: true, vous n’avez pas besoin de modifier le code, qui est pris en charge par nature. Et si vous souhaitez ajouter une configuration personnalisée et utiliser un rechargement à chaud, reportez-vous à Configuration dans ASP.NET Core.

Remarque

Étant donné que le temps d’établissement de la connexion entre le serveur/service et le client/service peut être différent, pour garantir qu’il n’y a pas de perte de messages pendant le processus de mise à l’échelle, nous avons une période d’attente pour que les connexions du serveur soient prêtes avant d’ouvrir le nouveau point de terminaison de service aux clients. En règle générale, l’exécution du processus prend quelques secondes et vous serez en mesure de voir un message de journal comme Succeed in adding endpoint: '{endpoint}', qui indique que le processus est terminé.

Dans certaines situations attendues, telles que les problèmes réseau interrégions ou les incohérences de configuration sur différents serveurs d’applications, la période de préproduction peut ne pas se terminer correctement. Dans ces cas, il est recommandé de redémarrer le serveur d’applications lorsque vous trouvez que le processus de mise à l’échelle ne fonctionne pas correctement.

La période d’expiration par défaut de l’échelle est de 5 minutes, et elle peut être personnalisée en modifiant la valeur dans ServiceOptions.ServiceScaleTimeout. Si vous avez beaucoup de serveurs d’application, il est suggéré d’étendre la valeur un peu plus.

Remarque

Actuellement, la fonctionnalité de points de terminaison multiples est uniquement prise en charge sur le type de transport Persistent.

Pour les extensions SignalR Functions

Configuration

Pour activer plusieurs instances SignalR Service, vous devez :

  1. Utiliser le type de transport Persistent.

    Le type de transport par défaut est le mode Transient. Vous devez ajouter l’entrée suivante à votre fichier local.settings.json ou au paramètre d’application sur Azure.

    {
        "AzureSignalRServiceTransportType":"Persistent"
    }
    

    Remarque

    Lorsque vous passez du mode Transient au mode Persistent, vous pouvez constater un changement de comportement de la sérialisation JSON. En effet, dans le mode Transient, la bibliothèque Newtonsoft.Json est utilisée pour sérialiser les arguments des méthodes de hub, alors que dans le mode Persistent, la bibliothèque System.Text.Json est utilisée par défaut. System.Text.Json présente certaines différences clés dans le comportement par défaut avec Newtonsoft.Json. Si vous souhaitez utiliser Newtonsoft.Json en mode Persistent, vous pouvez ajouter un élément de configuration : "Azure:SignalR:HubProtocol":"NewtonsoftJson" dans le fichier local.settings.json ou Azure__SignalR__HubProtocol=NewtonsoftJson sur le Portail Azure.

  2. Configurer plusieurs entrées de points de terminaison SignalR Service dans votre configuration.

    Nous utilisons un objet ServiceEndpoint pour représenter une instance SignalR Service. Vous pouvez définir un point de terminaison de service avec son <EndpointName> et son <EndpointType> dans la clé d’entrée, et la chaîne de connexion dans la valeur d’entrée. Les clés sont au format suivant :

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

    <EndpointType> est facultatif et est défini par défaut sur primary. Consultez les exemples ci-dessous :

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

    Remarque

    • Lorsque vous configurez des points de terminaison Azure SignalR dans App Service sur le Portail Azure, n’oubliez pas de remplacer ":" par "__" (double trait de soulignement dans les clés). Pour savoir pourquoi, consultez Variables d’environnement.

    • La chaîne de connexion configurée avec la clé {ConnectionStringSetting} (par défaut, « AzureSignalRConnectionString ») est également reconnue comme point de terminaison de service principal avec un nom vide. Toutefois, ce style de configuration n’est pas recommandé pour plusieurs points de terminaison.

Routage

Comportement par défaut

Par défaut, la liaison de fonctions utilise le DefaultEndpointRouter pour sélectionner les points de terminaison.

  • Routage du client : sélectionnez de façon aléatoire un point de terminaison parmi les points de terminaison en ligne principaux. Si tous les points de terminaison principaux sont hors connexion, sélectionnez aléatoirement un point de terminaison en ligne secondaire. Si la sélection échoue à nouveau, l’exception est levée.

  • Routage des messages serveur : tous les points de terminaison de service sont retournés.

Personnalisation

Modèle in-process C#

Voici les étapes à suivre :

  1. Implémentez un routeur personnalisé. Vous pouvez tirer parti des informations fournies par ServiceEndpoint pour prendre une décision de routage. Consultez le guide ici : customize-route-algorithm. Notez que le déclencheur HTTP est requis dans la fonction de négociation lorsque vous avez besoin de HttpContext dans la méthode de négociation personnalisée.

  2. Inscrivez le routeur dans le conteneur DI.

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>();
        }
    }
}
Modèle de processus isolé

Pour les fonctions s’exécutant sur un modèle de processus isolé, nous prenons en charge la spécification des points de terminaison cibles dans chaque requête. Vous utiliserez de nouveaux types de liaison pour obtenir des informations sur le point de terminaison.

Acheminement client

La liaison SignalRConnectionInfo sélectionne un point de terminaison en fonction de la règle de routage par défaut. Si vous souhaitez personnaliser la règle de routage, vous devez utiliser la liaison SignalRNegotiation au lieu de la liaison SignalRConnectionInfo.

Les propriétés de configuration de la liaison SignalRNegotiation sont identiques à celles de SignalRConnectionInfo. Voici un exemple de fichier function.json :

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

Vous pouvez également ajouter d’autres données de liaison telles que userId, idToken et claimTypeList tout comme SignalRConnectionInfo.

L’objet que vous obtenez à partir de la liaison SignalRNegotiation est au format suivant :

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

Voici un exemple d’utilisation JavaScript de la liaison SignalRNegotiation :

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;
    }
}
Routage des messages

Le routage des messages ou des actions nécessite la coopération de deux types de liaisons. En général, vous avez besoin d’un nouveau type SignalREndpoints de liaison d’entrée pour obtenir toutes les informations de point de terminaison disponibles. Ensuite, vous filtrez les points de terminaison et obtenez un tableau contenant tous les points de terminaison auxquels vous souhaitez envoyer. Enfin, vous spécifiez les points de terminaison cibles dans la liaison de sortie SignalR.

Voici les propriétés de configuration de la liaison SignalREndpoints dans le fichier functions.json :

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

L’objet que vous obtenez de SignalREndpoints est un tableau de points de terminaison dont chacun est représenté en tant qu’objet JSON selon le schéma suivant :

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

Après avoir obtenu le tableau des points de terminaison cible, ajoutez une propriété endpoints à l’objet de liaison de sortie. Voici un exemple JavaScript :

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

Pour le kit de développement logiciel (SDK) Management

Ajouter plusieurs points de terminaison à partir de la configuration

Effectuez la configuration avec la clé Azure:SignalR:Endpoints pour la chaîne de connexion SignalR Service. La clé doit être au format Azure:SignalR:Endpoints:{Name}:{EndpointType}, où Name et EndpointType sont des propriétés de l’objet ServiceEndpoint et sont accessibles à partir du code.

Vous pouvez ajouter plusieurs chaînes de connexion d’instance à l’aide des commandes dotnet suivantes :

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>

Ajouter plusieurs points de terminaison à partir du code

Une classe ServiceEndpoint décrit les propriétés d’un point de terminaison Azure SignalR Service. Vous pouvez configurer plusieurs points de terminaison d’instance quand vous utilisez le kit SDK Azure SignalR Management à l’aide du code suivant :

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

Personnaliser le routeur de point de terminaison

Par défaut, le SDK utilise le DefaultEndpointRouter pour sélectionner les points de terminaison.

Comportement par défaut

  • Routage des demandes du client :

    Quand le client négocie (/negotiate) avec le serveur d’applications, par défaut, le SDK sélectionne de manière aléatoire un point de terminaison dans l’ensemble de points de terminaison de service disponibles.

  • Routage des messages de serveur :

    Quand un message est envoyé à une connexion spécifique et que la connexion cible est acheminée vers le serveur actuel, le message parvient directement à ce point de terminaison connectée. Sinon, les messages sont diffusés à chaque point de terminaison Azure SignalR.

Personnaliser l’algorithme de routage

Vous pouvez créer votre propre routeur si vous avez suffisamment de connaissances pour identifier les points de terminaison vers lesquels les messages doivent être envoyés.

L’exemple suivant définit un routeur personnalisé qui route les messages avec un groupe commençant par east- vers le point de terminaison nommé 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);
    }
}

L’exemple suivant remplace le comportement de négociation par défaut et sélectionne le point de terminaison en fonction de l’emplacement du serveur d’applications.

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

N’oubliez pas d’inscrire le routeur sur le conteneur d’injection de dépendances comme suit :

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

Configuration dans les scénarios inter-régions

L’objet ServiceEndpoint a une propriété EndpointType avec la valeur primary ou secondary.

Les points de terminaison principaux sont des points de terminaison préférés pour recevoir le trafic client, car ils ont des connexions réseau plus fiables. Les points de terminaison secondaires disposent de connexions réseau moins fiables et sont utilisés uniquement pour le serveur vers le trafic client. Par exemple, les points de terminaison secondaires sont utilisés pour diffuser des messages au lieu du trafic client vers le serveur.

Dans les cas interrégions, le réseau peut être instable. Pour un serveur d’applications situé dans USA Est, le point de terminaison SignalR Service situé dans la même région USA Est est primary et les points de terminaison dans d’autres régions marquées comme secondary. Dans cette configuration, les points de terminaison de service dans les autres régions peuvent recevoir les messages de ce serveur d’applications USA Est, mais aucun client inter-régions n’est routé vers ce serveur d’applications. Le diagramme suivant présente l’architecture :

Infrastructure multigéographique

Quand un client tente de négocier (/negotiate) avec le serveur d’applications, avec un routeur par défaut, le SDK sélectionne de manière aléatoire un point de terminaison dans l’ensemble de points de terminaison primary disponibles. Si le point de terminaison principal n’est pas disponible, le SDK effectue alors une sélection aléatoire parmi tous les points de terminaison secondary disponibles. Le point de terminaison est marqué comme disponible quand la connexion entre le serveur et le point de terminaison de service est active.

Dans un scénario multirégion, quand un client tente de négocier (/negotiate) avec le serveur d’applications hébergé dans la région USA Est, par défaut, il retourne toujours le point de terminaison primary situé dans la même région. Lorsque tous les points de terminaison USA Est ne sont pas disponibles, le routeur redirige le client vers des points de terminaison dans d’autres régions. La section de basculement suivante décrit le scénario en détail.

Négociation normale

Basculement

Lorsqu’aucun point de terminaison primary n’est disponible, le /negotiate du client choisit parmi les points de terminaison secondary disponibles. Ce mécanisme de basculement demande que chaque point de terminaison fasse office de point de terminaison primary sur au moins un serveur d’applications.

Diagramme montrant le processus du mécanisme de Basculement.

Étapes suivantes

Vous pouvez utiliser plusieurs points de terminaison dans des scénarios de haute disponibilité et de récupération d’urgence.