SlideShare une entreprise Scribd logo
1  sur  34
Télécharger pour lire hors ligne
Information et communication pour l’ingénieur
ARCHITECTURE DES APPLICATIONS POUR
L’INTERNET DES OBJETS : LES FILES DE
MESSAGES ET LE PROTOCOLE MQTT
VALENTIN TRAËN
RESPONSABLE DE L’ENSEIGNEMENT : OLIVIER FLAUZAC
CONSERVATOIRE NATIONAL DES ARTS ET METIERS
2018 - 2019
Sommaire
Introduction............................................................................................................................ 2
I - Les files de messages ........................................................................................................... 3
I.1 - Description et Architecture..................................................................................................... 3
I.2 - Différents design de mise en place de files de messages ....................................................... 9
I.3 - Avantages et inconvénients des files de messages............................................................... 12
II - Le protocole MQTT ........................................................................................................... 14
II.1 - Présentation du protocole MQTT ........................................................................................ 14
II.2 - L’architecture MQTT ............................................................................................................ 15
II.3 - Scalabilité ............................................................................................................................. 18
II.4 - Mise en pratique.................................................................................................................. 19
Conclusion............................................................................................................................. 30
31
2
L’internet des objets entraîne depuis plusieurs années des échanges d’informations entre
applications ou objets connectés de plus en plus importants. L’internet des objets fait référence à
un vaste écosystème technologique regroupant des infrastructures lourdes ou mobiles et
permettant l’échange et la valorisation des informations d’objets du quotidien. A l’instar d’Internet,
il permet la communication de très nombreux objets entre eux. Les contraintes liées à ces
mécanismes sont diverses du fait de l’absence constante de certitude concernant la connectivité
des objets à un instant t, de leur potentielle faible puissance de calcul ou de la limitation matérielle
entraînant un besoin de sauvegarde d’énergie (appareils fonctionnant sur batteries, piles). Il s’agit
cependant déjà d’une réalité permettant à un résident de contrôler ses volets à distance ou à une
grande entreprise de vérifier en temps réel la quantité de liquide contenu dans une cuve à plusieurs
milliers de kilomètres.
Dans ce document, nous nous intéresserons plus particulièrement à la façon dont ces objets
communiquent entre eux en concentrant notre étude tout d’abord sur les files de messages
permettant d’échanger des informations de façon asynchrone puis sur un protocole d’échange
implémentant un tel mécanisme, MQTT.
INTRODUCTION
3
Il est courant en informatique de devoir créer des plateformes permettant à divers
programmes, services de communiquer entre eux. Les MOM (Message Oriented Middleware ou
intergiciels à messages) sont des logiciels permettant à ces services de communiquer entre eux et
assurant plusieurs rôles. Ils sont garants de la délivrabilité de l’information : chaque message
transitant par un MOM est tracé et peut être persisté en mémoire. Le transfert est en effet
asynchrone et les applications des deux côtés du MOM n’ont pas besoin d’être connectées en
même temps afin de communiquer. Ils n’ont pas connaissance de l’information et ont juste besoin
d’un entête technique leur indiquant quoi faire du message ; ils peuvent toutefois transformer le
message afin de le rendre compatible avec l’application réceptrice.
1 - Description et Architecture
A - Introduction aux files de messages
Les files d’attente de messages (Message Queue en anglais) permettent le stockage
temporaire de messages à destination de programmes. Ceux-ci peuvent alors récupérer
l’information envoyée par le client, sans contrainte de lien réseau, d’heure d’acquittement... Il s’agit
en fait d’une technique que l’on peut facilement visualiser en la mettant en corrélation avec les
systèmes de messagerie électronique : l’émetteur envoie un message à un destinataire, message
qui sera placé dans une file d’attente (ici la messagerie du destinataire) ; ce dernier a alors la liberté
de consulter le message reçu quand bon lui semble et n’a aucune obligation d’être connecté
logiquement au réseau de l’émetteur. Dans la réalité c’est d’ailleurs ce qu’il se passe à plus grande
échelle : lorsque vous envoyez un message électronique, celui-ci rebondit de serveurs en serveurs
jusqu’à arriver à la boîte aux lettres du destinataire ; il n’est pas concevable que, parce qu’un des
nœuds n du système est indisponible à un instant t, le message ne soit pas envoyé ou que toute la
procédure doive recommencer. Ce message est donc stocké dans la file du n-1 nœud intermédiaire
jusqu’à ce que le nœud n soit de nouveau accessible.
Mais qu’est-ce qu’une file d’attente ? Une file d’attente est une file logique nommée, gérée par un
gestionnaire des files d’attentes (Queue Manager en anglais), et dont la représentation physique
peut varier : on la retrouve soit uniquement en Ram soit sur un support de stockage permanent. La
file d’attente n’est pas directement visible par les autres applications ; celles-ci s’interfacent en
effet avec la gestionnaire de files d’attente qui sert de pont à toute action sur celle-ci. Le
“producteur” alimentera cette file, le “consommateur” recevra et exploitera le message. Le
message consommé, il sera automatiquement retiré de la file de message après acquittement de
bonne réception de la part du consommateur.
Un autre composant essentiel à cette architecture peut alors être introduit : l'agent de messages
(Message broker en anglais). Il valide et transforme si besoin les messages. Il se charge de récupérer
I - Les files de messages
4
le message dans la file de messages, de le recomposer s’il a été envoyé en plusieurs parties et de le
transmettre au bon format vers la destination voulue.
Par abus de langage, on parle seulement de broker pour désigner à la fois le gestionnaire de file de
messages et l’agent de message ; tous deux sont en effet la plupart du temps intégrés dans la même
couche logicielle.
En ce début de mémoire, nous pouvons donc représenter cette architecture ainsi :
Image 1 - Schéma résumant le fonctionnement des files de messages
Il est temps de passer à un cas concret et de manipuler une file de messages. Dans la mise en
pratique qui suit, le broker RabbitMQ est utilisé. Nous communiquerons avec celui-ci grâce à l’api
Python dédiée. Voici le scénario : nous avons un thermomètre extérieur qui envoie régulièrement
la température à notre thermostat connecté afin que celui-ci ajuste au mieux la température
intérieure de notre logement. Le producteur ici est le thermomètre, le consommateur le
thermostat.
Notre environnement est vierge de toute file de message ; nous pouvons d’ailleurs le vérifier avec
l’utilitaire fourni par le broker :
60.0 seconds ...
> rabbitmqctl list_queues
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
5
Voici le programme chargé dans notre thermomètre :
Et voilà le programme chargé dans notre thermostat :
#!/usr/bin/env python
import pika
## Connexion au broker (ici localhost)
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
## Nous devons nous assurer que la file de messages
## destination existe, sinon le message ne sera pas
## transmis. Si elle est absente, elle est alors
## créée
channel.queue_declare(queue='temperature')
## Composition du message
channel.basic_publish(exchange='',
routing_key='temperature',
body='30 degres celcius')
## Acquittement de l'envoi du message
print(" Le thermomètre a transféré une température")
## Fermeture de la connexion
connection.close()
#!/usr/bin/env python
import pika
## Connexion au broker (ici localhost)
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
## Nous devons nous assurer que la file de messages
## cible existe, sinon le programme ne pourra pas
## continuer correctement
channel.queue_declare(queue='temperature')
## Déclaration et initialisation du "callback" permettant
## la récupération des messages dans la file de messages
## déclarée
def callback(ch, method, properties, body):
print("Le thermostat a reçu la température extérieure %r" %body)
channel.basic_consume(queue='temperature',
auto_ack=True,
on_message_callback=callback)
## Début de la procédure de collecte des messages
print(' Thermostat en attente de messages...')
channel.start_consuming()
6
Le thermomètre se connecte au broker et transmet le message « 30 degres Celsius » dans une file
de messages nommée « temperature ». Le thermostat se connecte lui aussi au broker et récupère
tous les messages transmis dans cette file.
Testons maintenant notre programme et indiquons au thermomètre de transmettre trois
messages :
Nous pouvons observer le résultat sur le thermostat :
Enfin, l’utilitaire du broker nous indique que nous avons désormais une file de messages nommée
« temperature » avec 0 messages :
Si nous coupons le thermostat et que le thermomètre envoie deux messages voici le résultat de la
précédente commande :
Les deux messages n’ont pas été consommés et sont bien toujours dans la file d’attente. Ils seront
traités au lancement de l’application du thermostat.
>python publisher.py
Le thermomètre a transféré une température
>python publisher.py
Le thermomètre a transféré une température
>python publisher.py
Le thermomètre a transféré une température
>python receive.py
Thermostat en attente de messages...
Le thermostat a reçu la température extérieure b'30 degres celcius'
Le thermostat a reçu la température extérieure b'30 degres celcius'
Le thermostat a reçu la température extérieure b'30 degres celcius'
>rabbitmqctl list_queues
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages
temperature 0
>rabbitmqctl list_queues
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages
temperature 2
7
B - Les protocoles utilisant les files de messages
Etant donné la multitude d’objets connectés existant de nos jours, il a été nécessaire de
fixer des normes communes afin de rendre compatibles les programmes entre eux et de pouvoir
échanger des messages quel que soit le langage de programmation utilisé. Des protocoles ont
alors vu le jour afin de standardiser ces types d’échanges.
• Le protocole AMQP :
Un protocole a été mis en place afin de standardiser les échanges de messages en utilisant une file
d’attente : AMQP (Advanced message Queuing Protocol). Développé par la banque JPMorgan
Chase, c’est un protocole ouvert dont les spécifications résultent d’un consortium international
entre plusieurs grands acteurs des technologies liées aux réseaux. Tout comme HTTP, c’est un
protocole qui comporte différents éléments de description du message et qui permet donc à
différentes applications de communiquer entre elles, quel que soit le langage utilisé pour les
programmer. Il s’agit depuis 2012 d’un standard OASIS1
approuvé par l’ISO2
en 2014.
Plusieurs typologies d’échanges résultent de la définition de ce protocole, dont les principales :
• Point to Point (signifiant « point à point ») : De nombreux producteurs et consommateurs
utilisent une file d’attente mais chaque message transmis n’est consommé que par un seul
consommateur. La file d’attente sert alors de point d’échange entre les deux parties.
• Pub-Sub (pour « publish-suscribe » signifiant « publication-abonnement ») : les
consommateurs sont abonnés à des files de messages et reçoivent l’intégralité des
messages qui y sont transmis par les producteurs. Ainsi, chaque message placé dans une
file de messages est transmis à l’ensemble des consommateurs abonnés.
Nous pouvons aussi citer la typologie Store and Forward qui correspond à notre exemple de
messagerie développé précédemment : les messages sont stockés en mémoire persistante,
récupérés et consultés par un seul consommateur qui décidera de les supprimer ou non.
AMQP permet aussi par exemple le transfert de fichiers.
Plusieurs brokers comme RabbitMQ ou OpenAMQ permettent utilisent ce protocole.
• Le protocole MQTT :
MQTT (Message Queue Telemetry Transport) est un protocole développé par IBM n’implémentant
que la typologie pub-sub. La simplification de ce protocole par rapport à AMQP et l’utilisation de
messages très légers en font un candidat idéal pour toute architecture contrainte, que ce soit à
1
OASIS (Organization for the Advancement of Structured Information Standards) : Créée en 1993, l’OASIS est
un consortium international travaillant sur la standardisation des formats d’échange ouverts.
2
ISO : L’Organisation internationale de la normalisation. Cette organisation établit et publie les normes
internationales.
8
cause du matériel ou du réseau. Il s’agit depuis 2014 d’un standard OASIS approuvé par l’ISO en
2016.
Nous reviendrons bien plus en détails sur ce protocole en deuxième partie de ce mémoire.
• Le protocole STOMP :
STOMP (Streaming Text Oriented Message Protocol) est un protocole textuel à part puisque
n’utilisant pas les files de messages mais permettant tout de même l’échange de messages entre
applications. Davantage similaire à HTTP, il permet la transmission de messages via des commandes
(comme SEND) et un entête indiquant la destination intermédiaire de ceux-ci. Cette destination
intermédiaire est gérée en interne par le broker et peut prendre différentes formes (dont la file
d’attente). Le consommateur s’abonne alors à cette destination intermédiaire.
Il est nécessaire lorsque l’on parle d’échange réseau de bien visualiser à quelle couche du modèle
OSI on fait référence. Pour rappel, la représentation OSI (Open Systems Interconnection) décrit un
modèle de communication entre composants informatiques à l’aide de « couches » permettant de
transmettre l’information :
Couche Libellé Unité d’échange
7 Application Donnée
6 Présentation Donnée
5 Session Donnée
4 Transport Segment
3 Réseau Message
2 Liaison Message
1 Physique Bit
Les trois premières couches sont des couches « matérielles » qui regroupent par exemple
respectivement les hub, switch et routeur. Les couches suivantes sont appelées les couches
« hautes » et concernent davantage l’échange des données entre des processus. Les trois
protocoles présentés précédemment sont des protocoles applicatifs liés à la couche 7 du modèle
OSI, tout comme le protocole HTTP.
Nous pouvons enfin aborder le cas de JMS qui n’est pas un protocole mais une API3
Java très
largement utilisée. JMS permet aux programmes Java de s’interfacer avec un MOM et utilise les
typologies point-to-point et pub-sub.
3
API (Application Programming Interface): L’interface de programmation applicative fournit un ensemble de classes
et de méthodes permettant d’offrir des fonctionnalités supplémentaires à un programme.
9
2 - Différents design de mise en place de files de messages
Maintenant que nous connaissons le fonctionnement des files de messages, il est
nécessaire de se pencher sur plusieurs paramètres pouvant modifier le comportement du
traitement des messages stockés en file d’attente et donc des applications les utilisant. Nous
évoquerons dans cette partie différents choix d’architectures qui peuvent faire varier du tout au
tout l’attitude applicative face à un message.
A - La notion de priorité
Imaginons un exemple de domotique simple : plusieurs appareils connectés (un
thermomètre extérieur, un thermomètre intérieur et un détecteur de fumée) alimentent une
même file de messages. Ces messages sont ensuite transmis sur notre téléphone par l’intermédiaire
d’une application les récupère à intervalles réguliers. Les thermomètres m’envoient constamment
les informations concernant les températures alors que le détecteur de fumée ne m’envoie un
message que lorsqu’une alerte est déclenchée. Il est évident qu’un message du détecteur de fumée
sera bien plus urgent que celui des thermomètres. Le message du thermomètre intérieur pourra
tout de même me donner des informations concernant la nature de l’alerte (quelque chose qui
brûle dans le four ou la pièce entière qui a pris feu). Le thermomètre extérieur lui ne me sera
d’aucune utilité. Il est donc nécessaire de définir une règle de priorisation des messages comme
suit :
Niveau de priorité 3
(critique)
Niveau de priorité 2
(majeur)
Niveau de priorité 1
(commun)
Thermomètre extérieur X
Thermomètre intérieur X
Détecteur de fumée X
Il est possible dans le protocole AMQP par exemple d’indiquer un niveau de priorité lié au message
lors de sa publication dans une file de messages. Cette information sera transmise dans l’entête du
message.
Dans l’exemple suivant, le broker RabbitMQ est de nouveau utilisé. Le code des programmes
d’envoi et de réception étant sensiblement le même que celui utilisé dans la première mise en
pratique, seules les parties changeantes ont été commentées.
Pour une raison de facilité de lecture du document, tous les messages sont envoyés depuis le même
programme. Dans la réalité évidemment, chaque appareil, enverrait son propre message.
10
Voici ce programme :
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
## Notre file de messages prend désormais en compte les priorités avec une
## priorité maximale à 3
data = dict()
data['x-max-priority'] = 3
channel.queue_declare(queue='temperature_priority', arguments=data)
## Message 1
## Définition de la priorité du message
priority = pika.spec.BasicProperties(priority=1)
channel.basic_publish(exchange='',
routing_key='temperature_priority',
body='1 - 15 degres celcius',
properties=priority)
print(" Le thermomètre extérieur a transféré une température")
## Message 2
priority = pika.spec.BasicProperties(priority=2)
channel.basic_publish(exchange='',
routing_key='temperature_priority',
body='2 - 20 degres celcius',
properties=priority)
print(" Le thermomètre intérieur a transféré une température")
# Message 3
priority = pika.spec.BasicProperties(priority=1)
channel.basic_publish(exchange='',
routing_key='temperature_priority',
body='3 - 15 degres celcius',
properties=priority)
print(" Le thermomètre extérieur a transféré une température")
## Message 4
priority = pika.spec.BasicProperties(priority=2)
channel.basic_publish(exchange='',
routing_key='temperature_priority',
body='4 - 25 degres celcius',
properties=priority)
print(" Le thermomètre intérieur a transféré une température")
## Message 5
priority = pika.spec.BasicProperties(priority=3)
channel.basic_publish(exchange='',
routing_key='temperature_priority',
body='5 - ALERTE',
properties=priority)
print(" Le détecteur de fumée a envoyé une information")
11
Le programme de réception quant à lui n’a pas été modifié si ce n’est la déclaration d’une liste de
messages assurant la gestion des priorités.
Envoyons les messages :
Dans quel ordre le consommateur les a-t-il reçus ?
L’ordre des messages a bien été respecté et notre alerte nous a été transmise en priorité.
Mais est-ce réellement toujours efficace ? Imaginons que l’alarme se déclenche au temps t, juste
après l’ingestion d’un message indiquant la température extérieure, et que le traitement d’un
message par notre application prenne en moyenne 10 secondes. Nous recevrons notre
température à t + 10 secondes et notre alarme seulement à t + 20 secondes. Rien de vraiment
alarmant ici, mais dans le cas d’un temps d’attente sur un site web, cela peut devenir très gênant.
Cette notion de priorité est intéressante donc pour trier les messages au sein d’une liste de
messages mais peut s’avérer insuffisante lors d’applications critiques.
B - Une file de messages ou plusieurs ?
Rien n’oblige nos applications à transmettre les messages dans une file de messages
unique, un design « multi-files » peut aussi être adopté. L’architecture « mono-file » présente des
avantages importants : configuration commune de tous les messages transmis (facilité d’ajout d’un
service) et maintenance simplifiée du système. Cependant, une file de message unique ne permet
pas une gestion fine des priorités ; en effet, même si cette notion de priorités existe de façon
logique dans l’entête des messages, nous avons vu précédemment qu’elle peut ne pas être la bonne
solution dans certains cas. Il est alors plus sûr et efficace de créer des silos séparés gérant chacun
un type de message. Rappelons qu’un broker est multi-threadé : il permet à un instant t le
traitement et la transmission de n messages. Reprenons notre exemple de domotique précédent
et imaginons que nous créons deux files de messages : une pour les thermomètres et une pour le
détecteur de fumée. Nous pouvons alors configurer notre broker pour que deux processus (listener
en anglais) soient chargés de récupérer et transmettre les messages venant de la file de
>python send_priority.py
Le thermomètre extérieur a transféré une température
Le thermomètre intérieur a transféré une température
Le thermomètre extérieur a transféré une température
Le thermomètre intérieur a transféré une température
Le détecteur de fumée a envoyé une information
>python receive_priority.py
Application en attente de messages...
Message reçu b'5 - ALERTE'
Message reçu b'2 - 20 degres celcius'
Message reçu b'4 - 25 degres celcius'
Message reçu b'1 - 15 degres celcius'
Message reçu b'3 - 15 degres celcius'
12
température et un processus pour la file relative au détecteur de fumée. Ainsi, les threads du
programme étant répartis, nous sommes certains qu’un thread sera toujours en attente et prêt à
distribuer le message du détecteur de fumée s’il le faut.
Au-delà du choix de technologie de transmission des messages, les choix d’architectures peuvent
être tout aussi importants et doivent être étudiés en fonction de la priorisation souhaitée des
messages. Il est tout à fait possible de coupler l’architecture « multi-files » qui créera une notion de
priorité forte avec la notion de priorité embarquée dans les messages qui permettra un
reclassement des messages dans une file d’attente commune.
C - Une file de messages et plusieurs consommateurs
Une façon efficace d’accélérer notre processus d’ingestion de messages est de distribuer
les messages d’une même file d’attente vers plusieurs consommateurs. Dans ce cas-là, chaque
consommateur récupère le dernier message non consommé (principe FIFO4
). Les messages sont
alors équitablement répartis entre les consommateurs si bien sûr le temps de traitement d’un
message est le même pour chaque consommateur. Si toutefois nous avons besoin que l’information
soit décuplée et que chaque consommateur reçoive l’intégralité des messages (si nous voulons que
notre thermostat et que notre application mobile reçoive toutes les notifications liées aux
températures), il est possible d’utiliser la typologie pub-sub évoquée précédemment ; cette
typologie sera plus largement détaillée en deuxième partie de document.
3 - Avantages et inconvénients des files de messages
A - Avantages liés à l’utilisation des files de messages
De nombreux avantages découlent de l’utilisation d’une telle architecture. Nous pouvons
tout d’abord citer la redondance due à la persistance des données en file de messages ; en effet, si
un consommateur n’est pas disponible, un autre pourra prendre le relai et interpréter l’information.
L’acquittement permettra d’ailleurs d’être certain de la prise en compte du message. Si toutefois
aucun consommateur n’est disponible, le message ne sera pas perdu puisque persisté en mémoire,
en attente d’être consommé. La possibilité de parallélisation de l’ingestion des messages est aussi
un point important : il n’y a pas à attendre pour chaque message un acquittement pour lancer le
traitement du message suivant, ceux-ci peuvent être traités en même temps par différents
processus tout en conservant la cohérence de l’information. Cette gestion des messages permet
aussi une meilleure anticipation des pics de trafic que peut subir une application ; quel que soit le
nombre de messages reçus, ils seront traités de la même façon, « limitée » par le nombre de
consommateurs. La gestion de ces messages sera alors peut-être plus longue que d’habitude mais
sera faite dans tous les cas. Comme nous l’avons vu avec la notion de priorité et de multiplication
4
FIFO (First In First Out) : Se dit d’une structure de données dans laquelle le premier élément extrait est le
premier élément inséré.
13
de files de messages, cette architecture peut permettre un meilleur temps de réponse de pages
web par exemple en priorisant certaines tâches par rapport à d’autres. Bien sûr, comme introduit
en début de mémoire, un des avantages forts des files de messages est l’option offerte à un
producteur de délivrer une information sans délai à un instant t sans avoir à prendre en compte
l’état du consommateur à ce même instant. La scalabilité5
d’un tel système est enfin évidente : il
est aisé d’ajouter un consommateur faisant exactement le même travail qu’un autre, permettant
alors l‘accélération du temps de traitement des messages en file d’attente. Cette technologie est
beaucoup utilisée dans le cas d’applications à micro-services : chaque élément de l’application est
indépendant et permet ainsi en cas de panne de n’avoir qu’une seule partie de celle-ci non
fonctionnelle.
B - Inconvénients liés à l’utilisation des files de messages
Un inconvénient de ce type d’architecture est sa lourdeur de mise en place ; en effet, on
ajoute une couche applicative et de nombreux processus associés qui doivent être monitorés. Dans
le cas d’applications critiques, la persistance des données ne peut avoir lieu seulement en stockant
les données en file : une architecture physique (disques RAID, redondance des serveurs) et logique
(clustering des données persistées) doit être mise en place. La configuration applicative est aussi
plus complexe : au lieu de configurer un émetteur et un consommateur, il est nécessaire d’en
configurer n de chaque côté, en fonction du besoin.
5
Scalabilité (néologisme provenant du terme anglais scalability) : Capacité d’un système à s’adapter à la
montée en charge et à maintenir des temps de réponse acceptables.
14
Comme nous l’avons vu dans la partie précédente, la forte augmentation des objets
communiquant par l’intermédiaire de files de messages a nécessité la mise en place de règles afin
de normaliser ces échanges. Des protocoles ont alors vu le jour et ont permis une standardisation
des méthodes de gestion des files de messages : MQTT est l’un d’entre eux.
1 - Présentation du protocole MQTT
MQTT est un protocole d’échange de message basé sur les files de messages initialement
développé par IBM et open source. Il se veut être très léger et simple afin de pouvoir être utilisé et
embarqué sur des appareils avec très peu de capacités de calcul comme de simples capteurs.
Comme nous l’avons vu précédemment, comme tout protocole basé sur les files de messages, il
permet de connecter de nombreux appareils à une même source d’information (la file de messages)
même dans des environnements contraints (pas de réseau ou réseau lent). Contrairement à AMQP,
il n’implémente que la typologie pub-sub ; nous ne parlerons donc plus de consommateurs (même
s’ils le restent) mais d’« abonnés » dans cette partie. Pour rappel, le principe de cette typologie
d’échange est d’alimenter une liste de messages (un « topic ») à laquelle un certain nombre
d’abonnés ont souscrit afin de recevoir tous les messages y étant transmis. Nous verrons plus tard
que la notion de topic est en fait un peu plus évoluée et permet l’utilisation d’une syntaxe
particulière. Les messages stockés dans des topics ne sont pas forcément épurés comme ils peuvent
l’être avec une typologie point-to-point afin de permettre aux nouveaux abonnés ou abonnés non
connectés de récupérer le dernier message posté. MQTT permet enfin trois niveaux de QoS6
faisant
varier les exigences concernant la délivrabilité des messages.
Nous pouvons citer quelques brokers MQTT comme Mosquitto, JoramMQ, Really Small Message
Broker ou ActiveMQ qui sont tous open-sources.
Dans ce document, nous développerons la version 3.1.1 de ce protocole puisqu’il s’agit de la version
implémentée dans la plupart des brokers au moment de sa rédaction. Il est tout de même important
d’indiquer qu’une version 5.0 existe et qu’elle est officiellement devenue un standard OASIS le 03
avril 2019.
6
QoS (Quality of Service) : La qualité de service est la priorisation de certains services et l’adaptation de
contraintes fortes afin de maintenir un niveau de qualité constant préalablement défini
II - Le protocole MQTT
15
2 - L’architecture MQTT
A - La typologie pub-sub
Nous allons dans cette partie revenir plus précisément sur cette typologie particulière et
définir les différents concepts qui en font un moyen d’échange de messages à part. Ici aussi
l’émetteur n’a pas besoin de connaître l’identité des abonnés qui récupèreront les messages, leur
point de communication est le topic et donc le broker. Comme nous l’avons vu dans la première
partie de ce mémoire, c’est le broker qui est chargé de récupérer les messages dans le topic et de
les transmettre aux différents abonnés. On se retrouve donc avec une typologie similaire à celle en
point-to-point si ce n’est la distributivité des messages qui se fait sur l’ensemble des abonnés.
Un autre apport est la possibilité de communication inter-brokers ; ainsi, un abonné pourra
récupérer les messages d’un topic géré par un autre broker sans avoir de nouvelle connexion à
ouvrir.
Intéressons-nous maintenant à la notion de topic. Depuis le début de cette partie, nous avons
considéré qu’un topic était l’équivalent d’une file de messages à laquelle on s’abonnait ; c’est en
fait un peu plus complexe que cela. Il faut vraiment considérer le mot topic à son sens littéral : sujet,
thème. Lorsqu’un émetteur publie un message, il indique le thème de son message qui sera classé
dans une file de messages dont l’intitulé est alors compréhensible de tous. Ces topics sont organisés
de façon hiérarchique en arbres, du sujet le plus global au plus précis. L’intérêt de cette organisation
est la possibilité de souscrire un abonnement à un « groupe » de topics sans forcément connaître
le nom de chacun ou simplement pour recevoir tous les messages relatifs à un sujet global. Une
syntaxe dédiée permet la manipulation de ces groupes :
- on peut créer ou naviguer dans un topic grâce au caractère « / ». Ainsi, nous pourrons créer
un topic « maison » contenant un topic « température » contenant lui-même un topic
« température_intérieure ». Nous noterons alors cette arborescence ainsi :
maison/température/température_intérieure.
- un abonné peut souscrire à plusieurs topics en même temps en utilisant le caractère « # ».
Notre thermostat pourra alors être abonné à maison/température/#, recevant les
messages provenant de maison/température et maison/température/température_
intérieure.
- A contrario, le caractère « + » peut être utilisé afin de limiter l’abonnement à une strate de
l’arborescence. Notre utilisateur ne voudra peut-être pas recevoir toutes les notifications
détaillées relatives à son habitation mais des informations plus générales ; il pourra alors
s’abonner à maison/+ et ne recevra pas de notifications provenant d’un niveau plus bas
que maison/température.
B - Les messages MQTT
Il est possible d’indiquer lors de la publication d’un message si celui-ci devra être maintenu
dans le topic afin d’être transmis plus tard aux abonnés non connectés. Pour ce faire, il est
nécessaire d’alimenter la variable de rétention : retain. Initialisée à false, le message ne sera pas
16
conservé, à true il le sera. Un seul message peut être conservé par topic et le restera tant qu’il
n’aura pas été remplacé ou supprimé explicitement. Ce message peut servir à maintenir la dernière
information en mémoire afin de permettre à tous les nouveaux abonnés d’être à jour ou
simplement pour leur indiquer que leur connexion au topic a bien été faite. Il s’agit aussi d’un
moyen pour l’émetteur d’être sûr que le message sera bien remis à tous les abonnés.
Il est aussi possible de définir un niveau de QoS grâce à la variable qos. Initialisée à 1, le
broker s’assurera que le message soit au moins transmis une fois à l’abonné avant de le supprimer,
initialisée à 2 que le message soit transmis exactement une fois à l’abonné avant d’être supprimé.
Dans le cas où cette variable est initialisée à 0, le gestionnaire fera son possible pour remettre le
message aux abonnés mais rien n’est garanti.
Ce fonctionnement s’explique du fait des messages échangés dans chaque cas :
Image 2 - Schéma montrant les messages échangés en fonction du niveau de QoS configuré
• QoS = 0 : l’émetteur transmet le message au broker (PUBLISH) qui n’accuse pas réception.
• QoS = 1 : l’émetteur transmet le message au broker (PUBLISH) qui accuse réception
(PUBACK pour Publish acknowledgement). Si l’émetteur ne reçoit pas de message PUBACK
dans un délai imparti, il retransmet un message PUBLISH.
• QoS = 2 : l’émetteur transmet le message au broker (PUBLISH) qui indique l’avoir reçu
(PUBREC pour Publish received). Si l’émetteur ne reçoit pas le message PUBREC, il renverra
le message via un message PUBLISH en indiquant qu’il s’agit d’un message dupliqué (flag
PUB). S’il reçoit la message PUBREC, l’émetteur sait qu’il peut supprimer le message
PUBLISH de son côté. Il envoie alors un message PUBREL (pour Publish release) indiquant
au broker de « libérer » le message. Le broker transmet alors un message PUBCOM (pour
Publish complete) indiquant que le message a été transmis au topic. Pendant cette
publication de message PUBCOMP, le broker stocke temporairement l’identifiant du
message provenant du message initial PUBLISH afin d’assurer de ne le transmettre qu’une
fois aux abonnés.
Nous ne parlons ici que de l’échange émetteur – broker. Il existe néanmoins le même type
d’échange entre le broker et l’abonné mais c’est à l’abonné d’indiquer le niveau maximal de QoS
qu’il souhaite avoir avec le broker ; ainsi, il pourra tout à fait recevoir un message envoyé par
17
l’émetteur avec un QoS = 1 s’il s’est abonné au topic avec un niveau de QoS à 0. L’émetteur aura la
certitude que son message aura été remis au broker au moins une fois mais le broker ne pourra pas
assurer à 100% la remise du message à l’abonné avec lequel il n’échangera qu’un message PUBLISH.
Une règle est à retenir : le niveau de QoS maximum atteignable pour transférer un message du
broker à l’abonné est égal au niveau de QoS choisi par l’émetteur pour envoyer son message. En
effet, si le message a d’abord été transmis avec un flag QoS à 0, le broker ne peut pas garantir de
transmettre le message à l’abonné. S’il a été transmis avec un flag QoS à 1, il ne peut pas garantir
de transférer le message une seule fois à l’abonné, étant donné qu’il pourra lui-même le recevoir
plusieurs fois. Il est aussi important de noter que l’utilisation du paramètre qos n’influe pas sur le
stockage du message. En effet, en cas de redémarrage du broker, nouvelle connexion ou
reconnexion d’un client, il est nécessaire de jouer sur le paramètre retain afin de s’assurer de la
délivrabilité du message. Il est aussi possible d’influer sur ce comportement grâce au paramètre
clean_session que nous verrons dans la partie suivante.
C - Les clients MQTT
Il est tout à fait possible de configurer les clients MQTT (émetteurs de messages et abonnés)
dans le but d’adopter différents comportements lors de leur connexion/déconnexion au broker.
L’identification du client par le broker se fait par un identifiant unique composé de 23 octets
(possibilité d’en ajouter 17 pour obtenir un identifiant plus explicite) transmis lors d’un message de
connexion CONNECT. Lorsqu’une connexion s’ouvre, l’identification du client se fait donc pas la
lecture de cette chaîne unique. Le broker peut alors savoir si ce client s’est déjà connecté et dans
quel état il a souhaité conserver ou non sa session :
- si le paramètre clean_session a été initialisé à true, toute information concernant ce client
est supprimée du serveur (le broker) lors de sa déconnexion. C’est le paramètre par défaut.
- si le paramètre clean_session est à false, l’ancienne session est conservée à la déconnexion
par le broker et réouverte lors de la prochaine connexion du client. On agit alors comme si
le client ne s’était jamais déconnecté.
Les conséquences de ces paramètres diffèreront donc en fonction du rôle de notre client. S’il s’agit
d’un client publiant des messages, ce paramètre n’aura d’utilité qu’avec le paramètre qos à 1 ou 2
appliqué aux messages. En effet, si aucun acquittement n’est demandé au broker, le message avec
un niveau de QoS à 0 sera marqué comme envoyé. S’il s’agit d’un abonné, clean_session = true
résultera en la remise à zéro de tous les abonnements de la session précédente. A la reconnexion,
le client ne sera donc plus abonné à aucun topic.
Comme nous l’avons évoqué précédemment, lorsqu’un client se connecte au serveur, il envoie un
message CONNECT. Un message CONNACK (pour Connect acknowledge) est alors transmis par le
broker en réponse comportant plusieurs informations :
- le flag « session present » sera utilisé en cas de déconnexion précédente avec le paramètre
clean_session à false. Ce flag permet d’indiquer au client si les abonnements pourront bien
être restaurés depuis la session précédente ou si le client doit indiquer à quels topics il veut
se réabonner.
- Un code de retour est aussi chargé dans ce message : 0 si la connexion est acceptée, 1, 2 3,
4 ou 5 si elle est refusée. Elle peut l’être pour diverses raisons : problème de version de
protocole MQTT déclarée, refus de l’identifiant du client, service MQTT non disponible…
18
Quand utiliser ce paramètre ? Il peut être utile de positionner clean_session à false si un abonné
doit recevoir tous les messages d’un topic même en cas de déconnexion ou s’il s’agit d’un appareil
à ressources très limitées (comme un capteur) à qui on « épargne » l’envoi de messages
d’abonnements dès qu’il se reconnecte. Au contraire, si l’abonné n’a pas besoin de recevoir tous
les messages, conserver ce paramètre à true permet une charge moins importante au broker ; il en
va de même s’il s’agit seulement d’un émetteur.
Il existe une notion de dernière volonté (« last will and testament ») permettant de configurer
l’envoi automatique d’un message dans un topic si jamais la connexion du client est perdue. On
peut aussi indiquer la valeur de QoS voulue pour ce message.
Enfin, de même que pour la connexion, pour un client abonné, la souscription à un topic se fait
via l’envoi d’un message SUBSCRIBE indiquant le topic auquel l’abonné veut accéder. Ce message
comporte aussi la valeur maximale de QoS souhaitée lors de la réception d’un message. En réponse,
l’abonné reçoit un message SUBACK (pour Subscribe acknowledge) confirmant la prise en compte
de la demande d’abonnement.
3 - Scalabilité
Lorsque nous parlons de MQTT, nous restons très fortement liés à l’internet des objets et
donc à la multiplication d’applications, services, objets pouvant communiquer entre eux. Nous ne
sommes plus à l’échelle de notre petit exemple de domotique désormais mais plutôt à celle du
vendeur de thermomètres connectés qui reçoit des informations de la part de l’intégralité des
objets vendus. Par exemple, il peut recevoir régulièrement la version du micrologiciel embarqué
dans ses thermomètres afin d’établir une cartographie des appareils non mis à jour. Les temps de
réponse du serveur MQTT devant rester les mêmes que l’entreprise ait vendu 10 thermomètres
ou 10000, il est nécessaire d’avoir une architecture scalable. La scalabilité peut être verticale
(ajouter de la puissance de calcul au serveur MQTT) ou horizontale (multiplier les serveurs MQTT
afin d’y répartir la charge). Pour des raisons de coût, d’efficacité, de QoS, de flexibilité, la seconde
approche est bien souvent celle privilégiée. Nous avons vu précédemment qu’un abonné
interrogeant un topic pouvait recevoir des réponses de plusieurs brokers, ceux-ci ayant la
possibilité d’être reliés entre eux par un système de pont. C’est donc ici aussi la scalabilité
horizontale qui est choisie. On répartit ainsi la charge de calcul du broker mais doublons l’espace
de stockage nécessaire. Attention cependant, on introduit avec ce système de nouvelles
contraintes réseau (entre les brokers) et de persistance des données dans le cas où un broker
tombe en panne.
Il est tout de même important de préciser que la plupart des brokers MQTT du marché ont été
conçus pour être capable de recevoir de très nombreuses connexions de clients sur une
architecture serveur « classique » qui peut être améliorée si besoin ; la scalabilité verticale est
donc aussi tout à fait possible.
19
4 - Mise en pratique
Il est désormais temps de mettre en pratique ce qui a été expliqué plus tôt et de manipuler
le protocole MQTT. Pour ce faire, le broker Mosquitto sera utilisé. Le langage utilisé par les clients
sera Python. Chaque exemple sera associé à une mise en situation reprenant notre architecture de
domotique présentée jusqu’alors.
A - Mise en place d’un échange MQTT
Commençons par la mise en place d’une architecture pub-sub basique. Dans cet exemple,
nous souhaitons simplement qu’un publisher (notre thermomètre) envoie une température à deux
subscribers (le thermostat et l’application mobile). Pour le moment seul le topic
maison/temperature/temperature_exterieure est alimenté.
Le programme d’envoie des messages :
Notre client « thermometre » publie le message « 15 » dans le topic
maison/temperature/temperature_exterieure.
import paho.mqtt.client as mqtt
################################################
###fonction dédiée à la lecture des logs########
def on_log(client, userdata, level, buf):
print("log: ",buf)
################################################
#céeation d une instance
client =mqtt.Client("thermometre")
#activation des logs
client.on_log=on_log
#connexion au broker
client.connect("localhost",1883)
#publication d un message
client.publish("maison/temperature/temperature_exterieure","15")
20
Voici maintenant le programme d’abonnement au topic et réception des messages :
Notre client « thermostat » souscrit au topic « maison/temperature/temperature_exterieure » et
affiche les messages reçus à la réception de ceux-ci. Un deuxième programme a été écrit pour
l’application mobile mais seule la ligne « client =mqtt.Client("application_mobile") » diffère du
précédent programme.
Testons maintenant nos programmes. Nous ouvrons les connexions des clients abonnés en premier
lieu puis lançons la publication du message.
import paho.mqtt.client as mqtt
################################################
###fonction dédiée à la lecture des messages####
def on_message(client, userdata, message):
print("message reçu : " ,str(message.payload.decode("utf-8")))
print("topic : ",message.topic)
print("niveau de QoS : ",message.qos)
print("rétention : ",message.retain)
###fonction dédiée à la lecture des logs########
def on_log(client, userdata, level, buf):
print("log: ",buf)
################################################
#creation d une instance
client =mqtt.Client("thermostat")
#activation des logs
client.on_log=on_log
#connexion au broker
client.connect("localhost",1883)
#publication d un message
client.subscribe("maison/temperature/temperature_exterieure")
#boucle de lecture des messages
client.on_message=on_message
client.loop_forever()
> python publisher.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre'
log: Sending PUBLISH (d0, q0, r0, m1), 'b'maison/temperature/temperature_exterieure'', ... (2 bytes)
21
Le message est reçu par nos deux abonnés :
Intéressons-nous maintenant aux syntaxes « topic/# » et « topic/+ » ; pour rappel, ces syntaxes
permettent de s’abonner respectivement à l’ensemble des topics de la sous-arborescence
représentée par « # » et aux topics présents au même niveau de l’arborescence que celui
représenté par « + ». Pour ce faire, nous modifions temporairement le code de notre
thermomètre afin de lui faire publier 4 messages :
Nous introduisons ici deux nouveaux topics : maison/temperature/temperature_interieure qui se
trouve au même niveau que maison/temperature/temperature_exterieure et maison/alarme qui
se trouve au même niveau que maison/temperature. Des messages sont publiés dans chacun de
ces topics.
Le thermostat est désormais abonné à tous les topics de la branche maison/temperature :
> python receive1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 0
rétention : 0
> python receive2.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'application_mobile'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 0
rétention : 0
client.publish("maison/temperature/temperature_exterieure","20")
client.publish("maison/temperature/temperature_interieure","18")
client.publish("maison/temperature","TEMP")
client.publish("maison/alarme","ALERTE")
client.subscribe("maison/temperature/#")
22
Publions nos quatre messages :
Voici les messages reçus par notre abonné :
Seuls les messages relatifs à la gestion de la température ont été transmis.
Tous les messages ont été reçus sauf ceux envoyés dans le topic maison/alarme qui ne
correspondait pas à l’abonnement.
Modifions maintenant l’abonnement ainsi :
> python publisher.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre'
log: Sending PUBLISH (d0, q0, r0, m1), 'b'maison/temperature/temperature_exterieure'', ... (2 bytes)
log: Sending PUBLISH (d0, q0, r0, m2), 'b'maison/temperature/temperature_interieure'', ... (2 bytes)
log: Sending PUBLISH (d0, q0, r0, m3), 'b'maison/temperature'', ... (4 bytes)
log: Sending PUBLISH (d0, q0, r0, m4), 'b'maison/alarme'', ... (6 bytes)
> python receive1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/#', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes)
message reçu : 20
topic : maison/temperature/temperature_exterieure
niveau de QoS : 0
rétention : 0
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_interieure', ... (2 bytes)
message reçu : 18
topic : maison/temperature/temperature_interieure
niveau de QoS : 0
rétention : 0
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature', ... (4 bytes)
message reçu : TEMP
topic : maison/temperature
niveau de QoS : 0
rétention : 0
client.subscribe("maison/+")
23
Désormais, l’abonné ne devrait recevoir que les messages relatifs à la maison sans entrer dans le
détail des températures. Vérifions cela :
Enfin, un abonné peut se désabonner d’un topic ainsi :
Dans les exemples précédents, nous avons pu voir afficher dans les logs les différents types de
messages MQTT échangés lors de la publication des messages.
B - Attribution de variables aux messages
Si un nouveau client s’abonne au topic ou qu’un abonné se connecte après envoi du
message par l’émetteur, il ne recevra pas cette information. En effet, elle n’est pas maintenue en
mémoire étant donné que nous n’avons pas demandé à l’émetteur d’envoyer l’information de
persistance au broker. Pour ce faire, nous allons manipuler la variable de rétention. La
publication du message a été modifiée comme suit :
Pour le test suivant, la connexion du thermostat est ouverte au moment de l’envoi du message
mais pas celle de l’application mobile. Nous testons donc la bonne réception du message sur
l’application mobile lors de sa connexion.
> python receive1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/+', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature', ... (4 bytes)
message reçu : TEMP
topic : maison/temperature
niveau de QoS : 0
rétention : 0
log: Received PUBLISH (d0, q0, r0, m0), 'maison/alarme', ... (6 bytes)
message reçu : ALERTE
topic : maison/alarme
niveau de QoS : 0
rétention : 0
client.unsubscribe("maison/temperature/temperature_exterieure")
client.publish("maison/temperature/temperature_exterieure","15",retain=True)
24
Sur le thermostat :
Sur l’application mobile :
On constate que le message ayant été transmis « en direct » au thermostat, le flag de rétention
est à 0. Cependant, le message transmis à l’application mobile est quant à lui bien un message
ayant été stocké temporairement par le broker : le flag est à 1.
Si nous n’avions pas indiqué au broker de garder en mémoire le message, celui-ci n’aurait pas été
transmis à la connexion de l’application mobile car le message aurait été supprimé. A partir de
maintenant, la variable de rétention est remise à false.
Modifions maintenant le niveau de QoS afin de le mettre à 1 (pour faciliter la lecture de ce
rapport, nous considérons qu’un flag QoS = 1 correspond à l’initialisation de cette variable à 1
pour les échanges émetteur – broker et broker – abonné). Pour rappel, le niveau 1 garantit la
délivrabilité du message au minimum une fois. Dans ce scénario, notre application mobile sera
mise hors ligne juste avant l’envoi du message afin qu’elle ait pu indiquer la valeur de QoS désirée
pour la réception des messages. Nous enverrons tout d’abord le message depuis le thermomètre,
lirons le résultat sur le thermostat, et démarrerons enfin le service lié à l’application mobile. Si le
niveau de QoS est respecté, l’application mobile devrait recevoir le message à sa connexion à
condition qu’il ait été indiqué au broker de conserver un historique de la session.
> python receive1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 0
rétention : 0
> python receive2.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'application_mobile'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q0, r1, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 0
rétention : 1
25
Les lignes suivantes ont préalablement été modifiées :
• Sur le thermomètre :
• Sur le thermostat et l’application mobile :
Dans la déclaration du client, le paramètre « False » indique de conserver un historique de la
session à la déconnexion.
Le résultat obtenu est-il le bon ?
Publication du message :
On peut vérifier le niveau de QoS avec lequel le message a été envoyé grâce au paramètre « q1 »
(pour QoS = 1).
Réception « en direct » sur le thermostat :
client.publish("maison/temperature/temperature_exterieure","15",qos=1)
#Sauvegarde de la session
client =mqtt.Client("thermostat",False)
#Souscription aux messages allant jusqu’à un QoS = 1
client.subscribe("maison/temperature/temperature_exterieure",1)
> python publisher.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre'
log: Sending PUBLISH (d0, q1, r1, m1), 'b'maison/temperature/temperature_exterieure'' (NULL
payload)
log: Received CONNACK (0, 0)
log: Received PUBACK (Mid: 1)
> python subscriber_1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 2)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Sending PINGREQ
log: Received PINGRESP
log: Received PUBLISH (d0, q1, r0, m1), 'maison/temperature/temperature_exterieure', ... (2 bytes)
log: Sending PUBACK (Mid: 1)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 1
rétention : 0
26
Réception différée sur l’application mobile à son démarrage :
Si le message a été reçu même après la déconnexion de l’abonné c’est parce que nous avons
préalablement indiqué au broker de sauvegarder l’état de la session ; le message est alors transmis
à l’abonné puisque lors de sa connexion, le flag « session present » du message CONNACK est
initialisé à true et le broker considère qu’il s’agit d’une session « sans coupure ».
Image 3 - Extrait du message CONNACK transmis lors de l'échange
> python subscriber_2.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'application_mobile'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 1)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q1, r1, m1), 'maison/temperature/temperature_exterieure', ... (2 bytes)
log: Sending PUBACK (Mid: 1)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 1
rétention : 0
27
Etudions maintenant les messages MQTT échangés lors de la remise de ce message :
Image 4 - Echange de messages avec un niveau de QoS fixé à 1
On constate le double échange de messages dû au niveau de QoS choisi ainsi que le contenu du
message embarqué dans le message MQTT PUBLISH. On remarque aussi dans l’ensemble de ces
messages un id (id = 1) qui correspond à l’identifiant unique du message dans le topic. On
retrouve d’ailleurs cette information lors de la réception d’un message par un abonné (mid : 1).
Ce test se comporte de façon identique avec un niveau de QoS à 2.
> python publisher.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre'
log: Sending PUBLISH (d0, q2, r1, m1), 'b'maison/temperature/temperature_exterieure'' (NULL
payload)
log: Received CONNACK (0, 0)
log: Received PUBREC (Mid: 1)
log: Sending PUBREL (Mid: 1)
log: Received PUBCOMP (Mid: 1)
> python subscriber_1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 2)]
log: Received CONNACK (0, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q2, r0, m1), 'maison/temperature/temperature_exterieure', ... (0 bytes)
log: Sending PUBREC (Mid: 1)
log: Received PUBREL (Mid: 1)
message reçu : 15
topic : maison/temperature/temperature_exterieure
niveau de QoS : 2
rétention : 0
log: Sending PUBCOMP (Mid: 1)
28
On reconnaît bien ici le quadruple échange de messages MQTT lié à ce niveau de QoS :
Image 5 - Echange de messages avec un niveau de QoS fixé à 2
Enfin, nous allons tester le mécanisme de « last will and testament » permettant à un client se
déconnectant de déposer un message dans un topic. Dans notre cas, nous voulons prévenir notre
application mobile de la déconnexion du thermomètre. Voici comment est mise en place cette
fonctionnalité dans le code du client :
Lorsque nous déconnectons le thermomètre, le message est bien reçu par les abonnés :
client.will_set("maison/temperature/temperature_exterieure","Je suis déconnecté", qos=1)
> python subscriber_1.py
log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat'
log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 1)]
log: Received CONNACK (1, 0)
log: Received SUBACK
log: Received PUBLISH (d0, q1, r1, m36472), 'maison/temperature/temperature_exterieure', ...
(20 bytes)
log: Sending PUBACK (Mid: 36472)
message reçu : Je suis déconnecté
topic : maison/temperature/temperature_exterieure
niveau de QoS : 1
rétention : 0
29
Le message délivré est un message comme un autre, envoyé selon le niveau de QoS choisi. Nous
pouvons cependant constater dans le message de connexion du thermomètre le paramètre
indiquant qu’il s’agit d’un message à remettre en cas de déconnexion :
Image 6 - Publication d'un message de "dernière volonté"
Ces différentes mises en pratiques, au-delà d’illustrer différents concepts inhérents au protocole
MQTT, montrent aussi la facilité de mis en œuvre de messages utilisant cette technologie. Très peu
de paramètres sont nécessaire à la publication des messages, très peu de manipulations sont
requises de la part des clients. MQTT se veut être simple à appréhender et ne nécessite pas de
connaissances particulières en réseau.
30
L’internet des objets nous a forcé à repenser la manière dont les applications pouvaient
communiquer entre elles. Les entreprises ont dû s’adapter à des échanges qu’elles ne maîtrisaient
pas du fait de l’externalisation de leurs produits et de la multiplication de ceux-ci. Comment
s’assurer que l’information soit reçue de la même façon à plusieurs milliers de kilomètres de
distance, sur des appareils dont nous ne connaissons pas la nature, connectés à des réseaux
inconnus ? Les protocoles conventionnels n’ont pas été conçus pour des domaines aussi variés
que ceux que l’on retrouve dans l’internet des objets, entraînant des consommations trop élevées
et des difficultés de mise en place dues à la complexité de leur utilisation. Les files d’attente de
messages offrent une alternative intéressante aux protocoles « classiques » concernant l’échange
de messages en milieu contraint. Elles offrent un échange asynchrone d’information, permettant
alors à un processus de ne pas être totalement stoppé en cas de défaillance d’une partie du
système. Elles introduisent cependant de nouvelles couches logicielles qu’il faut pouvoir et savoir
maintenir en production. Des règles d’échange ont alors dû être mises en place afin de
standardiser les communications et permettent la compatibilité des produits entre eux. Nous
pouvons tout de même nous interroger sur les ressources machines requises pour la mise en
place de tels systèmes : si bien sûr, l’internet des objets a introduit des composants très peu
énergivores et que certains d’entre eux permettent même la gestion de l’énergie de composants
plus classiques, qu’en est-il de la démultiplication des brokers nécessaires au bon fonctionnement
des files de messages ?
CONCLUSION
31
Amazon - Files d'attente de messages - https://aws.amazon.com/fr/message-queue/ -
aws.amazon.com
Amazon - Pub/Sub Messaging - https://aws.amazon.com/fr/pub-sub-messaging/ -
aws.amazon.com
A.Piper - Choosing Your Messaging Protocol: AMQP, MQTT, or STOMP. -
https://blogs.vmware.com/vfabric/2013/02/choosing-your-messaging-protocol-amqp-
mqtt-or-stomp.html - blogs.vmware.com
Eclipse Foundation - Eclipse Mosquitto™ - An open source MQTT broker - https://mosquitto.org/
G. C. Hillar - MQTT Essentials - A Lightweight IoT Protocol - Packt Publishing Ltd - 2017
IBM - Présentation de la mise en file d'attente de messages -
https://www.ibm.com/support/knowledgecenter/fr/SSFKSJ_8.0.0/com.ibm.mq.pro.doc/q
002620_.htm - 18 Mai 2018 - www.ibm.com
MQTT.org - http://mqtt.org/
M.Richards - The Art of Messaging. - http://www.wmrichards.com/messaging.pdf - 2011 -
http://www.wmrichards.com
M.Watson - Message Queues & You – 12 Reasons to Use Message Queuing -
https://stackify.com/message-queues-12-reasons/ - 30 Janvier 2017 - stackify.com
OASIS - MQTT Version 3.1.1 - http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-
os.html - docs.oasis-open.org
OASIS - OASIS Advanced Message Queuing Protocol (AMQP) Version 1.0 - http://docs.oasis-
open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html - http://docs.oasis-
open.org
Pivotal - RabbitMQ by Pivotal - www.rabbitmq.com.
V.Lampkin, W. Tat Leong, L. Olivera, S. Rawat, N. Subrahmanyam, R. Xiang - Building Smarter
Planet Solutions with MQTT and IBM WebSphere MQ Telemetry - IBM RedBooks -2012
Bibliographie
32
Introduction............................................................................................................................ 2
I - Les files de messages ........................................................................................................... 3
I.1 - Description et Architecture..................................................................................................... 3
I.1.A - Introduction aux files de messages........................................................................................... 3
I.1.B - Les protocoles utilisant les files de messages ........................................................................... 7
I.2 - Différents design de mise en place de files de messages ....................................................... 9
I.2.A - La notion de priorité ................................................................................................................. 9
I.2.B - Une file de messages ou plusieurs ? ....................................................................................... 11
I.2.C - Une file de messages et plusieurs consommateurs ................................................................ 12
I.3 - Avantages et inconvénients des files de messages............................................................... 12
I.3.A - Avantage liés à l’utilisation des files de messages.................................................................. 12
I.3.B - Inconvénients liés à l’utilisation des files de messages........................................................... 13
II - Le protocole MQTT ........................................................................................................... 14
II.1 - Présentation du protocole MQTT ........................................................................................ 14
II.2 - L’architecture MQTT ............................................................................................................ 15
II.2.A - La typologie pub-sub.............................................................................................................. 15
II.2.B - Les messages MQTT............................................................................................................... 15
II.2.C - Les clients MQTT .................................................................................................................... 17
II.3 - Scalabilité ............................................................................................................................. 18
II.4 - Mise en pratique.................................................................................................................. 19
II.4.A - Mise en place d’un échange MQTT........................................................................................ 19
II.4.B - Attribution de variables aux messages .................................................................................. 23
Conclusion............................................................................................................................. 30
Bibliographie......................................................................................................................... 31
Table des matières

