Considérations sur l’encodage des messages

De nombreuses applications Cloud utilisent des messages asynchrones pour échanger des informations entre les composants du système. Un aspect important de la messagerie est le format utilisé pour encoder les données de charge utile. Une fois que vous avez choisi une technologie de messagerie, l’étape suivante consiste à définir la manière dont les messages seront encodés. De nombreuses options sont disponibles, mais le choix approprié dépend de votre cas d’usage.

Cet article décrit quelques-uns des points à prendre en compte.

Besoins en matière d’échange de messages

Un échange de messages entre un producteur et un consommateur doit comporter les éléments suivants :

  • Une forme ou une structure qui définit la charge utile du message.
  • Un format d’encodage pour représenter la charge utile.
  • Des bibliothèques de sérialisation pour la lecture et l’écriture de la charge utile encodée.

Le producteur du message définit la forme du message en fonction de la logique métier et des informations qu’il souhaite envoyer aux consommateurs. Pour structurer la forme, divisez les informations en sujets discrets ou associés (champs). Déterminez les caractéristiques des valeurs de ces champs. Vous devez : Quel est le type de données le plus efficace ? La charge utile comprendra-t-elle toujours certains champs ? La charge utile comprendra-t-elle un enregistrement unique ou un ensemble répété de valeurs ?

Choisissez ensuite un format d’encodage en fonction de vos besoins. Certains facteurs incluent la possibilité de créer des données hautement structurées si vous en avez besoin, le temps nécessaire pour encoder et transférer le message, ainsi que la possibilité d’analyser la charge utile. Selon le format d’encodage, choisissez une bibliothèque de sérialisation qui est bien prise en charge.

Le consommateur du message doit être conscient de ces décisions de manière à être en mesure de lire les messages entrants.

Pour transférer des messages, le producteur sérialise le message dans un format d’encodage. À l’extrémité de réception, le consommateur désérialise la charge utile pour utiliser les données. Ainsi, les deux entités partagent le modèle et tant que la forme ne change pas, la messagerie se poursuit sans problème. Lorsque le contrat change, le format d’encodage doit être en capable de gérer ce changement sans arrêter le consommateur.

Certains formats d’encodage tels que JSON sont autodescriptifs, ce qui signifie qu’ils peuvent être analysés sans référence à un schéma. Toutefois, ces formats ont tendance à générer des messages plus volumineux. Dans d’autres formats, les données peuvent ne pas être analysées aussi facilement, mais les messages sont compacts. Cet article met l’accent sur certains facteurs susceptibles de vous aider à choisir un format.

Considérations relatives au format d’encodage

Le format d’encodage définit la manière dont un jeu de données structurées est représenté sous la forme d’octets. Le type de message peut influencer le choix de format. Les messages liés aux transactions commerciales contiennent probablement des données hautement structurées. En outre, vous souhaiterez peut-être les récupérer ultérieurement à des fins d’audit. Pour un flux d’événements, vous souhaiterez peut-être lire une séquence d’enregistrements aussi rapidement que possible et la stocker en vue d’une analyse statistique.

Voici quelques points à prendre en compte lors du choix d’un format d’encodage.

La lisibilité humaine

L’encodage de message peut être largement divisé en formats textes et binaires.

Avec l’encodage en format texte, la charge utile du message est en texte brut et peut donc être inspectée par une personne sans l’aide de bibliothèques de codes. Les formats lisibles par les humains sont adaptés aux données d’archivage. En outre, étant donné qu’un homme peut lire la charge utile, les formats textes sont plus faciles à déboguer et à envoyer aux journaux en vue de la résolution des erreurs.

L’inconvénient est que la charge utile a tendance à être plus importante. JSON est un format texte standard.

Chiffrement

Si les messages contiennent des données sensibles, déterminez s’ils doivent être chiffrés dans leur intégralité, comme indiqué dans les conseils d’aide sur le chiffrement des données Azure Service Bus au repos. Dans le cas contraire, si seuls certains champs doivent être chiffrés et si vous préférez réduire les coûts liés au cloud, utilisez une bibliothèque telle que NServiceBus.

Taille de l’encodage

