Introduction au scale-out dans SignalR
par Patrick Fletcher
Avertissement
Cette documentation ne concerne pas la dernière version de SignalR. Consultez ASP.NET Core SignalR.
Versions logicielles utilisées dans cette rubrique
- Visual Studio 2013
- .NET 4.5
- SignalR version 2
Versions précédentes de cette rubrique
Pour plus d’informations sur les versions antérieures de SignalR, consultez Anciennes versions de SignalR.
Questions et commentaires
Laissez vos commentaires sur la façon dont vous avez aimé ce tutoriel et sur ce que nous pourrions améliorer dans les commentaires en bas de la page. Si vous avez des questions qui ne sont pas directement liées au tutoriel, vous pouvez les publier sur le forum ASP.NET SignalR ou StackOverflow.com.
En général, il existe deux façons de mettre à l’échelle une application web : scale-up et scale-out.
- Le scale-up signifie utiliser un serveur plus grand (ou une machine virtuelle plus grande) avec plus de RAM, de processeurs, etc.
- Le scale-out signifie l’ajout de serveurs supplémentaires pour gérer la charge.
Le problème avec la montée en puissance est que vous atteignez rapidement une limite sur la taille de la machine. Au-delà, vous devez effectuer un scale-out. Toutefois, lorsque vous effectuez un scale-out, les clients peuvent être routés vers différents serveurs. Un client connecté à un serveur ne reçoit pas de messages envoyés à partir d’un autre serveur.
Une solution consiste à transférer des messages entre serveurs, à l’aide d’un composant appelé backplane. Avec un backplane activé, chaque application instance envoie des messages au fond de panier et le fond de panier les transfère aux autres instances d’application. (En électronique, un fond de panier est un groupe de connecteurs parallèles. Par analogie, un fond de panier SignalR connecte plusieurs serveurs.)
SignalR fournit actuellement trois backplans :
- Azure Service Bus. Service Bus est une infrastructure de messagerie qui permet aux composants d’envoyer des messages de manière faiblement couplée.
- Redis. Redis est un magasin clé-valeur en mémoire. Redis prend en charge un modèle de publication/abonnement (« pub/sub ») pour l’envoi de messages.
- SQL Server. Le SQL Server backplane écrit des messages dans des tables SQL. Le backplane utilise Service Broker pour une messagerie efficace. Toutefois, cela fonctionne également si Service Broker n’est pas activé.
Si vous déployez votre application sur Azure, envisagez d’utiliser le fond de panier Redis à l’aide du cache Redis Azure. Si vous déployez sur votre propre batterie de serveurs, tenez compte des SQL Server ou des backplans Redis.
Les rubriques suivantes contiennent des tutoriels pas à pas pour chaque backplane :
- Scale-out de SignalR avec Azure Service Bus
- Scale-out de SignalR avec Redis
- Scale-out de SignalR avec SQL Server
Implémentation
Dans SignalR, chaque message est envoyé via un bus de messages. Un bus de messages implémente l’interface IMessageBus , qui fournit une abstraction de publication/abonnement. Les backplans fonctionnent en remplaçant le IMessageBus par défaut par un bus conçu pour ce fond de panier. Par exemple, le bus de messages pour Redis est RedisMessageBus, et il utilise le mécanisme pub/sub Redis pour envoyer et recevoir des messages.
Chaque serveur instance se connecte au fond de panier via le bus. Lorsqu’un message est envoyé, il passe au fond de panier et le fond de panier l’envoie à chaque serveur. Lorsqu’un serveur reçoit un message à partir du backplane, il le place dans son cache local. Le serveur remet ensuite des messages aux clients à partir de son cache local.
Pour chaque connexion cliente, la progression du client dans la lecture du flux de messages est suivie à l’aide d’un curseur. (Un curseur représente une position dans le flux de messages.) Si un client se déconnecte, puis se reconnecte, il demande au bus tous les messages arrivés après la valeur du curseur du client. La même chose se produit lorsqu’une connexion utilise une interrogation longue. Une fois une longue demande de sondage terminée, le client ouvre une nouvelle connexion et demande les messages qui sont arrivés après le curseur.
Le mécanisme de curseur fonctionne même si un client est routé vers un autre serveur lors de la reconnexion. Le backplane est conscient de tous les serveurs, et peu importe le serveur auquel un client se connecte.
Limites
À l’aide d’un backplane, le débit maximal des messages est inférieur à ce qu’il est lorsque les clients communiquent directement à un nœud de serveur unique. Cela est dû au fait que le fond de panier transfère chaque message à chaque nœud, de sorte que le fond de panier peut devenir un goulot d’étranglement. La question de savoir si cette limitation est un problème dépend de l’application. Par exemple, voici quelques scénarios SignalR classiques :
- Diffusion du serveur (par exemple, ticker boursier) : les backplans fonctionnent bien dans ce scénario, car le serveur contrôle la vitesse d’envoi des messages.
- Client à client (par exemple, conversation) : dans ce scénario, le fond de panier peut être un goulot d’étranglement si le nombre de messages est mis à l’échelle avec le nombre de clients ; autrement dit, si le taux de messages augmente proportionnellement à mesure que plus de clients rejoignent.
- Temps réel à haute fréquence (par exemple, les jeux en temps réel) : un fond de panier n’est pas recommandé pour ce scénario.
Activation du suivi pour La mise à l’échelle de Signalr
Pour activer le suivi pour les backplans, ajoutez les sections suivantes au fichier web.config, sous l’élément de configuration racine :
<configuration>
<system.diagnostics>
<sources>
<source name="SignalR.SqlMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
<source name="SignalR.ServiceBusMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
<source name="SignalR.ScaleoutMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
</sources>
<switches>
<add name="SignalRSwitch" value="Verbose" />
<!-- Off, Critical, Error, Warning, Information, Verbose -->
</switches>
<sharedListeners>
<add name="SignalR-Bus"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="bus.log.txt" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
. . .
</configuration>