Contenu connexe

Tendances

Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Nawres Farhat
 
Hadoop Hbase - Introduction
Hadoop Hbase - IntroductionHadoop Hbase - Introduction
Hadoop Hbase - IntroductionBlandine Larbret
 
Introduction à OpenStack
Introduction à OpenStackIntroduction à OpenStack
Introduction à OpenStackAnDaolVras
 
Conception et réalisation d’un Système d’information des étudiants du départe...
Conception et réalisation d’un Système d’information des étudiants du départe...Conception et réalisation d’un Système d’information des étudiants du départe...
Conception et réalisation d’un Système d’information des étudiants du départe...Ilyas CHAOUA
 
rapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATrapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATSiwar GUEMRI
 
Modélisation de données pour MongoDB
Modélisation de données pour MongoDBModélisation de données pour MongoDB
Modélisation de données pour MongoDBMongoDB
 
Aql métriques logicielles
Aql métriques logiciellesAql métriques logicielles
Aql métriques logiciellesmarwa baich
 
BigData_Chp2: Hadoop & Map-Reduce
BigData_Chp2: Hadoop & Map-ReduceBigData_Chp2: Hadoop & Map-Reduce
BigData_Chp2: Hadoop & Map-ReduceLilia Sfaxi
 
Qu'est ce que le Cloud computing ?
Qu'est ce que le Cloud computing ?Qu'est ce que le Cloud computing ?
Qu'est ce que le Cloud computing ?Olivier Schmitt
 
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...abdelaligougou1
 
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...AHMEDBELGHITH4
 
