Considérations relatives à 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. Après avoir choisi une technologie de messagerie, l’étape suivante consiste à définir la façon dont les messages seront encodés. Il existe de nombreuses options disponibles, mais le bon choix dépend de votre cas d’usage.
Cet article décrit certaines des considérations.
Besoins d’échange de messages
Un échange de messages entre un producteur et un consommateur a besoin :
- Forme ou structure qui définit la charge utile du message.
- Format d’encodage pour représenter la charge utile.
- Bibliothèques de sérialisation pour lire et écrire la charge utile encodée.
Le producteur du message définit la forme de 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 connexes (champs). Déterminez les caractéristiques des valeurs de ces champs. Considérez : Quel est le type de données le plus efficace ? La charge utile aura-t-elle toujours certains champs ? La charge utile aura-t-elle un enregistrement unique ou un ensemble répété de valeurs ?
Ensuite, choisissez 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 et la possibilité d’analyser la charge utile. Selon le format d’encodage, choisissez une bibliothèque de sérialisation bien prise en charge.
Un consommateur du message doit être conscient de ces décisions afin qu’il sache comment 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 continue sans problème. Lorsque le contrat change, le format d’encodage doit être capable de gérer la modification sans rompre le consommateur.
Certains formats d’encodage tels que JSON sont auto-décrivant, ce qui signifie qu’ils peuvent être analysés sans référencer un schéma. Toutefois, ces formats ont tendance à produire des messages plus volumineux. Avec d’autres formats, les données peuvent ne pas être analysées aussi facilement, mais les messages sont compacts. Cet article met en évidence certains facteurs qui peuvent vous aider à choisir un format.
Considérations relatives au format d’encodage
Le format d’encodage définit la façon dont un ensemble de données structurées est représenté sous 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. Vous pouvez également le récupérer ultérieurement à des fins d’audit. Pour un flux d’événements, vous pouvez lire une séquence d’enregistrements aussi rapidement que possible et la stocker pour l’analyse statistique.
Voici quelques points à prendre en compte lors du choix d’un format d’encodage.
Lisibilité humaine
L’encodage des messages peut être largement divisé en formats texte et binaires.
Avec l’encodage textuel, la charge utile du message est en texte brut et peut donc être inspectée par une personne sans utiliser de bibliothèques de code. Les formats lisibles par l’homme conviennent 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 grande. Un format texte commun est JSON.
Chiffrement
S’il existe des données sensibles dans les messages, déterminez si ces messages doivent être chiffrés dans leur intégralité, comme décrit dans ces instructions sur chiffrer les données Azure Service Bus au repos. Sinon, si seuls certains champs doivent être chiffrés et que vous préférez réduire les coûts cloud, envisagez d’utiliser une bibliothèque comme NServiceBus pour cela.
Taille d’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 textuels. Les formats binaires nécessitent une sérialisation/des bibliothèques de 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 filaire 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 est un problème. Les options pour les formats binaires incluent 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 la 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 qui peuvent être coûteux à gérer. En outre, ils ont besoin de bibliothèques spécialisées pour décoder, ce qui peut ne pas être pris 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 de la charge utile. Il existe deux approches principales pour stocker et distribuer des métadonnées :
Métadonnées avec balises. Dans certains encodages, notamment JSON, les champs sont marqués avec le type de données et l’identificateur, dans le corps du message. Ces formats sont auto-décrivant, car ils peuvent être analysés dans un dictionnaire de valeurs sans faire référence à un schéma. Un moyen pour le consommateur de comprendre les champs consiste à interroger les valeurs attendues. Par exemple, le producteur envoie une charge utile au format JSON. Le consommateur analyse le JSON dans un dictionnaire et vérifie l’existence de champs pour comprendre la charge utile. Un autre moyen est que le consommateur applique un modèle de données partagé par le producteur. Par exemple, si vous utilisez un langage typé statiquement, 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 :
Stockez le schéma en tant que préambule ou en-tête dans le message, mais séparément de la charge utile.
Stockez 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 le schéma enregistreur et lecteur. Protobuf et Apache Avro suivent cette approche. La principale différence est que protobuf a une définition de schéma indépendant du langage, mais Avro utilise 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 lecteur et d’enregistreur.
Une autre façon de stocker le schéma en externe dans un registre de schémas. 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 magasin externe. Les deux parties utilisent une bibliothèque spécifique au format pour lire et écrire des messages. Outre le stockage du schéma, un registre peut fournir des vérifications de compatibilité pour vous assurer que le contrat entre le producteur et le consommateur n’est pas rompu à mesure que le schéma évolue.
Avant de choisir une approche, décidez de ce qui est plus important : la taille des données de transfert ou la possibilité d’analyser les données archivées ultérieurement.
Le stockage du schéma avec la charge utile génère une plus grande taille d’encodage et est préféré pour les messages intermittents. Choisissez cette approche si le transfert de petits blocs d’octets est crucial ou que vous attendez une séquence d’enregistrements. Le coût de la maintenance d’un magasin 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 peut affecter le coût du stockage.
Contrôle des versions des schémas
À mesure que les exigences métier changent, la forme est censée changer et le schéma évoluera. Le contrôle de version permet au producteur d’indiquer les mises à jour de schéma qui peuvent inclure de nouvelles fonctionnalités. Il existe deux aspects du contrôle de version :
Le consommateur doit connaître les modifications.
L’une des façons est que le consommateur vérifie tous les champs pour déterminer si le schéma a changé. Un autre moyen est 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 modifications ne doivent pas affecter ou interrompre la logique métier des consommateurs.
Supposons qu’un champ soit ajouté à un schéma existant. Si les consommateurs utilisant la nouvelle version reçoivent une charge utile comme selon l'ancienne version, leur logique risque de dysfonctionner s'ils ne peuvent pas ignorer l'absence du champ nouveau. Compte tenu du cas inverse, supposons qu’un champ soit supprimé dans le 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 fournissent des fonctionnalités similaires par le biais de champs obligatoires et facultatifs.
Structure de charge utile
Considérez la façon dont les données sont organisées dans la charge utile. Est-ce une séquence d’enregistrements ou une charge utile unique discrète ? La structure de charge utile peut être classée dans l’un des modèles suivants :
Tableau/dictionnaire/valeur : définit les entrées qui contiennent des valeurs dans un ou plusieurs tableaux multidimensionnels. Les entrées ont des paires clé-valeur uniques. Il peut être étendu pour représenter les structures complexes. Voici quelques exemples : JSON, Apache Avro et MessagePack.
Cette disposition convient si les messages sont codés individuellement avec différents schémas. 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 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 répétitif d’informations, comme les données de série chronologique.
CSV est l’un des formats texte les plus simples. Il présente des 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 similaire à un en-tête CSV, mais génère une taille d’encodage compacte.
Prise en charge des bibliothèques
Envisagez d’utiliser des formats connus sur un modèle propriétaire.
Les formats connus sont pris en charge par le biais de bibliothèques qui sont universellement prises en charge par la communauté. Avec des formats spécialisés, vous avez besoin de bibliothèques spécifiques. Votre logique métier peut devoir contourner certains des choix de conception d’API fournis par les bibliothèques.
Pour le format basé sur le schéma, choisissez une bibliothèque d’encodage qui effectue des vérifications de compatibilité entre le lecteur et le schéma de l’enregistreur. 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 conscient des versions du schéma.
Interopérabilité
Votre choix de formats peut dépendre de la charge de travail ou de l’écosystème technologique particulier.
Par exemple:
Azure Stream Analytics prend en charge nativement 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 de les réencoder dans un autre format.
Il ne s’agit que de deux exemples de considérations d’interopérabilité. En général, les formats standardisés seront plus interopérables que les formats personnalisés. Dans les options textuelles, JSON est l’un des plus interopérables.
Choix pour les formats d’encodage
Voici quelques formats d’encodage populaires. Tenez compte des considérations avant de choisir un format.
JSON
JSON est une norme ouverte (IETF RFC8259). Il s’agit d’un format textuel qui suit le modèle tableau/dictionnaire/valeur.
JSON peut être utilisé pour marquer 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 facilite la compatibilité avant et descendante.
L’avantage le plus important est qu'elle est disponible universellement. Il est le plus interopérable et le format d’encodage par défaut pour de nombreux services de messagerie.
Étant un format textuel, il n’est pas efficace sur le fil et n’est pas un choix idéal dans les cas où le stockage est un problème. Si vous retournez des éléments mis en cache directement à un client via HTTP, le stockage json peut réduire le coût de désérialisation à partir d’un autre format, puis sérialiser au format JSON.
Utilisez JSON pour les messages à enregistrement unique ou pour une séquence de messages dans laquelle chaque message a un schéma différent. Évitez d’utiliser JSON pour une séquence d’enregistrements, par exemple pour les données de série chronologique.
Il existe d’autres variantes de JSON, telles que json binaire (BSON), qui est un encodage binaire aligné pour fonctionner avec MongoDB.
Valeurs séparées par des virgules (CSV)
CSV est un format tabulaire basé sur du texte. L’en-tête du tableau indique les champs. Il s’agit d’un choix préféré où le message contient un ensemble d’enregistrements.
L’inconvénient est l’absence de normalisation. Il existe de nombreuses façons d’exprimer des séparateurs, des en-têtes et des champs vides.
Mémoires tampons de protocole (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 sous forme de paires clé/valeur. Ces fichiers de définition sont ensuite compilés en classes spécifiques au langage utilisées pour la sérialisation et la désérialisation des messages.
Le message contient une petite charge utile binaire compressée, ce qui entraîne 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é pour 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 similaire à protobuf, mais il n’existe pas d’étape de compilation. Au lieu de cela, 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 plus petite taille d’encodage, Avro est recommandé pour la diffusion en continu de données. En outre, étant donné qu’il a un en-tête qui s’applique à un ensemble d’enregistrements, c’est un bon choix pour les données tabulaires.
MessagePack
MessagePack est un format de sérialisation binaire conçu pour être compact pour la transmission sur le fil. Il n’existe aucun schéma de message ou vérification du type de message. Ce format n’est pas recommandé pour le stockage en bloc.
CBOR
Concise Binary Object Representation (CBOR) (Spécification) est un format binaire qui offre une petite taille d’encodage. L’avantage de CBOR sur MessagePack est qu’il est conforme à IETF dans RFC7049.