Simuler 10 000 connexions de périphériques Azure IoT Hub à partir d’un cluster Azure Service Fabric

Nous développons un service .Net Core qui sera hébergé dans Azure Service Fabric. Ce service SF doit pouvoir interagir avec 10 000 périphériques enregistrés dans Azure IoT Hub via ses points de terminaison TLS SSL AMQP 1.0. Chaque périphérique IoT Hub possède ses propres jetons de sécurité et chaîne de connexion fournis par le service IoT Hub.

Pour notre scénario, nous devons écouter tous les messages de cloud à périphériques provenant des 10 000 instances de périphériques IoT Hub et les “acheminer” vers un sujet central Service Bus auquel les “passerelles” réelles écoutent. Nous souhaitons donc essentiellement transférer les messages de 10 000 files d’attente de bus de service dans une queue centrale.

Quelle est la meilleure approche pour gérer ces 10 000 participants AMQP à partir d’un service SF? Existe-t-il un moyen de réutiliser des connexions, des sessions ou des liens AMQP afin de mettre en cache / partager des ressources? Et comment pouvons-nous répartir dynamicment la charge de maintenance des connexions sur les 5 nœuds du cluster SF?

Nous évaluons actuellement ces packages Nuget pour la mise en œuvre: Microsoft.Azure.ServiceBus AMQPNetLite Microsoft.Azure.Devices.Client

Nous effectuons des tests à l’aide de la bibliothèque Microsoft.Azure.Devices.Client . Voir un exemple de code simplifié ci-dessous:

 using System; using System.Fabric; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Devices.Client; using Microsoft.ServiceFabric.Services.Runtime; namespace ID.Monitoring.MonServer.ServiceFabric.ServiceBus { ///  /// An instance of this class is created for each service instance by the Service Fabric runtime. ///  internal sealed class ServiceBus : StatelessService { private readonly DeviceClient _deviceClient; private ConnectionStatus _status; public ServiceBus(StatelessServiceContext context) : base(context) { _deviceClient = DeviceClient.CreateFromConnectionSsortingng("HostName=id-monitoring-dev.azuree-devices.net;DeviceId=100;SharedAccessSignature=SharedAccessSignature sr=id-monitoring-dev.azuree-devices.net%2Fdevices%2F100&sig={token}&se=1553265888", TransportType.Amqp_Tcp_Only); } ///  /// This is the main entry point for your service instance. ///  /// Canceled when Service Fabric needs to shut down this service instance. protected override async Task RunAsync(CancellationToken cancellationToken) { _deviceClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandler); while (true) { if (_status != ConnectionStatus.Connected) { await _deviceClient.OpenAsync(); } var receivedMessage = await _deviceClient.ReceiveAsync(TimeSpan.FromSeconds(10)).ConfigureAwait(false); if (receivedMessage != null) { var messageData = Encoding.ASCII.GetSsortingng(receivedMessage.GetBytes()); //TODO: handle incoming message and publish to common await _deviceClient.CompleteAsync(receivedMessage).ConfigureAwait(false); } } } private void ConnectionStatusChangeHandler(ConnectionStatus status, ConnectionStatusChangeReason reason) { _status = status; } } } 

Question: Est-ce que cela va bien jusqu’à 10 000 instances de service Service Fabric? Ou existe-t-il des moyens plus efficaces de conserver autant de listes de bus de service AMQP à partir d’un environnement de service Service Fabric? Est-il possible d’appliquer le multiplexage de connexion AMQP?

    Jetez un coup d’oeil à ceci .

    La deuxième réponse fournit un exemple qui vous permet de multiplexer plusieurs périphériques sur une seule connexion Amqp.

    L’approche que vous choisissez pour surveiller vos appareils ne sera pas bien adaptée et sera difficile à maintenir.

    Actuellement, la structure de service limite le nombre d’instances que vous pouvez placer dans un seul nœud. Par exemple: si vous créez une application avec votre service ServiceBus et que vous étendez 10000 instances, vous atteindrez cette limitation, à savoir le nombre de nœuds. C’est-à-dire que si vous avez un cluster de 5 nœuds, vous ne pourrez exécuter que 5 instances de votre service en utilisant l’approche de dimensionnement par défaut.

    Pour contourner ce problème, vous avez quelques options:

    Partitionnement :

    Pour qu’un seul service sans état exécute plus de partitions que le nombre de nœuds, vous devez partitionner votre service. En supposant que vous avez un cluster de 5 nœuds et que vous avez besoin de 10 000 instances, vous aurez besoin de 2 000 partitions exécutées sur chaque nœud. Si vous utilisez un processus partagé et que vous avez suffisamment de mémoire vive, cette approche peut vous aider, jetez un œil à ce fil et à ce fil avant de suivre cette approche.

    Plusieurs services nommés :

    Le service nommé est la définition de service en cours d’exécution pour un type de service. Dans ce cas, vous en créez une par périphérique. comme:

    • ServiceBusType
      • ServiceBus-Device1
      • ServiceBus-Device2
      • ServiceBus-Device3

    Cette approche consum trop de ressources sur votre ordinateur, car vous allez exécuter une instance pour chaque périphérique, mais elle est facile à gérer, car vous pouvez étendre de nouvelles instances pour chaque nouveau périphérique sans affecter les autres services en cours d’exécution.

    Traitement parallèle par instance :

    Si chaque instance est responsable du traitement simultané de plusieurs messages, dans ce cas, vous créerez 2 000 connexions pour chaque instance (si vous exécutez 5 instances / nœuds par cluster). Ce sera plus léger que les autres approches sur la consommation de ressources, mais est un peu plus difficile à maintenir, car vous devrez gérer l’équilibre vous-même et aurez peut-être besoin d’un service supplémentaire pour surveiller et déléguer les tâches à tous les services et vous assurer que les messages sont bien transmis. traitement uniformément.

    Résumé:

    Une instance traitant une connexion à la fois par message nécessitera 10000 instances de votre service. Le partitionnement sera similaire, mais vous pouvez utiliser un processus partagé pour réduire la consommation de mémoire, mais la consommation de mémoire sera toujours élevée dans les deux cas.

    Plusieurs services nommés pourraient être une option si le nombre de services n’était pas trop élevé. Vous ne seriez pas non plus en mesure de partager la connexion. Donc, je ne recommanderai pas cette approche pour votre scénario.

    La troisième option est la plus conviviale en ressources, mais vous devrez trouver un moyen de partitionner les connexions de manière uniforme sur tous les nœuds du cluster.

    Vous pouvez également utiliser une approche mixte. Par exemple, vous pouvez demander à un service de gérer plusieurs messages en parallèle et à un service partitionné de définir la plage de clés de périphériques.

    S’il vous plaît jeter un oeil dans les liens que j’ai mentionnés.

    J’ai trouvé qu’il existe un constructeur DeviceClient qui permet de définir AmqpConnectionPoolSettings.