Introduction aux architectures des SI
Introduction aux architectures des SI Introduction aux architectures des SI
Introduction aux architectures des SI Heithem Abbes
 
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTTModel Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTTymelka
 
Tp1 - WS avec JAXWS
Tp1 - WS avec JAXWSTp1 - WS avec JAXWS
Tp1 - WS avec JAXWSLilia Sfaxi
 
55174240 rapport-cloud-computing
55174240 rapport-cloud-computing55174240 rapport-cloud-computing
55174240 rapport-cloud-computingnoussa krid
 
Architectures 3-tiers (Web)
Architectures 3-tiers (Web)Architectures 3-tiers (Web)
Architectures 3-tiers (Web)Heithem Abbes
 

Tendances (20)

Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
 
Hadoop Hbase - Introduction
Hadoop Hbase - IntroductionHadoop Hbase - Introduction
Hadoop Hbase - Introduction
 
Introduction à OpenStack
Introduction à OpenStackIntroduction à OpenStack
Introduction à OpenStack
 
Presentation cassandra
Presentation cassandraPresentation cassandra
Presentation cassandra
 
Conception et réalisation d’un Système d’information des étudiants du départe...
Conception et réalisation d’un Système d’information des étudiants du départe...Conception et réalisation d’un Système d’information des étudiants du départe...
Conception et réalisation d’un Système d’information des étudiants du départe...
 