La taille des messages a un impact sur le niveau de performance d’E/S réseau sur le réseau. Les formats binaires sont plus compacts que les formats textes. Les formats binaires nécessitent des bibliothèques de sérialisation/désérialisation. La charge utile ne peut pas être lue, sauf si elle est décodée.

Utilisez un format binaire si vous souhaitez réduire l’empreinte sur le réseau et transférer les messages plus rapidement. Cette catégorie de format est recommandée dans les scénarios où le stockage ou la bande passante réseau sont problématiques. Voici les options de formats binaires : Apache Avro, Google Protocol buffers (protobuf), MessagePack et Concise Binary Object Representation (CBOR). Les avantages et les inconvénients de ces formats sont décrits dans cette section.

L’inconvénient est que la charge utile n’est pas lisible par l’homme. La plupart des formats binaires utilisent des systèmes complexes dont la gestion peut être coûteuse. En outre, des bibliothèques spécialisées sont nécessaires pour le décodage, et celles-ci peuvent ne pas être prises en charge si vous souhaitez récupérer des données d’archivage.

Comprendre la charge utile

Une charge utile de message arrive sous la forme d’une séquence d’octets. Pour analyser cette séquence, le consommateur doit avoir accès aux métadonnées qui décrivent les champs de données dans la charge utile. Il existe deux approches principales de stockage et de distribution des métadonnées :

Métadonnées avec balises. Dans certains encodages, en particulier le format JSON, les champs sont balisés avec le type de données et l’identificateur, dans le corps du message. Ces formats sont autodescriptifs, car ils peuvent être analysés dans un dictionnaire de valeurs sans référence à un schéma. Pour le consommateur, l’une des façons de comprendre les champs est d’interroger les valeurs attendues. Par exemple, le producteur envoie une charge utile au format JSON. Le consommateur analyse le format JSON dans un dictionnaire et vérifie l’existence de champs pour comprendre la charge utile. Une autre méthode pour le consommateur consiste à appliquer un modèle de données partagé par le producteur. Par exemple, si vous utilisez un langage à typage statique, de nombreuses bibliothèques de sérialisation JSON peuvent analyser une chaîne JSON dans une classe typée.

Schéma. Un schéma définit formellement la structure et les champs de données d’un message. Dans ce modèle, le producteur et le consommateur ont un contrat par le biais d’un schéma bien défini. Le schéma peut définir les types de données, les champs obligatoires/facultatifs, les informations de version et la structure de la charge utile. Le producteur envoie la charge utile en fonction du schéma d’écriture. Le consommateur reçoit la charge en appliquant un schéma de lecture. Le message est sérialisé/désérialisé à l’aide des bibliothèques spécifiques à l’encodage. Il existe deux façons de distribuer des schémas :

  • Stocker le schéma en tant que préambule ou en-tête dans le message, mais séparé de la charge utile.

  • Stocker le schéma en externe.

Certains formats d’encodage définissent le schéma et utilisent des outils qui génèrent des classes à partir du schéma. Le producteur et le consommateur utilisent ces classes et bibliothèques pour sérialiser et désérialiser la charge utile. Les bibliothèques fournissent également des vérifications de compatibilité entre les schémas d’écriture et de lecture. Protobuf et Apache Avro adoptent cette approche. La principale différence réside dans le fait que la définition de schéma de Protobuf est indépendante du langage et qu’Avro utilise le format JSON compact. Une autre différence réside dans la façon dont les deux formats fournissent des vérifications de compatibilité entre les schémas de lecture et d’écriture.

Autre façon de stocker le schéma en externe dans un registre de schéma. Le message contient une référence au schéma et à la charge utile. Le producteur envoie l’identificateur de schéma dans le message et le consommateur récupère le schéma en spécifiant cet identificateur à partir d’un stockage externe. Les deux parties utilisent une bibliothèque spécifique au format pour lire et écrire des messages. Hormis le stockage du schéma, un registre peut fournir des vérifications de compatibilité pour s’assurer que le contrat entre le producteur et le consommateur n’est pas rompu au fil de l’évolution du schéma.

Avant de choisir une approche, choisissez ce qui est plus important : la taille des données de transfert ou la possibilité d’analyser ultérieurement les données archivées.