Hive ppt (1)
Hive ppt (1)Hive ppt (1)
Hive ppt (1)
 
rapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATrapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSAT
 
Modélisation de données pour MongoDB
Modélisation de données pour MongoDBModélisation de données pour MongoDB
Modélisation de données pour MongoDB
 
Aql métriques logicielles
Aql métriques logiciellesAql métriques logicielles
Aql métriques logicielles
 
BigData_Chp2: Hadoop & Map-Reduce
BigData_Chp2: Hadoop & Map-ReduceBigData_Chp2: Hadoop & Map-Reduce
BigData_Chp2: Hadoop & Map-Reduce
 
DEVOPS
DEVOPSDEVOPS
DEVOPS
 
Qu'est ce que le Cloud computing ?
Qu'est ce que le Cloud computing ?Qu'est ce que le Cloud computing ?
Qu'est ce que le Cloud computing ?
 
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...
CONCEPTION ET REALISATION D’UN RESEAU DE CAPTEURS SANS FILS APPLICATION : AGR...
 
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...
Détection communautaire dans des réseaux complexe a l'aide de l'algorithme gé...
 
Introduction aux architectures des SI
Introduction aux architectures des SI Introduction aux architectures des SI
Introduction aux architectures des SI
 
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTTModel Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
 
Conception d'un Extranet
Conception d'un ExtranetConception d'un Extranet
Conception d'un Extranet
 
Tp1 - WS avec JAXWS
Tp1 - WS avec JAXWSTp1 - WS avec JAXWS
Tp1 - WS avec JAXWS
 
55174240 rapport-cloud-computing
55174240 rapport-cloud-computing55174240 rapport-cloud-computing
55174240 rapport-cloud-computing
 
Architectures 3-tiers (Web)
Architectures 3-tiers (Web)Architectures 3-tiers (Web)
Architectures 3-tiers (Web)
 

Similaire à Architectures des applications pour l internet des objets : les files de messages et le protocole MQTT

Etat de l’art des communications basées sur Mach (1995)
Etat de l’art des communications basées sur Mach (1995)Etat de l’art des communications basées sur Mach (1995)
Etat de l’art des communications basées sur Mach (1995)Julien SIMON
 
Socket tcp ip client server on langace c
Socket tcp ip client server on langace c Socket tcp ip client server on langace c
Socket tcp ip client server on langace c mouad Lousimi
 
Creation de cluster (Master et deux slave ) nfs, htcondor, mpi
Creation de cluster (Master et deux slave ) nfs, htcondor, mpiCreation de cluster (Master et deux slave ) nfs, htcondor, mpi
Creation de cluster (Master et deux slave ) nfs, htcondor, mpiKhalid EDAIG
 
Protocoles d'acces aleatoires
Protocoles d'acces aleatoiresProtocoles d'acces aleatoires
Protocoles d'acces aleatoiresKONAN MARTIAL
 
Ch3_Couche application.pptx
Ch3_Couche application.pptxCh3_Couche application.pptx
Ch3_Couche application.pptxOthmaneMansouri1
 
Virtual Private Network Virtual Private Network
Virtual Private Network Virtual Private NetworkVirtual Private Network Virtual Private Network
Virtual Private Network Virtual Private Networkmia884611
 
A la découverte d'abus
A la découverte d'abusA la découverte d'abus
A la découverte d'abusThierry Gayet
 
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinal
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinalPSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinal
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinalBelkacem KAID
 
Documentation serveur acs wibox (dev interne)
Documentation serveur acs wibox (dev interne)Documentation serveur acs wibox (dev interne)
Documentation serveur acs wibox (dev interne)Taha abbad andaloussi
 
Réseau de capteurs sans fil
Réseau de capteurs sans fil  Réseau de capteurs sans fil
Réseau de capteurs sans fil Ghassen Chaieb
 
CoAP master presentaion
CoAP master presentaionCoAP master presentaion
CoAP master presentaionTarik Sefiri
 

Similaire à Architectures des applications pour l internet des objets : les files de messages et le protocole MQTT (20)

8-socket.pdf
8-socket.pdf8-socket.pdf
8-socket.pdf
 
MPI.pdf
MPI.pdfMPI.pdf
MPI.pdf
 
Etat de l’art des communications basées sur Mach (1995)
Etat de l’art des communications basées sur Mach (1995)Etat de l’art des communications basées sur Mach (1995)
Etat de l’art des communications basées sur Mach (1995)
 
Socket tcp ip client server on langace c
Socket tcp ip client server on langace c Socket tcp ip client server on langace c
Socket tcp ip client server on langace c
 
23508212 vpn
23508212 vpn23508212 vpn
23508212 vpn
 
Creation de cluster (Master et deux slave ) nfs, htcondor, mpi
Creation de cluster (Master et deux slave ) nfs, htcondor, mpiCreation de cluster (Master et deux slave ) nfs, htcondor, mpi
Creation de cluster (Master et deux slave ) nfs, htcondor, mpi
 
Annex
AnnexAnnex
Annex
 
Cours couche application
Cours couche applicationCours couche application
Cours couche application
 
vpn
vpnvpn
vpn
 
Protocoles d'acces aleatoires
Protocoles d'acces aleatoiresProtocoles d'acces aleatoires
Protocoles d'acces aleatoires
 
SSL/TSL Protocols
SSL/TSL ProtocolsSSL/TSL Protocols
SSL/TSL Protocols
 
Ch3_Couche application.pptx
Ch3_Couche application.pptxCh3_Couche application.pptx
Ch3_Couche application.pptx
 
Virtual Private Network Virtual Private Network
Virtual Private Network Virtual Private NetworkVirtual Private Network Virtual Private Network
Virtual Private Network Virtual Private Network
 
A la découverte d'abus
A la découverte d'abusA la découverte d'abus
A la découverte d'abus
 
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinal
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinalPSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinal
PSECRES2017-Projet11-KHATOUN_RIDA-Secu_VoIP-RapFinal
 
si3.pdf
si3.pdfsi3.pdf
si3.pdf
 
Vpn
VpnVpn
Vpn
 
Documentation serveur acs wibox (dev interne)
Documentation serveur acs wibox (dev interne)Documentation serveur acs wibox (dev interne)
Documentation serveur acs wibox (dev interne)
 
Réseau de capteurs sans fil
Réseau de capteurs sans fil  Réseau de capteurs sans fil
Réseau de capteurs sans fil
 
CoAP master presentaion
CoAP master presentaionCoAP master presentaion
CoAP master presentaion
 