Le stockage du schéma avec la charge utile produit une plus grande taille d’encodage et est préférable pour les messages intermittents. Choisissez cette approche si le transfert de plus petits blocs d’octets est essentiel ou si vous prévoyez une séquence d’enregistrements. Le coût de la gestion d’un stockage de schémas externe peut être élevé.

Toutefois, si le décodage à la demande de la charge utile est plus important que la taille, inclure le schéma avec la charge utile ou l’approche de métadonnées avec balises garantit le décodage par la suite. Il peut y avoir une augmentation significative de la taille des messages et un impact sur le coût du stockage.

Contrôle des versions des schémas

À mesure que les besoins de l’entreprise évoluent, la forme est censée changer et le schéma évolue. Le contrôle de version permet au producteur d’indiquer des mises à jour de schéma qui peuvent inclure de nouvelles fonctionnalités. Le contrôle de version comporte deux aspects :

  • Le consommateur doit être au fait des changements.

    L’une des méthodes consiste à ce que le consommateur vérifie tous les champs pour déterminer si le schéma a changé. Une autre méthode consiste à ce que le producteur publie un numéro de version de schéma avec le message. Lorsque le schéma évolue, le producteur incrémente la version.

  • Les changements ne doivent pas influer sur ni arrêter la logique métier des consommateurs.

    Supposons qu’un champ soit ajouté à un schéma existant. Si les consommateurs qui utilisent la nouvelle version obtiennent une charge utile en fonction de l’ancienne version, leur logique peut s’arrêter si elle ne parvient pas à ignorer l’absence du nouveau champ. Dans la situation inverse, supposons qu’un champ soit supprimé du nouveau schéma. Les consommateurs qui utilisent l’ancien schéma peuvent ne pas être en mesure de lire les données.

    Les formats d’encodage tels qu’Avro offrent la possibilité de définir des valeurs par défaut. Dans l’exemple précédent, si le champ est ajouté avec une valeur par défaut, le champ manquant est rempli avec la valeur par défaut. D’autres formats tels que Protobuf offrent des fonctionnalités similaires par le biais de champs obligatoires et facultatifs.

Structure de charge utile

Tenez compte de la façon dont les données sont organisées dans la charge utile. S’agit-il d’une séquence d’enregistrements ou d’une charge utile unique discrète ? La structure de charge utile peut être classée dans l’un de ces modèles :

  • Tableau/dictionnaire/valeur : Définit des entrées qui contiennent des valeurs dans un ou plusieurs tableaux multidimensionnels. Les entrées ont des paires clé-valeur uniques. Peut être étendu pour représenter les structures complexes. Voici quelques exemples : JSON, Apache Avro et MessagePack.

    Cette disposition convient si les messages sont encodés individuellement avec des schémas différents. Si vous avez plusieurs enregistrements, la charge utile peut être trop redondante, provoquant un ballonnement de la charge utile.

  • Données tabulaires : Les informations sont divisées en lignes et en colonnes. Chaque colonne indique un champ, ou l’objet des informations et chaque ligne contient des valeurs pour ces champs. Cette disposition est efficace pour un ensemble d’informations répétées, telles que des données de série chronologique.

    Le format CSV est l’un des formats textes les plus simples. Il présente les données sous la forme d’une séquence d’enregistrements avec un en-tête commun. Pour l’encodage binaire, Apache Avro a un préambule semblable à un en-tête CSV, mais génère une taille d’encodage compacte.

Prise en charge de la bibliothèque

Envisagez d’utiliser des formats connus sur un modèle propriétaire.

Les formats connus sont pris en charge par les bibliothèques prises en charge universellement par la communauté. Avec les formats spécialisés, vous devez disposer de bibliothèques spécifiques. Votre logique métier peut avoir à contourner certains des choix de conception d’API fournis par les bibliothèques.

Pour le format basé sur un schéma, choisissez une bibliothèque d’encodage qui effectue des vérifications de compatibilité entre les schémas de lecture et d’écriture. Certaines bibliothèques d’encodage, telles qu’Apache Avro, s’attendent à ce que le consommateur spécifie à la fois le schéma d’écriture et le schéma de lecture avant de désérialiser le message. Cette vérification garantit que le consommateur est au fait des versions de schémas.

Interopérabilité

Vos choix de formats peuvent dépendre de la charge de travail ou de l’écosystème technologique.

Par exemple :

  • Azure Stream Analytics offre une prise en charge native de JSON, CSV et Avro. Lorsque vous utilisez Stream Analytics, il est judicieux de choisir l’un de ces formats si possible. Autrement, vous pouvez fournir un désérialiseur personnalisé, mais cela complique votre solution.

  • JSON est un format d’échange standard pour les API REST HTTP. Si votre application reçoit des charges utiles JSON de clients, puis les place dans une file d’attente de messages pour un traitement asynchrone, il peut être judicieux d’utiliser JSON pour la messagerie, plutôt que d’effectuer à nouveau l’encodage dans un format différent.

Il s’agit de deux exemples de considérations relatives à l’interopérabilité. En général, les formats standardisés sont plus interopérables que les formats personnalisés. Parmi les options textuelles, JSON est l’un des plus interopérables.

Choix de formats d’encodage

Voici quelques formats d’encodage populaires. Ne négligez pas les points à prendre en compte avant de choisir un format.

JSON

JSON est un standard ouvert (IETF RFC8259). Il s’agit d’un format texte qui suit le modèle tableau/dictionnaire/valeur.

JSON peut être utilisé pour baliser les métadonnées et vous pouvez analyser la charge utile sans schéma. JSON prend en charge l’option permettant de spécifier des champs facultatifs, ce qui offre une compatibilité ascendante et descendante.

Son plus grand avantage est qu’il est accessible partout. Il est le format le plus interopérable et le format d’encodage par défaut pour de nombreux services de messagerie.

Étant un format texte, il n’est pas efficace sur le réseau et n’est pas un choix idéal dans les cas où le stockage est problématique. Toutefois, si vous renvoyez directement à un client des éléments en cache par le biais du protocole HTTP, le stockage de données JSON permet d’économiser les coûts de désérialisation à partir d’un autre format et de sérialisation vers JSON.

Utilisez JSON pour les messages à enregistrement unique ou pour une séquence de messages dans laquelle chaque message présente un schéma différent. Évitez d'utiliser JSON pour une séquence d'enregistrements, comme pour des données de série chronologique.

Il existe d’autres variantes de JSON, comme BSON, un encodage binaire conçu pour fonctionner avec MongoDB.

Valeurs séparées par des virgules (CSV)

CSV est un format texte tabulaire. L’en-tête du tableau indique les champs. Il s’agit d’un choix judicieux lorsque le message contient un ensemble d’enregistrements.

L’inconvénient est l’absence de standardisation. Il existe de nombreuses façons d’exprimer des séparateurs, des en-têtes et des champs vides.

Protocol Buffers (Protobuf)

Protocol Buffers (ou protobuf) est un format de sérialisation qui utilise des fichiers de définition fortement typés pour définir des schémas dans des paires clé/valeur. Ces fichiers de définition sont ensuite compilés sous la forme de classes propres au langage utilisées pour la sérialisation et la désérialisation des messages.

Le message contient une faible charge utile binaire compressée, ce qui se traduit par un transfert plus rapide. L’inconvénient est que la charge utile n’est pas lisible par l’homme. En outre, étant donné que le schéma est externe, il n’est pas recommandé dans les cas où vous devez récupérer des données archivées.

Apache Avro

Apache Avro est un format de sérialisation binaire qui utilise un fichier de définition de manière comparable à Protobuf, mais il n’existe pas d’étape de compilation. À la place, les données sérialisées incluent toujours un préambule de schéma.

Le préambule peut contenir l’en-tête ou un identificateur de schéma. En raison de la taille d’encodage plus petite, Avro est recommandé pour la diffusion de données en continu. En outre, étant donné qu’il contient un en-tête qui s’applique à un ensemble d’enregistrements, il convient tout à fait pour les données tabulaires.

MessagePack

MessagePack est un format de sérialisation binaire conçu pour se révéler compact dans le cadre des transmissions sur le réseau. Il ne comporte aucun schéma de message ni contrôle du type de message. Ce format n’est pas recommandé pour le stockage en vrac.

CBOR

Concise Binary Object Representation (CBOR) (spécification) est un format binaire qui offre une taille d’encodage réduite. L’avantage de CBOR sur MessagePack est qu’il est conforme à l’IETF dans RFC7049.

Étapes suivantes