Architectures des applications pour l internet des objets : les files de messages et le protocole MQTT

  • 1. Information et communication pour l’ingénieur ARCHITECTURE DES APPLICATIONS POUR L’INTERNET DES OBJETS : LES FILES DE MESSAGES ET LE PROTOCOLE MQTT VALENTIN TRAËN RESPONSABLE DE L’ENSEIGNEMENT : OLIVIER FLAUZAC CONSERVATOIRE NATIONAL DES ARTS ET METIERS 2018 - 2019
  • 2.
  • 3. Sommaire Introduction............................................................................................................................ 2 I - Les files de messages ........................................................................................................... 3 I.1 - Description et Architecture..................................................................................................... 3 I.2 - Différents design de mise en place de files de messages ....................................................... 9 I.3 - Avantages et inconvénients des files de messages............................................................... 12 II - Le protocole MQTT ........................................................................................................... 14 II.1 - Présentation du protocole MQTT ........................................................................................ 14 II.2 - L’architecture MQTT ............................................................................................................ 15 II.3 - Scalabilité ............................................................................................................................. 18 II.4 - Mise en pratique.................................................................................................................. 19 Conclusion............................................................................................................................. 30 31
  • 4. 2 L’internet des objets entraîne depuis plusieurs années des échanges d’informations entre applications ou objets connectés de plus en plus importants. L’internet des objets fait référence à un vaste écosystème technologique regroupant des infrastructures lourdes ou mobiles et permettant l’échange et la valorisation des informations d’objets du quotidien. A l’instar d’Internet, il permet la communication de très nombreux objets entre eux. Les contraintes liées à ces mécanismes sont diverses du fait de l’absence constante de certitude concernant la connectivité des objets à un instant t, de leur potentielle faible puissance de calcul ou de la limitation matérielle entraînant un besoin de sauvegarde d’énergie (appareils fonctionnant sur batteries, piles). Il s’agit cependant déjà d’une réalité permettant à un résident de contrôler ses volets à distance ou à une grande entreprise de vérifier en temps réel la quantité de liquide contenu dans une cuve à plusieurs milliers de kilomètres. Dans ce document, nous nous intéresserons plus particulièrement à la façon dont ces objets communiquent entre eux en concentrant notre étude tout d’abord sur les files de messages permettant d’échanger des informations de façon asynchrone puis sur un protocole d’échange implémentant un tel mécanisme, MQTT. INTRODUCTION
  • 5. 3 Il est courant en informatique de devoir créer des plateformes permettant à divers programmes, services de communiquer entre eux. Les MOM (Message Oriented Middleware ou intergiciels à messages) sont des logiciels permettant à ces services de communiquer entre eux et assurant plusieurs rôles. Ils sont garants de la délivrabilité de l’information : chaque message transitant par un MOM est tracé et peut être persisté en mémoire. Le transfert est en effet asynchrone et les applications des deux côtés du MOM n’ont pas besoin d’être connectées en même temps afin de communiquer. Ils n’ont pas connaissance de l’information et ont juste besoin d’un entête technique leur indiquant quoi faire du message ; ils peuvent toutefois transformer le message afin de le rendre compatible avec l’application réceptrice. 1 - Description et Architecture A - Introduction aux files de messages Les files d’attente de messages (Message Queue en anglais) permettent le stockage temporaire de messages à destination de programmes. Ceux-ci peuvent alors récupérer l’information envoyée par le client, sans contrainte de lien réseau, d’heure d’acquittement... Il s’agit en fait d’une technique que l’on peut facilement visualiser en la mettant en corrélation avec les systèmes de messagerie électronique : l’émetteur envoie un message à un destinataire, message qui sera placé dans une file d’attente (ici la messagerie du destinataire) ; ce dernier a alors la liberté de consulter le message reçu quand bon lui semble et n’a aucune obligation d’être connecté logiquement au réseau de l’émetteur. Dans la réalité c’est d’ailleurs ce qu’il se passe à plus grande échelle : lorsque vous envoyez un message électronique, celui-ci rebondit de serveurs en serveurs jusqu’à arriver à la boîte aux lettres du destinataire ; il n’est pas concevable que, parce qu’un des nœuds n du système est indisponible à un instant t, le message ne soit pas envoyé ou que toute la procédure doive recommencer. Ce message est donc stocké dans la file du n-1 nœud intermédiaire jusqu’à ce que le nœud n soit de nouveau accessible. Mais qu’est-ce qu’une file d’attente ? Une file d’attente est une file logique nommée, gérée par un gestionnaire des files d’attentes (Queue Manager en anglais), et dont la représentation physique peut varier : on la retrouve soit uniquement en Ram soit sur un support de stockage permanent. La file d’attente n’est pas directement visible par les autres applications ; celles-ci s’interfacent en effet avec la gestionnaire de files d’attente qui sert de pont à toute action sur celle-ci. Le “producteur” alimentera cette file, le “consommateur” recevra et exploitera le message. Le message consommé, il sera automatiquement retiré de la file de message après acquittement de bonne réception de la part du consommateur. Un autre composant essentiel à cette architecture peut alors être introduit : l'agent de messages (Message broker en anglais). Il valide et transforme si besoin les messages. Il se charge de récupérer I - Les files de messages
  • 6. 4 le message dans la file de messages, de le recomposer s’il a été envoyé en plusieurs parties et de le transmettre au bon format vers la destination voulue. Par abus de langage, on parle seulement de broker pour désigner à la fois le gestionnaire de file de messages et l’agent de message ; tous deux sont en effet la plupart du temps intégrés dans la même couche logicielle. En ce début de mémoire, nous pouvons donc représenter cette architecture ainsi : Image 1 - Schéma résumant le fonctionnement des files de messages Il est temps de passer à un cas concret et de manipuler une file de messages. Dans la mise en pratique qui suit, le broker RabbitMQ est utilisé. Nous communiquerons avec celui-ci grâce à l’api Python dédiée. Voici le scénario : nous avons un thermomètre extérieur qui envoie régulièrement la température à notre thermostat connecté afin que celui-ci ajuste au mieux la température intérieure de notre logement. Le producteur ici est le thermomètre, le consommateur le thermostat. Notre environnement est vierge de toute file de message ; nous pouvons d’ailleurs le vérifier avec l’utilitaire fourni par le broker : 60.0 seconds ... > rabbitmqctl list_queues Timeout: 60.0 seconds ... Listing queues for vhost / ...
  • 7. 5 Voici le programme chargé dans notre thermomètre : Et voilà le programme chargé dans notre thermostat : #!/usr/bin/env python import pika ## Connexion au broker (ici localhost) connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() ## Nous devons nous assurer que la file de messages ## destination existe, sinon le message ne sera pas ## transmis. Si elle est absente, elle est alors ## créée channel.queue_declare(queue='temperature') ## Composition du message channel.basic_publish(exchange='', routing_key='temperature', body='30 degres celcius') ## Acquittement de l'envoi du message print(" Le thermomètre a transféré une température") ## Fermeture de la connexion connection.close() #!/usr/bin/env python import pika ## Connexion au broker (ici localhost) connection = pika.BlockingConnection( pika.ConnectionParameters(host='localhost')) channel = connection.channel() ## Nous devons nous assurer que la file de messages ## cible existe, sinon le programme ne pourra pas ## continuer correctement channel.queue_declare(queue='temperature') ## Déclaration et initialisation du "callback" permettant ## la récupération des messages dans la file de messages ## déclarée def callback(ch, method, properties, body): print("Le thermostat a reçu la température extérieure %r" %body) channel.basic_consume(queue='temperature', auto_ack=True, on_message_callback=callback) ## Début de la procédure de collecte des messages print(' Thermostat en attente de messages...') channel.start_consuming()
  • 8. 6 Le thermomètre se connecte au broker et transmet le message « 30 degres Celsius » dans une file de messages nommée « temperature ». Le thermostat se connecte lui aussi au broker et récupère tous les messages transmis dans cette file. Testons maintenant notre programme et indiquons au thermomètre de transmettre trois messages : Nous pouvons observer le résultat sur le thermostat : Enfin, l’utilitaire du broker nous indique que nous avons désormais une file de messages nommée « temperature » avec 0 messages : Si nous coupons le thermostat et que le thermomètre envoie deux messages voici le résultat de la précédente commande : Les deux messages n’ont pas été consommés et sont bien toujours dans la file d’attente. Ils seront traités au lancement de l’application du thermostat. >python publisher.py Le thermomètre a transféré une température >python publisher.py Le thermomètre a transféré une température >python publisher.py Le thermomètre a transféré une température >python receive.py Thermostat en attente de messages... Le thermostat a reçu la température extérieure b'30 degres celcius' Le thermostat a reçu la température extérieure b'30 degres celcius' Le thermostat a reçu la température extérieure b'30 degres celcius' >rabbitmqctl list_queues Timeout: 60.0 seconds ... Listing queues for vhost / ... name messages temperature 0 >rabbitmqctl list_queues Timeout: 60.0 seconds ... Listing queues for vhost / ... name messages temperature 2
  • 9. 7 B - Les protocoles utilisant les files de messages Etant donné la multitude d’objets connectés existant de nos jours, il a été nécessaire de fixer des normes communes afin de rendre compatibles les programmes entre eux et de pouvoir échanger des messages quel que soit le langage de programmation utilisé. Des protocoles ont alors vu le jour afin de standardiser ces types d’échanges. • Le protocole AMQP : Un protocole a été mis en place afin de standardiser les échanges de messages en utilisant une file d’attente : AMQP (Advanced message Queuing Protocol). Développé par la banque JPMorgan Chase, c’est un protocole ouvert dont les spécifications résultent d’un consortium international entre plusieurs grands acteurs des technologies liées aux réseaux. Tout comme HTTP, c’est un protocole qui comporte différents éléments de description du message et qui permet donc à différentes applications de communiquer entre elles, quel que soit le langage utilisé pour les programmer. Il s’agit depuis 2012 d’un standard OASIS1 approuvé par l’ISO2 en 2014. Plusieurs typologies d’échanges résultent de la définition de ce protocole, dont les principales : • Point to Point (signifiant « point à point ») : De nombreux producteurs et consommateurs utilisent une file d’attente mais chaque message transmis n’est consommé que par un seul consommateur. La file d’attente sert alors de point d’échange entre les deux parties. • Pub-Sub (pour « publish-suscribe » signifiant « publication-abonnement ») : les consommateurs sont abonnés à des files de messages et reçoivent l’intégralité des messages qui y sont transmis par les producteurs. Ainsi, chaque message placé dans une file de messages est transmis à l’ensemble des consommateurs abonnés. Nous pouvons aussi citer la typologie Store and Forward qui correspond à notre exemple de messagerie développé précédemment : les messages sont stockés en mémoire persistante, récupérés et consultés par un seul consommateur qui décidera de les supprimer ou non. AMQP permet aussi par exemple le transfert de fichiers. Plusieurs brokers comme RabbitMQ ou OpenAMQ permettent utilisent ce protocole. • Le protocole MQTT : MQTT (Message Queue Telemetry Transport) est un protocole développé par IBM n’implémentant que la typologie pub-sub. La simplification de ce protocole par rapport à AMQP et l’utilisation de messages très légers en font un candidat idéal pour toute architecture contrainte, que ce soit à 1 OASIS (Organization for the Advancement of Structured Information Standards) : Créée en 1993, l’OASIS est un consortium international travaillant sur la standardisation des formats d’échange ouverts. 2 ISO : L’Organisation internationale de la normalisation. Cette organisation établit et publie les normes internationales.
  • 10. 8 cause du matériel ou du réseau. Il s’agit depuis 2014 d’un standard OASIS approuvé par l’ISO en 2016. Nous reviendrons bien plus en détails sur ce protocole en deuxième partie de ce mémoire. • Le protocole STOMP : STOMP (Streaming Text Oriented Message Protocol) est un protocole textuel à part puisque n’utilisant pas les files de messages mais permettant tout de même l’échange de messages entre applications. Davantage similaire à HTTP, il permet la transmission de messages via des commandes (comme SEND) et un entête indiquant la destination intermédiaire de ceux-ci. Cette destination intermédiaire est gérée en interne par le broker et peut prendre différentes formes (dont la file d’attente). Le consommateur s’abonne alors à cette destination intermédiaire. Il est nécessaire lorsque l’on parle d’échange réseau de bien visualiser à quelle couche du modèle OSI on fait référence. Pour rappel, la représentation OSI (Open Systems Interconnection) décrit un modèle de communication entre composants informatiques à l’aide de « couches » permettant de transmettre l’information : Couche Libellé Unité d’échange 7 Application Donnée 6 Présentation Donnée 5 Session Donnée 4 Transport Segment 3 Réseau Message 2 Liaison Message 1 Physique Bit Les trois premières couches sont des couches « matérielles » qui regroupent par exemple respectivement les hub, switch et routeur. Les couches suivantes sont appelées les couches « hautes » et concernent davantage l’échange des données entre des processus. Les trois protocoles présentés précédemment sont des protocoles applicatifs liés à la couche 7 du modèle OSI, tout comme le protocole HTTP. Nous pouvons enfin aborder le cas de JMS qui n’est pas un protocole mais une API3 Java très largement utilisée. JMS permet aux programmes Java de s’interfacer avec un MOM et utilise les typologies point-to-point et pub-sub. 3 API (Application Programming Interface): L’interface de programmation applicative fournit un ensemble de classes et de méthodes permettant d’offrir des fonctionnalités supplémentaires à un programme.
  • 11. 9 2 - Différents design de mise en place de files de messages Maintenant que nous connaissons le fonctionnement des files de messages, il est nécessaire de se pencher sur plusieurs paramètres pouvant modifier le comportement du traitement des messages stockés en file d’attente et donc des applications les utilisant. Nous évoquerons dans cette partie différents choix d’architectures qui peuvent faire varier du tout au tout l’attitude applicative face à un message. A - La notion de priorité Imaginons un exemple de domotique simple : plusieurs appareils connectés (un thermomètre extérieur, un thermomètre intérieur et un détecteur de fumée) alimentent une même file de messages. Ces messages sont ensuite transmis sur notre téléphone par l’intermédiaire d’une application les récupère à intervalles réguliers. Les thermomètres m’envoient constamment les informations concernant les températures alors que le détecteur de fumée ne m’envoie un message que lorsqu’une alerte est déclenchée. Il est évident qu’un message du détecteur de fumée sera bien plus urgent que celui des thermomètres. Le message du thermomètre intérieur pourra tout de même me donner des informations concernant la nature de l’alerte (quelque chose qui brûle dans le four ou la pièce entière qui a pris feu). Le thermomètre extérieur lui ne me sera d’aucune utilité. Il est donc nécessaire de définir une règle de priorisation des messages comme suit : Niveau de priorité 3 (critique) Niveau de priorité 2 (majeur) Niveau de priorité 1 (commun) Thermomètre extérieur X Thermomètre intérieur X Détecteur de fumée X Il est possible dans le protocole AMQP par exemple d’indiquer un niveau de priorité lié au message lors de sa publication dans une file de messages. Cette information sera transmise dans l’entête du message. Dans l’exemple suivant, le broker RabbitMQ est de nouveau utilisé. Le code des programmes d’envoi et de réception étant sensiblement le même que celui utilisé dans la première mise en pratique, seules les parties changeantes ont été commentées. Pour une raison de facilité de lecture du document, tous les messages sont envoyés depuis le même programme. Dans la réalité évidemment, chaque appareil, enverrait son propre message.
  • 12. 10 Voici ce programme : #!/usr/bin/env python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() ## Notre file de messages prend désormais en compte les priorités avec une ## priorité maximale à 3 data = dict() data['x-max-priority'] = 3 channel.queue_declare(queue='temperature_priority', arguments=data) ## Message 1 ## Définition de la priorité du message priority = pika.spec.BasicProperties(priority=1) channel.basic_publish(exchange='', routing_key='temperature_priority', body='1 - 15 degres celcius', properties=priority) print(" Le thermomètre extérieur a transféré une température") ## Message 2 priority = pika.spec.BasicProperties(priority=2) channel.basic_publish(exchange='', routing_key='temperature_priority', body='2 - 20 degres celcius', properties=priority) print(" Le thermomètre intérieur a transféré une température") # Message 3 priority = pika.spec.BasicProperties(priority=1) channel.basic_publish(exchange='', routing_key='temperature_priority', body='3 - 15 degres celcius', properties=priority) print(" Le thermomètre extérieur a transféré une température") ## Message 4 priority = pika.spec.BasicProperties(priority=2) channel.basic_publish(exchange='', routing_key='temperature_priority', body='4 - 25 degres celcius', properties=priority) print(" Le thermomètre intérieur a transféré une température") ## Message 5 priority = pika.spec.BasicProperties(priority=3) channel.basic_publish(exchange='', routing_key='temperature_priority', body='5 - ALERTE', properties=priority) print(" Le détecteur de fumée a envoyé une information")
  • 13. 11 Le programme de réception quant à lui n’a pas été modifié si ce n’est la déclaration d’une liste de messages assurant la gestion des priorités. Envoyons les messages : Dans quel ordre le consommateur les a-t-il reçus ? L’ordre des messages a bien été respecté et notre alerte nous a été transmise en priorité. Mais est-ce réellement toujours efficace ? Imaginons que l’alarme se déclenche au temps t, juste après l’ingestion d’un message indiquant la température extérieure, et que le traitement d’un message par notre application prenne en moyenne 10 secondes. Nous recevrons notre température à t + 10 secondes et notre alarme seulement à t + 20 secondes. Rien de vraiment alarmant ici, mais dans le cas d’un temps d’attente sur un site web, cela peut devenir très gênant. Cette notion de priorité est intéressante donc pour trier les messages au sein d’une liste de messages mais peut s’avérer insuffisante lors d’applications critiques. B - Une file de messages ou plusieurs ? Rien n’oblige nos applications à transmettre les messages dans une file de messages unique, un design « multi-files » peut aussi être adopté. L’architecture « mono-file » présente des avantages importants : configuration commune de tous les messages transmis (facilité d’ajout d’un service) et maintenance simplifiée du système. Cependant, une file de message unique ne permet pas une gestion fine des priorités ; en effet, même si cette notion de priorités existe de façon logique dans l’entête des messages, nous avons vu précédemment qu’elle peut ne pas être la bonne solution dans certains cas. Il est alors plus sûr et efficace de créer des silos séparés gérant chacun un type de message. Rappelons qu’un broker est multi-threadé : il permet à un instant t le traitement et la transmission de n messages. Reprenons notre exemple de domotique précédent et imaginons que nous créons deux files de messages : une pour les thermomètres et une pour le détecteur de fumée. Nous pouvons alors configurer notre broker pour que deux processus (listener en anglais) soient chargés de récupérer et transmettre les messages venant de la file de >python send_priority.py Le thermomètre extérieur a transféré une température Le thermomètre intérieur a transféré une température Le thermomètre extérieur a transféré une température Le thermomètre intérieur a transféré une température Le détecteur de fumée a envoyé une information >python receive_priority.py Application en attente de messages... Message reçu b'5 - ALERTE' Message reçu b'2 - 20 degres celcius' Message reçu b'4 - 25 degres celcius' Message reçu b'1 - 15 degres celcius' Message reçu b'3 - 15 degres celcius'
  • 14. 12 température et un processus pour la file relative au détecteur de fumée. Ainsi, les threads du programme étant répartis, nous sommes certains qu’un thread sera toujours en attente et prêt à distribuer le message du détecteur de fumée s’il le faut. Au-delà du choix de technologie de transmission des messages, les choix d’architectures peuvent être tout aussi importants et doivent être étudiés en fonction de la priorisation souhaitée des messages. Il est tout à fait possible de coupler l’architecture « multi-files » qui créera une notion de priorité forte avec la notion de priorité embarquée dans les messages qui permettra un reclassement des messages dans une file d’attente commune. C - Une file de messages et plusieurs consommateurs Une façon efficace d’accélérer notre processus d’ingestion de messages est de distribuer les messages d’une même file d’attente vers plusieurs consommateurs. Dans ce cas-là, chaque consommateur récupère le dernier message non consommé (principe FIFO4 ). Les messages sont alors équitablement répartis entre les consommateurs si bien sûr le temps de traitement d’un message est le même pour chaque consommateur. Si toutefois nous avons besoin que l’information soit décuplée et que chaque consommateur reçoive l’intégralité des messages (si nous voulons que notre thermostat et que notre application mobile reçoive toutes les notifications liées aux températures), il est possible d’utiliser la typologie pub-sub évoquée précédemment ; cette typologie sera plus largement détaillée en deuxième partie de document. 3 - Avantages et inconvénients des files de messages A - Avantages liés à l’utilisation des files de messages De nombreux avantages découlent de l’utilisation d’une telle architecture. Nous pouvons tout d’abord citer la redondance due à la persistance des données en file de messages ; en effet, si un consommateur n’est pas disponible, un autre pourra prendre le relai et interpréter l’information. L’acquittement permettra d’ailleurs d’être certain de la prise en compte du message. Si toutefois aucun consommateur n’est disponible, le message ne sera pas perdu puisque persisté en mémoire, en attente d’être consommé. La possibilité de parallélisation de l’ingestion des messages est aussi un point important : il n’y a pas à attendre pour chaque message un acquittement pour lancer le traitement du message suivant, ceux-ci peuvent être traités en même temps par différents processus tout en conservant la cohérence de l’information. Cette gestion des messages permet aussi une meilleure anticipation des pics de trafic que peut subir une application ; quel que soit le nombre de messages reçus, ils seront traités de la même façon, « limitée » par le nombre de consommateurs. La gestion de ces messages sera alors peut-être plus longue que d’habitude mais sera faite dans tous les cas. Comme nous l’avons vu avec la notion de priorité et de multiplication 4 FIFO (First In First Out) : Se dit d’une structure de données dans laquelle le premier élément extrait est le premier élément inséré.
  • 15. 13 de files de messages, cette architecture peut permettre un meilleur temps de réponse de pages web par exemple en priorisant certaines tâches par rapport à d’autres. Bien sûr, comme introduit en début de mémoire, un des avantages forts des files de messages est l’option offerte à un producteur de délivrer une information sans délai à un instant t sans avoir à prendre en compte l’état du consommateur à ce même instant. La scalabilité5 d’un tel système est enfin évidente : il est aisé d’ajouter un consommateur faisant exactement le même travail qu’un autre, permettant alors l‘accélération du temps de traitement des messages en file d’attente. Cette technologie est beaucoup utilisée dans le cas d’applications à micro-services : chaque élément de l’application est indépendant et permet ainsi en cas de panne de n’avoir qu’une seule partie de celle-ci non fonctionnelle. B - Inconvénients liés à l’utilisation des files de messages Un inconvénient de ce type d’architecture est sa lourdeur de mise en place ; en effet, on ajoute une couche applicative et de nombreux processus associés qui doivent être monitorés. Dans le cas d’applications critiques, la persistance des données ne peut avoir lieu seulement en stockant les données en file : une architecture physique (disques RAID, redondance des serveurs) et logique (clustering des données persistées) doit être mise en place. La configuration applicative est aussi plus complexe : au lieu de configurer un émetteur et un consommateur, il est nécessaire d’en configurer n de chaque côté, en fonction du besoin. 5 Scalabilité (néologisme provenant du terme anglais scalability) : Capacité d’un système à s’adapter à la montée en charge et à maintenir des temps de réponse acceptables.
  • 16. 14 Comme nous l’avons vu dans la partie précédente, la forte augmentation des objets communiquant par l’intermédiaire de files de messages a nécessité la mise en place de règles afin de normaliser ces échanges. Des protocoles ont alors vu le jour et ont permis une standardisation des méthodes de gestion des files de messages : MQTT est l’un d’entre eux. 1 - Présentation du protocole MQTT MQTT est un protocole d’échange de message basé sur les files de messages initialement développé par IBM et open source. Il se veut être très léger et simple afin de pouvoir être utilisé et embarqué sur des appareils avec très peu de capacités de calcul comme de simples capteurs. Comme nous l’avons vu précédemment, comme tout protocole basé sur les files de messages, il permet de connecter de nombreux appareils à une même source d’information (la file de messages) même dans des environnements contraints (pas de réseau ou réseau lent). Contrairement à AMQP, il n’implémente que la typologie pub-sub ; nous ne parlerons donc plus de consommateurs (même s’ils le restent) mais d’« abonnés » dans cette partie. Pour rappel, le principe de cette typologie d’échange est d’alimenter une liste de messages (un « topic ») à laquelle un certain nombre d’abonnés ont souscrit afin de recevoir tous les messages y étant transmis. Nous verrons plus tard que la notion de topic est en fait un peu plus évoluée et permet l’utilisation d’une syntaxe particulière. Les messages stockés dans des topics ne sont pas forcément épurés comme ils peuvent l’être avec une typologie point-to-point afin de permettre aux nouveaux abonnés ou abonnés non connectés de récupérer le dernier message posté. MQTT permet enfin trois niveaux de QoS6 faisant varier les exigences concernant la délivrabilité des messages. Nous pouvons citer quelques brokers MQTT comme Mosquitto, JoramMQ, Really Small Message Broker ou ActiveMQ qui sont tous open-sources. Dans ce document, nous développerons la version 3.1.1 de ce protocole puisqu’il s’agit de la version implémentée dans la plupart des brokers au moment de sa rédaction. Il est tout de même important d’indiquer qu’une version 5.0 existe et qu’elle est officiellement devenue un standard OASIS le 03 avril 2019. 6 QoS (Quality of Service) : La qualité de service est la priorisation de certains services et l’adaptation de contraintes fortes afin de maintenir un niveau de qualité constant préalablement défini II - Le protocole MQTT
  • 17. 15 2 - L’architecture MQTT A - La typologie pub-sub Nous allons dans cette partie revenir plus précisément sur cette typologie particulière et définir les différents concepts qui en font un moyen d’échange de messages à part. Ici aussi l’émetteur n’a pas besoin de connaître l’identité des abonnés qui récupèreront les messages, leur point de communication est le topic et donc le broker. Comme nous l’avons vu dans la première partie de ce mémoire, c’est le broker qui est chargé de récupérer les messages dans le topic et de les transmettre aux différents abonnés. On se retrouve donc avec une typologie similaire à celle en point-to-point si ce n’est la distributivité des messages qui se fait sur l’ensemble des abonnés. Un autre apport est la possibilité de communication inter-brokers ; ainsi, un abonné pourra récupérer les messages d’un topic géré par un autre broker sans avoir de nouvelle connexion à ouvrir. Intéressons-nous maintenant à la notion de topic. Depuis le début de cette partie, nous avons considéré qu’un topic était l’équivalent d’une file de messages à laquelle on s’abonnait ; c’est en fait un peu plus complexe que cela. Il faut vraiment considérer le mot topic à son sens littéral : sujet, thème. Lorsqu’un émetteur publie un message, il indique le thème de son message qui sera classé dans une file de messages dont l’intitulé est alors compréhensible de tous. Ces topics sont organisés de façon hiérarchique en arbres, du sujet le plus global au plus précis. L’intérêt de cette organisation est la possibilité de souscrire un abonnement à un « groupe » de topics sans forcément connaître le nom de chacun ou simplement pour recevoir tous les messages relatifs à un sujet global. Une syntaxe dédiée permet la manipulation de ces groupes : - on peut créer ou naviguer dans un topic grâce au caractère « / ». Ainsi, nous pourrons créer un topic « maison » contenant un topic « température » contenant lui-même un topic « température_intérieure ». Nous noterons alors cette arborescence ainsi : maison/température/température_intérieure. - un abonné peut souscrire à plusieurs topics en même temps en utilisant le caractère « # ». Notre thermostat pourra alors être abonné à maison/température/#, recevant les messages provenant de maison/température et maison/température/température_ intérieure. - A contrario, le caractère « + » peut être utilisé afin de limiter l’abonnement à une strate de l’arborescence. Notre utilisateur ne voudra peut-être pas recevoir toutes les notifications détaillées relatives à son habitation mais des informations plus générales ; il pourra alors s’abonner à maison/+ et ne recevra pas de notifications provenant d’un niveau plus bas que maison/température. B - Les messages MQTT Il est possible d’indiquer lors de la publication d’un message si celui-ci devra être maintenu dans le topic afin d’être transmis plus tard aux abonnés non connectés. Pour ce faire, il est nécessaire d’alimenter la variable de rétention : retain. Initialisée à false, le message ne sera pas
  • 18. 16 conservé, à true il le sera. Un seul message peut être conservé par topic et le restera tant qu’il n’aura pas été remplacé ou supprimé explicitement. Ce message peut servir à maintenir la dernière information en mémoire afin de permettre à tous les nouveaux abonnés d’être à jour ou simplement pour leur indiquer que leur connexion au topic a bien été faite. Il s’agit aussi d’un moyen pour l’émetteur d’être sûr que le message sera bien remis à tous les abonnés. Il est aussi possible de définir un niveau de QoS grâce à la variable qos. Initialisée à 1, le broker s’assurera que le message soit au moins transmis une fois à l’abonné avant de le supprimer, initialisée à 2 que le message soit transmis exactement une fois à l’abonné avant d’être supprimé. Dans le cas où cette variable est initialisée à 0, le gestionnaire fera son possible pour remettre le message aux abonnés mais rien n’est garanti. Ce fonctionnement s’explique du fait des messages échangés dans chaque cas : Image 2 - Schéma montrant les messages échangés en fonction du niveau de QoS configuré • QoS = 0 : l’émetteur transmet le message au broker (PUBLISH) qui n’accuse pas réception. • QoS = 1 : l’émetteur transmet le message au broker (PUBLISH) qui accuse réception (PUBACK pour Publish acknowledgement). Si l’émetteur ne reçoit pas de message PUBACK dans un délai imparti, il retransmet un message PUBLISH. • QoS = 2 : l’émetteur transmet le message au broker (PUBLISH) qui indique l’avoir reçu (PUBREC pour Publish received). Si l’émetteur ne reçoit pas le message PUBREC, il renverra le message via un message PUBLISH en indiquant qu’il s’agit d’un message dupliqué (flag PUB). S’il reçoit la message PUBREC, l’émetteur sait qu’il peut supprimer le message PUBLISH de son côté. Il envoie alors un message PUBREL (pour Publish release) indiquant au broker de « libérer » le message. Le broker transmet alors un message PUBCOM (pour Publish complete) indiquant que le message a été transmis au topic. Pendant cette publication de message PUBCOMP, le broker stocke temporairement l’identifiant du message provenant du message initial PUBLISH afin d’assurer de ne le transmettre qu’une fois aux abonnés. Nous ne parlons ici que de l’échange émetteur – broker. Il existe néanmoins le même type d’échange entre le broker et l’abonné mais c’est à l’abonné d’indiquer le niveau maximal de QoS qu’il souhaite avoir avec le broker ; ainsi, il pourra tout à fait recevoir un message envoyé par
  • 19. 17 l’émetteur avec un QoS = 1 s’il s’est abonné au topic avec un niveau de QoS à 0. L’émetteur aura la certitude que son message aura été remis au broker au moins une fois mais le broker ne pourra pas assurer à 100% la remise du message à l’abonné avec lequel il n’échangera qu’un message PUBLISH. Une règle est à retenir : le niveau de QoS maximum atteignable pour transférer un message du broker à l’abonné est égal au niveau de QoS choisi par l’émetteur pour envoyer son message. En effet, si le message a d’abord été transmis avec un flag QoS à 0, le broker ne peut pas garantir de transmettre le message à l’abonné. S’il a été transmis avec un flag QoS à 1, il ne peut pas garantir de transférer le message une seule fois à l’abonné, étant donné qu’il pourra lui-même le recevoir plusieurs fois. Il est aussi important de noter que l’utilisation du paramètre qos n’influe pas sur le stockage du message. En effet, en cas de redémarrage du broker, nouvelle connexion ou reconnexion d’un client, il est nécessaire de jouer sur le paramètre retain afin de s’assurer de la délivrabilité du message. Il est aussi possible d’influer sur ce comportement grâce au paramètre clean_session que nous verrons dans la partie suivante. C - Les clients MQTT Il est tout à fait possible de configurer les clients MQTT (émetteurs de messages et abonnés) dans le but d’adopter différents comportements lors de leur connexion/déconnexion au broker. L’identification du client par le broker se fait par un identifiant unique composé de 23 octets (possibilité d’en ajouter 17 pour obtenir un identifiant plus explicite) transmis lors d’un message de connexion CONNECT. Lorsqu’une connexion s’ouvre, l’identification du client se fait donc pas la lecture de cette chaîne unique. Le broker peut alors savoir si ce client s’est déjà connecté et dans quel état il a souhaité conserver ou non sa session : - si le paramètre clean_session a été initialisé à true, toute information concernant ce client est supprimée du serveur (le broker) lors de sa déconnexion. C’est le paramètre par défaut. - si le paramètre clean_session est à false, l’ancienne session est conservée à la déconnexion par le broker et réouverte lors de la prochaine connexion du client. On agit alors comme si le client ne s’était jamais déconnecté. Les conséquences de ces paramètres diffèreront donc en fonction du rôle de notre client. S’il s’agit d’un client publiant des messages, ce paramètre n’aura d’utilité qu’avec le paramètre qos à 1 ou 2 appliqué aux messages. En effet, si aucun acquittement n’est demandé au broker, le message avec un niveau de QoS à 0 sera marqué comme envoyé. S’il s’agit d’un abonné, clean_session = true résultera en la remise à zéro de tous les abonnements de la session précédente. A la reconnexion, le client ne sera donc plus abonné à aucun topic. Comme nous l’avons évoqué précédemment, lorsqu’un client se connecte au serveur, il envoie un message CONNECT. Un message CONNACK (pour Connect acknowledge) est alors transmis par le broker en réponse comportant plusieurs informations : - le flag « session present » sera utilisé en cas de déconnexion précédente avec le paramètre clean_session à false. Ce flag permet d’indiquer au client si les abonnements pourront bien être restaurés depuis la session précédente ou si le client doit indiquer à quels topics il veut se réabonner. - Un code de retour est aussi chargé dans ce message : 0 si la connexion est acceptée, 1, 2 3, 4 ou 5 si elle est refusée. Elle peut l’être pour diverses raisons : problème de version de protocole MQTT déclarée, refus de l’identifiant du client, service MQTT non disponible…
  • 20. 18 Quand utiliser ce paramètre ? Il peut être utile de positionner clean_session à false si un abonné doit recevoir tous les messages d’un topic même en cas de déconnexion ou s’il s’agit d’un appareil à ressources très limitées (comme un capteur) à qui on « épargne » l’envoi de messages d’abonnements dès qu’il se reconnecte. Au contraire, si l’abonné n’a pas besoin de recevoir tous les messages, conserver ce paramètre à true permet une charge moins importante au broker ; il en va de même s’il s’agit seulement d’un émetteur. Il existe une notion de dernière volonté (« last will and testament ») permettant de configurer l’envoi automatique d’un message dans un topic si jamais la connexion du client est perdue. On peut aussi indiquer la valeur de QoS voulue pour ce message. Enfin, de même que pour la connexion, pour un client abonné, la souscription à un topic se fait via l’envoi d’un message SUBSCRIBE indiquant le topic auquel l’abonné veut accéder. Ce message comporte aussi la valeur maximale de QoS souhaitée lors de la réception d’un message. En réponse, l’abonné reçoit un message SUBACK (pour Subscribe acknowledge) confirmant la prise en compte de la demande d’abonnement. 3 - Scalabilité Lorsque nous parlons de MQTT, nous restons très fortement liés à l’internet des objets et donc à la multiplication d’applications, services, objets pouvant communiquer entre eux. Nous ne sommes plus à l’échelle de notre petit exemple de domotique désormais mais plutôt à celle du vendeur de thermomètres connectés qui reçoit des informations de la part de l’intégralité des objets vendus. Par exemple, il peut recevoir régulièrement la version du micrologiciel embarqué dans ses thermomètres afin d’établir une cartographie des appareils non mis à jour. Les temps de réponse du serveur MQTT devant rester les mêmes que l’entreprise ait vendu 10 thermomètres ou 10000, il est nécessaire d’avoir une architecture scalable. La scalabilité peut être verticale (ajouter de la puissance de calcul au serveur MQTT) ou horizontale (multiplier les serveurs MQTT afin d’y répartir la charge). Pour des raisons de coût, d’efficacité, de QoS, de flexibilité, la seconde approche est bien souvent celle privilégiée. Nous avons vu précédemment qu’un abonné interrogeant un topic pouvait recevoir des réponses de plusieurs brokers, ceux-ci ayant la possibilité d’être reliés entre eux par un système de pont. C’est donc ici aussi la scalabilité horizontale qui est choisie. On répartit ainsi la charge de calcul du broker mais doublons l’espace de stockage nécessaire. Attention cependant, on introduit avec ce système de nouvelles contraintes réseau (entre les brokers) et de persistance des données dans le cas où un broker tombe en panne. Il est tout de même important de préciser que la plupart des brokers MQTT du marché ont été conçus pour être capable de recevoir de très nombreuses connexions de clients sur une architecture serveur « classique » qui peut être améliorée si besoin ; la scalabilité verticale est donc aussi tout à fait possible.
  • 21. 19 4 - Mise en pratique Il est désormais temps de mettre en pratique ce qui a été expliqué plus tôt et de manipuler le protocole MQTT. Pour ce faire, le broker Mosquitto sera utilisé. Le langage utilisé par les clients sera Python. Chaque exemple sera associé à une mise en situation reprenant notre architecture de domotique présentée jusqu’alors. A - Mise en place d’un échange MQTT Commençons par la mise en place d’une architecture pub-sub basique. Dans cet exemple, nous souhaitons simplement qu’un publisher (notre thermomètre) envoie une température à deux subscribers (le thermostat et l’application mobile). Pour le moment seul le topic maison/temperature/temperature_exterieure est alimenté. Le programme d’envoie des messages : Notre client « thermometre » publie le message « 15 » dans le topic maison/temperature/temperature_exterieure. import paho.mqtt.client as mqtt ################################################ ###fonction dédiée à la lecture des logs######## def on_log(client, userdata, level, buf): print("log: ",buf) ################################################ #céeation d une instance client =mqtt.Client("thermometre") #activation des logs client.on_log=on_log #connexion au broker client.connect("localhost",1883) #publication d un message client.publish("maison/temperature/temperature_exterieure","15")
  • 22. 20 Voici maintenant le programme d’abonnement au topic et réception des messages : Notre client « thermostat » souscrit au topic « maison/temperature/temperature_exterieure » et affiche les messages reçus à la réception de ceux-ci. Un deuxième programme a été écrit pour l’application mobile mais seule la ligne « client =mqtt.Client("application_mobile") » diffère du précédent programme. Testons maintenant nos programmes. Nous ouvrons les connexions des clients abonnés en premier lieu puis lançons la publication du message. import paho.mqtt.client as mqtt ################################################ ###fonction dédiée à la lecture des messages#### def on_message(client, userdata, message): print("message reçu : " ,str(message.payload.decode("utf-8"))) print("topic : ",message.topic) print("niveau de QoS : ",message.qos) print("rétention : ",message.retain) ###fonction dédiée à la lecture des logs######## def on_log(client, userdata, level, buf): print("log: ",buf) ################################################ #creation d une instance client =mqtt.Client("thermostat") #activation des logs client.on_log=on_log #connexion au broker client.connect("localhost",1883) #publication d un message client.subscribe("maison/temperature/temperature_exterieure") #boucle de lecture des messages client.on_message=on_message client.loop_forever() > python publisher.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre' log: Sending PUBLISH (d0, q0, r0, m1), 'b'maison/temperature/temperature_exterieure'', ... (2 bytes)
  • 23. 21 Le message est reçu par nos deux abonnés : Intéressons-nous maintenant aux syntaxes « topic/# » et « topic/+ » ; pour rappel, ces syntaxes permettent de s’abonner respectivement à l’ensemble des topics de la sous-arborescence représentée par « # » et aux topics présents au même niveau de l’arborescence que celui représenté par « + ». Pour ce faire, nous modifions temporairement le code de notre thermomètre afin de lui faire publier 4 messages : Nous introduisons ici deux nouveaux topics : maison/temperature/temperature_interieure qui se trouve au même niveau que maison/temperature/temperature_exterieure et maison/alarme qui se trouve au même niveau que maison/temperature. Des messages sont publiés dans chacun de ces topics. Le thermostat est désormais abonné à tous les topics de la branche maison/temperature : > python receive1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 0 rétention : 0 > python receive2.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'application_mobile' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 0 rétention : 0 client.publish("maison/temperature/temperature_exterieure","20") client.publish("maison/temperature/temperature_interieure","18") client.publish("maison/temperature","TEMP") client.publish("maison/alarme","ALERTE") client.subscribe("maison/temperature/#")
  • 24. 22 Publions nos quatre messages : Voici les messages reçus par notre abonné : Seuls les messages relatifs à la gestion de la température ont été transmis. Tous les messages ont été reçus sauf ceux envoyés dans le topic maison/alarme qui ne correspondait pas à l’abonnement. Modifions maintenant l’abonnement ainsi : > python publisher.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre' log: Sending PUBLISH (d0, q0, r0, m1), 'b'maison/temperature/temperature_exterieure'', ... (2 bytes) log: Sending PUBLISH (d0, q0, r0, m2), 'b'maison/temperature/temperature_interieure'', ... (2 bytes) log: Sending PUBLISH (d0, q0, r0, m3), 'b'maison/temperature'', ... (4 bytes) log: Sending PUBLISH (d0, q0, r0, m4), 'b'maison/alarme'', ... (6 bytes) > python receive1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/#', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes) message reçu : 20 topic : maison/temperature/temperature_exterieure niveau de QoS : 0 rétention : 0 log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_interieure', ... (2 bytes) message reçu : 18 topic : maison/temperature/temperature_interieure niveau de QoS : 0 rétention : 0 log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature', ... (4 bytes) message reçu : TEMP topic : maison/temperature niveau de QoS : 0 rétention : 0 client.subscribe("maison/+")
  • 25. 23 Désormais, l’abonné ne devrait recevoir que les messages relatifs à la maison sans entrer dans le détail des températures. Vérifions cela : Enfin, un abonné peut se désabonner d’un topic ainsi : Dans les exemples précédents, nous avons pu voir afficher dans les logs les différents types de messages MQTT échangés lors de la publication des messages. B - Attribution de variables aux messages Si un nouveau client s’abonne au topic ou qu’un abonné se connecte après envoi du message par l’émetteur, il ne recevra pas cette information. En effet, elle n’est pas maintenue en mémoire étant donné que nous n’avons pas demandé à l’émetteur d’envoyer l’information de persistance au broker. Pour ce faire, nous allons manipuler la variable de rétention. La publication du message a été modifiée comme suit : Pour le test suivant, la connexion du thermostat est ouverte au moment de l’envoi du message mais pas celle de l’application mobile. Nous testons donc la bonne réception du message sur l’application mobile lors de sa connexion. > python receive1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/+', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature', ... (4 bytes) message reçu : TEMP topic : maison/temperature niveau de QoS : 0 rétention : 0 log: Received PUBLISH (d0, q0, r0, m0), 'maison/alarme', ... (6 bytes) message reçu : ALERTE topic : maison/alarme niveau de QoS : 0 rétention : 0 client.unsubscribe("maison/temperature/temperature_exterieure") client.publish("maison/temperature/temperature_exterieure","15",retain=True)
  • 26. 24 Sur le thermostat : Sur l’application mobile : On constate que le message ayant été transmis « en direct » au thermostat, le flag de rétention est à 0. Cependant, le message transmis à l’application mobile est quant à lui bien un message ayant été stocké temporairement par le broker : le flag est à 1. Si nous n’avions pas indiqué au broker de garder en mémoire le message, celui-ci n’aurait pas été transmis à la connexion de l’application mobile car le message aurait été supprimé. A partir de maintenant, la variable de rétention est remise à false. Modifions maintenant le niveau de QoS afin de le mettre à 1 (pour faciliter la lecture de ce rapport, nous considérons qu’un flag QoS = 1 correspond à l’initialisation de cette variable à 1 pour les échanges émetteur – broker et broker – abonné). Pour rappel, le niveau 1 garantit la délivrabilité du message au minimum une fois. Dans ce scénario, notre application mobile sera mise hors ligne juste avant l’envoi du message afin qu’elle ait pu indiquer la valeur de QoS désirée pour la réception des messages. Nous enverrons tout d’abord le message depuis le thermomètre, lirons le résultat sur le thermostat, et démarrerons enfin le service lié à l’application mobile. Si le niveau de QoS est respecté, l’application mobile devrait recevoir le message à sa connexion à condition qu’il ait été indiqué au broker de conserver un historique de la session. > python receive1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r0, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 0 rétention : 0 > python receive2.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'application_mobile' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 0)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q0, r1, m0), 'maison/temperature/temperature_exterieure', ... (2 bytes) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 0 rétention : 1
  • 27. 25 Les lignes suivantes ont préalablement été modifiées : • Sur le thermomètre : • Sur le thermostat et l’application mobile : Dans la déclaration du client, le paramètre « False » indique de conserver un historique de la session à la déconnexion. Le résultat obtenu est-il le bon ? Publication du message : On peut vérifier le niveau de QoS avec lequel le message a été envoyé grâce au paramètre « q1 » (pour QoS = 1). Réception « en direct » sur le thermostat : client.publish("maison/temperature/temperature_exterieure","15",qos=1) #Sauvegarde de la session client =mqtt.Client("thermostat",False) #Souscription aux messages allant jusqu’à un QoS = 1 client.subscribe("maison/temperature/temperature_exterieure",1) > python publisher.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre' log: Sending PUBLISH (d0, q1, r1, m1), 'b'maison/temperature/temperature_exterieure'' (NULL payload) log: Received CONNACK (0, 0) log: Received PUBACK (Mid: 1) > python subscriber_1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 2)] log: Received CONNACK (0, 0) log: Received SUBACK log: Sending PINGREQ log: Received PINGRESP log: Received PUBLISH (d0, q1, r0, m1), 'maison/temperature/temperature_exterieure', ... (2 bytes) log: Sending PUBACK (Mid: 1) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 1 rétention : 0
  • 28. 26 Réception différée sur l’application mobile à son démarrage : Si le message a été reçu même après la déconnexion de l’abonné c’est parce que nous avons préalablement indiqué au broker de sauvegarder l’état de la session ; le message est alors transmis à l’abonné puisque lors de sa connexion, le flag « session present » du message CONNACK est initialisé à true et le broker considère qu’il s’agit d’une session « sans coupure ». Image 3 - Extrait du message CONNACK transmis lors de l'échange > python subscriber_2.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'application_mobile' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 1)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q1, r1, m1), 'maison/temperature/temperature_exterieure', ... (2 bytes) log: Sending PUBACK (Mid: 1) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 1 rétention : 0
  • 29. 27 Etudions maintenant les messages MQTT échangés lors de la remise de ce message : Image 4 - Echange de messages avec un niveau de QoS fixé à 1 On constate le double échange de messages dû au niveau de QoS choisi ainsi que le contenu du message embarqué dans le message MQTT PUBLISH. On remarque aussi dans l’ensemble de ces messages un id (id = 1) qui correspond à l’identifiant unique du message dans le topic. On retrouve d’ailleurs cette information lors de la réception d’un message par un abonné (mid : 1). Ce test se comporte de façon identique avec un niveau de QoS à 2. > python publisher.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'thermometre' log: Sending PUBLISH (d0, q2, r1, m1), 'b'maison/temperature/temperature_exterieure'' (NULL payload) log: Received CONNACK (0, 0) log: Received PUBREC (Mid: 1) log: Sending PUBREL (Mid: 1) log: Received PUBCOMP (Mid: 1) > python subscriber_1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 2)] log: Received CONNACK (0, 0) log: Received SUBACK log: Received PUBLISH (d0, q2, r0, m1), 'maison/temperature/temperature_exterieure', ... (0 bytes) log: Sending PUBREC (Mid: 1) log: Received PUBREL (Mid: 1) message reçu : 15 topic : maison/temperature/temperature_exterieure niveau de QoS : 2 rétention : 0 log: Sending PUBCOMP (Mid: 1)
  • 30. 28 On reconnaît bien ici le quadruple échange de messages MQTT lié à ce niveau de QoS : Image 5 - Echange de messages avec un niveau de QoS fixé à 2 Enfin, nous allons tester le mécanisme de « last will and testament » permettant à un client se déconnectant de déposer un message dans un topic. Dans notre cas, nous voulons prévenir notre application mobile de la déconnexion du thermomètre. Voici comment est mise en place cette fonctionnalité dans le code du client : Lorsque nous déconnectons le thermomètre, le message est bien reçu par les abonnés : client.will_set("maison/temperature/temperature_exterieure","Je suis déconnecté", qos=1) > python subscriber_1.py log: Sending CONNECT (u0, p0, wr0, wq0, wf0, c0, k60) client_id=b'thermostat' log: Sending SUBSCRIBE (d0, m1) [(b'maison/temperature/temperature_exterieure', 1)] log: Received CONNACK (1, 0) log: Received SUBACK log: Received PUBLISH (d0, q1, r1, m36472), 'maison/temperature/temperature_exterieure', ... (20 bytes) log: Sending PUBACK (Mid: 36472) message reçu : Je suis déconnecté topic : maison/temperature/temperature_exterieure niveau de QoS : 1 rétention : 0
  • 31. 29 Le message délivré est un message comme un autre, envoyé selon le niveau de QoS choisi. Nous pouvons cependant constater dans le message de connexion du thermomètre le paramètre indiquant qu’il s’agit d’un message à remettre en cas de déconnexion : Image 6 - Publication d'un message de "dernière volonté" Ces différentes mises en pratiques, au-delà d’illustrer différents concepts inhérents au protocole MQTT, montrent aussi la facilité de mis en œuvre de messages utilisant cette technologie. Très peu de paramètres sont nécessaire à la publication des messages, très peu de manipulations sont requises de la part des clients. MQTT se veut être simple à appréhender et ne nécessite pas de connaissances particulières en réseau.
  • 32. 30 L’internet des objets nous a forcé à repenser la manière dont les applications pouvaient communiquer entre elles. Les entreprises ont dû s’adapter à des échanges qu’elles ne maîtrisaient pas du fait de l’externalisation de leurs produits et de la multiplication de ceux-ci. Comment s’assurer que l’information soit reçue de la même façon à plusieurs milliers de kilomètres de distance, sur des appareils dont nous ne connaissons pas la nature, connectés à des réseaux inconnus ? Les protocoles conventionnels n’ont pas été conçus pour des domaines aussi variés que ceux que l’on retrouve dans l’internet des objets, entraînant des consommations trop élevées et des difficultés de mise en place dues à la complexité de leur utilisation. Les files d’attente de messages offrent une alternative intéressante aux protocoles « classiques » concernant l’échange de messages en milieu contraint. Elles offrent un échange asynchrone d’information, permettant alors à un processus de ne pas être totalement stoppé en cas de défaillance d’une partie du système. Elles introduisent cependant de nouvelles couches logicielles qu’il faut pouvoir et savoir maintenir en production. Des règles d’échange ont alors dû être mises en place afin de standardiser les communications et permettent la compatibilité des produits entre eux. Nous pouvons tout de même nous interroger sur les ressources machines requises pour la mise en place de tels systèmes : si bien sûr, l’internet des objets a introduit des composants très peu énergivores et que certains d’entre eux permettent même la gestion de l’énergie de composants plus classiques, qu’en est-il de la démultiplication des brokers nécessaires au bon fonctionnement des files de messages ? CONCLUSION
  • 33. 31 Amazon - Files d'attente de messages - https://aws.amazon.com/fr/message-queue/ - aws.amazon.com Amazon - Pub/Sub Messaging - https://aws.amazon.com/fr/pub-sub-messaging/ - aws.amazon.com A.Piper - Choosing Your Messaging Protocol: AMQP, MQTT, or STOMP. - https://blogs.vmware.com/vfabric/2013/02/choosing-your-messaging-protocol-amqp- mqtt-or-stomp.html - blogs.vmware.com Eclipse Foundation - Eclipse Mosquitto™ - An open source MQTT broker - https://mosquitto.org/ G. C. Hillar - MQTT Essentials - A Lightweight IoT Protocol - Packt Publishing Ltd - 2017 IBM - Présentation de la mise en file d'attente de messages - https://www.ibm.com/support/knowledgecenter/fr/SSFKSJ_8.0.0/com.ibm.mq.pro.doc/q 002620_.htm - 18 Mai 2018 - www.ibm.com MQTT.org - http://mqtt.org/ M.Richards - The Art of Messaging. - http://www.wmrichards.com/messaging.pdf - 2011 - http://www.wmrichards.com M.Watson - Message Queues & You – 12 Reasons to Use Message Queuing - https://stackify.com/message-queues-12-reasons/ - 30 Janvier 2017 - stackify.com OASIS - MQTT Version 3.1.1 - http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1- os.html - docs.oasis-open.org OASIS - OASIS Advanced Message Queuing Protocol (AMQP) Version 1.0 - http://docs.oasis- open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html - http://docs.oasis- open.org Pivotal - RabbitMQ by Pivotal - www.rabbitmq.com. V.Lampkin, W. Tat Leong, L. Olivera, S. Rawat, N. Subrahmanyam, R. Xiang - Building Smarter Planet Solutions with MQTT and IBM WebSphere MQ Telemetry - IBM RedBooks -2012 Bibliographie
  • 34. 32 Introduction............................................................................................................................ 2 I - Les files de messages ........................................................................................................... 3 I.1 - Description et Architecture..................................................................................................... 3 I.1.A - Introduction aux files de messages........................................................................................... 3 I.1.B - Les protocoles utilisant les files de messages ........................................................................... 7 I.2 - Différents design de mise en place de files de messages ....................................................... 9 I.2.A - La notion de priorité ................................................................................................................. 9 I.2.B - Une file de messages ou plusieurs ? ....................................................................................... 11 I.2.C - Une file de messages et plusieurs consommateurs ................................................................ 12 I.3 - Avantages et inconvénients des files de messages............................................................... 12 I.3.A - Avantage liés à l’utilisation des files de messages.................................................................. 12 I.3.B - Inconvénients liés à l’utilisation des files de messages........................................................... 13 II - Le protocole MQTT ........................................................................................................... 14 II.1 - Présentation du protocole MQTT ........................................................................................ 14 II.2 - L’architecture MQTT ............................................................................................................ 15 II.2.A - La typologie pub-sub.............................................................................................................. 15 II.2.B - Les messages MQTT............................................................................................................... 15 II.2.C - Les clients MQTT .................................................................................................................... 17 II.3 - Scalabilité ............................................................................................................................. 18 II.4 - Mise en pratique.................................................................................................................. 19 II.4.A - Mise en place d’un échange MQTT........................................................................................ 19 II.4.B - Attribution de variables aux messages .................................................................................. 23 Conclusion............................................................................................................................. 30 Bibliographie......................................................................................................................... 31 Table des matières