Overwegingen voor berichtcodering
Veel cloudtoepassingen gebruiken asynchrone berichten om informatie uit te wisselen tussen onderdelen van het systeem. Een belangrijk aspect van berichten is het formaat dat wordt gebruikt om de payloadgegevens te coderen. Nadat u een berichttechnologiehebt gekozen, is de volgende stap het definiëren van hoe de berichten worden gecodeerd. Er zijn veel opties beschikbaar, maar de juiste keuze is afhankelijk van uw use-case.
In dit artikel worden enkele overwegingen beschreven.
Berichtuitwisselingsbehoeften
Een berichtuitwisseling tussen een producent en een consument heeft nodig:
- Een vorm of structuur die de nettolading van het bericht definieert.
- Een coderingsindeling die de nettolading vertegenwoordigt.
- Serialisatiebibliotheken voor het lezen en schrijven van de gecodeerde nettolading.
De producent van het bericht definieert de berichtvorm op basis van de bedrijfslogica en de informatie die het naar de consumenten wil verzenden. Als u de shape wilt structuren, verdeelt u de informatie in discrete of gerelateerde onderwerpen (velden). Bepaal de kenmerken van de waarden voor deze velden. Overweeg: Wat is het meest efficiënte gegevenstype? Heeft de nettolading altijd bepaalde velden? Heeft de nettolading één record of een herhaalde set waarden?
Kies vervolgens een coderingsindeling, afhankelijk van uw behoeften. Bepaalde factoren omvatten de mogelijkheid om zeer gestructureerde gegevens te maken als u deze nodig hebt, de tijd die nodig is om het bericht te coderen en over te dragen, en de mogelijkheid om de nettolading te parseren. Afhankelijk van de coderingsindeling kiest u een serialisatiebibliotheek die goed wordt ondersteund.
Een consument van het bericht moet op de hoogte zijn van deze beslissingen, zodat het weet hoe binnenkomende berichten moeten worden gelezen.
Om de berichten over te dragen, serialiseert de producent het bericht naar een coderingsindeling. Aan de ontvangende kant deserialiseert de consument de payload om de gegevens te gebruiken. Op deze manier delen beide entiteiten het model en zolang de vorm niet verandert, gaat het berichten zonder problemen door. Wanneer het contract wordt gewijzigd, moet de coderingsindeling in staat zijn om de wijziging te verwerken zonder de consument te verstoren.
Sommige coderingsindelingen, zoals JSON, beschrijven zelf, wat betekent dat ze kunnen worden geparseerd zonder naar een schema te verwijzen. Dergelijke indelingen leveren echter meestal grotere berichten op. Met andere indelingen worden de gegevens mogelijk niet zo eenvoudig geparseerd, maar de berichten zijn compact. In dit artikel worden enkele factoren beschreven waarmee u een indeling kunt kiezen.
Overwegingen voor coderingsformaat
De coderingsindeling definieert hoe een set gestructureerde gegevens wordt weergegeven als bytes. Het type bericht kan van invloed zijn op de indelingskeuze. Berichten met betrekking tot zakelijke transacties bevatten hoogstwaarschijnlijk zeer gestructureerde gegevens. Mogelijk wilt u deze later ophalen voor controledoeleinden. Voor een stroom gebeurtenissen wilt u mogelijk zo snel mogelijk een reeks records lezen en opslaan voor statistische analyse.
Hier volgen enkele punten waarmee u rekening moet houden bij het kiezen van een coderingsindeling.
Menselijke leesbaarheid
Berichtcodering kan breed worden onderverdeeld in op tekst gebaseerde en binaire indelingen.
Met tekstgebaseerde codering is de berichtlading in platte tekst en kan daarom door een persoon worden geïnspecteerd zonder codebibliotheken te gebruiken. Leesbare indelingen voor mensen zijn geschikt voor archiveringsgegevens. Omdat een mens de nettolading kan lezen, zijn tekstindelingen eenvoudiger om fouten op te sporen en naar logboeken te verzenden voor het oplossen van fouten.
Het nadeel is dat de belading meestal groter is. Een algemene indeling op basis van tekst is JSON.
Versleuteling
Als er gevoelige gegevens in de berichten staan, kunt u overwegen of deze berichten volledig gecodeerd moeten worden, zoals beschreven in deze richtlijnen over het coderen van Azure Service Bus-gegevens in rust. Als er alleen bepaalde velden moeten worden versleuteld en u de cloudkosten wilt verlagen, kunt u overwegen om hiervoor een bibliotheek zoals NServiceBus te gebruiken.
Coderingsgrootte
Berichtgrootte is van invloed op de netwerk-I/O-prestaties via de kabel. Binaire indelingen zijn compacter dan op tekst gebaseerde indelingen. Binaire indelingen vereisen serialisatie-/deserialisatiebibliotheken. De payload kan niet worden gelezen tenzij deze is gedecodeerd.
Gebruik een binaire indeling als u het netwerkverkeer wilt verminderen en berichten sneller wilt versturen. Deze indelingscategorie wordt aanbevolen in scenario's waarin opslag of netwerkbandbreedte een probleem is. Opties voor binaire indelingen zijn Apache Avro, Google Protocol Buffers (protobuf), MessagePack en Beknopte binaire objectweergave (CBOR). De voor- en nadelen van die formaten worden beschreven in Deze sectie.
Het nadeel is dat de nettolading niet door mensen kan worden gelezen. De meeste binaire indelingen maken gebruik van complexe systemen die kostbaar kunnen worden onderhouden. Ze hebben ook speciale bibliotheken nodig om te decoderen, wat mogelijk niet wordt ondersteund als u archiveringsgegevens wilt ophalen.
Inzicht in de nettolading
Een nettolading van een bericht arriveert als een reeks bytes. Om deze volgorde te parseren, moet de consument toegang hebben tot metagegevens die de gegevensvelden binnen de payload beschrijven. Er zijn twee hoofdmethoden voor het opslaan en distribueren van metagegevens:
gelabelde metagegevens. In sommige coderingen, met name JSON, worden velden gelabeld met het gegevenstype en de id, binnen de hoofdtekst van het bericht. Deze indelingen zijn zelfbeschrijvend omdat ze kunnen worden geparseerd in een woordenboek met waarden zonder naar een schema te verwijzen. Een manier om de consument inzicht te geven in de velden is door een query uit te voeren op verwachte waarden. De producer verzendt bijvoorbeeld een payload in JSON. De gebruiker parseert de JSON in een woordenboek en controleert het bestaan van velden om de payload te begrijpen. Een andere manier is dat de consument een gegevensmodel toepast dat door de producent wordt gedeeld. Als u bijvoorbeeld een statisch getypte taal gebruikt, kunnen veel JSON-serialisatiebibliotheken een JSON-tekenreeks parseren in een getypte klasse.
Schema. Een schema definieert formeel de structuur- en gegevensvelden van een bericht. In dit model hebben de producent en consument een contract via een goed gedefinieerd schema. Het schema kan de gegevenstypen, vereiste/optionele velden, versiegegevens en de structuur van de nettolading definiëren. De producent verzendt het gegevenspakket volgens het schrijverschema. De consument ontvangt de payload door een leesschema toe te passen. Het bericht wordt geserialiseerd/gedeserialiseerd door middel van bibliotheken die specifiek zijn voor codering. Er zijn twee manieren om schema's te distribueren:
Sla het schema op als inleiding of koptekst in het bericht, maar los van de inhoud.
Sla het schema extern op.
Sommige coderingsindelingen definiëren het schema en maken gebruik van hulpprogramma's die klassen genereren op basis van het schema. De producent en consument gebruiken deze klassen en bibliotheken om de last te serialiseren en deserialiseren. De bibliotheken bieden ook compatibiliteitscontroles tussen het schrijver- en lezerschema. Zowel protobuf als Apache Avro volgen die benadering. Het belangrijkste verschil is dat protobuf een taalagnostische schemadefinitie heeft, maar Avro maakt gebruik van compacte JSON. Een ander verschil is de manier waarop beide indelingen compatibiliteitscontroles bieden tussen lezer- en schrijfschema's.
Een andere manier om het schema extern op te slaan in een schemaregister. Het bericht bevat een verwijzing naar het schema en de payload. De producent verzendt de schema-identificator in het bericht en de consument haalt het schema op door die identificator op te geven uit een externe opslag. Beide partijen gebruiken een indelingsspecifieke bibliotheek om berichten te lezen en te schrijven. Afgezien van het opslaan van het schema kan een register compatibiliteitscontroles bieden om ervoor te zorgen dat het contract tussen de producent en consument niet wordt verbroken naarmate het schema zich ontwikkelt.
Voordat u een benadering kiest, moet u bepalen wat belangrijker is: de grootte van de overdrachtsgegevens of de mogelijkheid om de gearchiveerde gegevens later te parseren.
Het opslaan van het schema samen met de nettolading levert een grotere coderingsgrootte op en heeft de voorkeur voor onregelmatige berichten. Kies deze methode als het overdragen van kleinere segmenten van bytes cruciaal is of als u een reeks records verwacht. De kosten voor het onderhouden van een extern schemaarchief kunnen hoog zijn.
Als on-demand decodering van de payload echter belangrijker is dan de grootte, zorgt het opnemen van het schema met de payload of de benadering van getagde metadata ervoor dat decodering achteraf gegarandeerd is. Mogelijk is er een aanzienlijke toename van de berichtgrootte en kan dit van invloed zijn op de opslagkosten.
Schemaversiebeheer
Naarmate de bedrijfsvereisten veranderen, wordt verwacht dat de shape verandert en zal het schema zich ontwikkelen. Met versiebeheer kan de producent schema-updates aangeven die mogelijk nieuwe functies bevatten. Er zijn twee aspecten voor versiebeheer:
De consument moet op de hoogte zijn van de wijzigingen.
Een manier is dat de consument alle velden controleert om te bepalen of het schema is gewijzigd. Een andere manier is dat de producent een schemaversienummer met het bericht publiceert. Wanneer het schema zich ontwikkelt, wordt de versie verhoogd door de producent.
Wijzigingen mogen de bedrijfslogica van consumenten niet beïnvloeden of verbreken.
Stel dat een veld wordt toegevoegd aan een bestaand schema. Als consumenten die de nieuwe versie gebruiken een belasting zoals in de oude versie krijgen, kan hun logica falen als ze het ontbreken van het nieuwe veld niet kunnen negeren. Gezien het omgekeerde geval, stel dat een veld wordt verwijderd in het nieuwe schema. Consumenten die het oude schema gebruiken, kunnen de gegevens mogelijk niet lezen.
Coderingsindelingen zoals Avro bieden de mogelijkheid om standaardwaarden te definiëren. Als in het voorgaande voorbeeld het veld wordt toegevoegd met een standaardwaarde, wordt het ontbrekende veld gevuld met de standaardwaarde. Andere indelingen, zoals protobuf, bieden vergelijkbare functionaliteit via vereiste en optionele velden.
Payloadstructuur
Houd rekening met de manier waarop gegevens in het gegevenspakket worden gerangschikt. Is het een reeks records of een afzonderlijke enkele payload? De payloadstructuur kan worden ingedeeld in een van de volgende modellen:
Matrix/woordenlijst/waarde: definieert vermeldingen die waarden bevatten in een of meerdimensionale matrices. Vermeldingen hebben unieke sleutel-waardeparen. Het kan worden uitgebreid om de complexe structuren weer te geven. Enkele voorbeelden zijn JSON, Apache Avro en MessagePack.
Deze indeling is geschikt als berichten afzonderlijk zijn gecodeerd met verschillende schema's. Als u meerdere records hebt, kan de gegevenslading overbodig worden en daardoor opzwellen.
Tabelgegevens: Informatie is onderverdeeld in rijen en kolommen. Elke kolom geeft een veld aan, of het onderwerp van de informatie en elke rij bevat waarden voor deze velden. Deze indeling is efficiënt voor een herhalende set gegevens, zoals tijdreeksgegevens.
CSV is een van de eenvoudigste tekstgebaseerde formaten. Het presenteert gegevens als een reeks records met een gemeenschappelijke header. Voor binaire codering heeft Apache Avro een preambule die lijkt op een CSV-header, maar produceert een compacte coderingsgrootte.
Bibliotheekondersteuning
Overweeg het gebruik van bekende indelingen in plaats van een eigen model.
Bekende formaten worden ondersteund via bibliotheken die universeel door de gemeenschap worden ondersteund. Met gespecialiseerde indelingen hebt u specifieke bibliotheken nodig. Uw bedrijfslogica moet mogelijk een aantal van de API-ontwerpopties van de bibliotheken omzeilen.
Kies voor indeling op basis van een schema een coderingsbibliotheek die compatibiliteitscontroles tussen de lezer en het schrijfschema maakt. Bepaalde coderingsbibliotheken, zoals Apache Avro, verwachten dat de consument zowel het schrijver- als het lezerschema opgeeft voordat het bericht wordt gedeserialiseerd. Deze controle zorgt ervoor dat de consument op de hoogte is van de schemaversies.
Interoperabiliteit
Uw keuze voor indelingen is mogelijk afhankelijk van de specifieke workload of het technologie-ecosysteem.
Bijvoorbeeld:
Azure Stream Analytics biedt systeemeigen ondersteuning voor JSON, CSV en Avro. Wanneer u Stream Analytics gebruikt, is het zinvol om indien mogelijk een van deze indelingen te kiezen. Zo niet, dan kunt u een aangepaste deserializeropgeven, maar dit voegt enige extra complexiteit toe aan uw oplossing.
JSON is een standaardindeling voor HTTP REST API's. Als uw toepassing JSON-nettoladingen van clients ontvangt en deze vervolgens in een berichtenwachtrij plaatst voor asynchrone verwerking, kan het zinvol zijn om JSON te gebruiken voor de berichten, in plaats van opnieuw te coderen in een andere indeling.
Dit zijn slechts twee voorbeelden van interoperabiliteitsoverwegingen. Over het algemeen zijn gestandaardiseerde indelingen beter compatibel dan aangepaste indelingen. In tekstopties is JSON een van de meest interoperabele opties.
Opties voor coderingsindelingen
Hier volgen enkele populaire coderingsindelingen. Houd rekening met de overwegingen voordat u een formaat kiest.
JSON
JSON- is een open standaard (IETF-RFC8259). Het is een op tekst gebaseerde indeling die het matrix-/woordenlijst-/waardemodel volgt.
JSON kan worden gebruikt voor het taggen van metagegevens en u kunt de nettolading parseren zonder een schema. JSON ondersteunt de mogelijkheid om optionele velden te specificeren, wat helpt bij voorwaartse en achterwaartse compatibiliteit.
Het grootste voordeel is dat het universeel beschikbaar is. Het is de meest interoperabele en de standaardcoderingsindeling voor veel berichtenservices.
Omdat het een tekstindeling is, is het niet efficiënt via de kabel en niet een ideale keuze in gevallen waarin opslag een probleem is. Als u items in de cache rechtstreeks naar een client retourneert via HTTP, kan het opslaan van JSON de kosten voor het deserialiseren van een andere indeling besparen en vervolgens serialiseren naar JSON.
Gebruik JSON voor berichten met één record of voor een reeks berichten waarin elk bericht een ander schema heeft. Vermijd het gebruik van JSON voor een reeks records, zoals voor tijdreeksgegevens.
Er zijn andere variaties van JSON, zoals binaire JSON (BSON), een binaire codering die is afgestemd op het werken met MongoDB.
Comma-Separated Waarden (CSV)
CSV is een tabelindeling op basis van tekst. De koptekst van de tabel geeft de velden aan. Het is een voorkeurskeuze waarbij het bericht een set records bevat.
Het nadeel is gebrek aan standaardisatie. Er zijn veel manieren om scheidingstekens, kopteksten en lege velden uit te drukken.
Protocol Buffers (protobuf)
ProtocolBuffers (of protobuf) is een serialisatie-indeling die gebruikmaakt van sterk getypte definitiebestanden om schema's in sleutel-/waardeparen te definiëren. Deze definitiebestanden worden vervolgens gecompileerd naar taalspecifieke klassen die worden gebruikt voor het serialiseren en deserialiseren van berichten.
Het bericht bevat een gecomprimeerde binaire kleine nettolading, wat resulteert in een snellere overdracht. Het nadeel is dat de nettolading niet door mensen kan worden gelezen. Omdat het schema extern is, wordt het niet aanbevolen voor gevallen waarin u gearchiveerde gegevens moet ophalen.
Apache Avro
Apache Avro- is een binaire serialisatie-indeling die gebruikmaakt van definitiebestand dat vergelijkbaar is met protobuf, maar er is geen compilatiestap. In plaats daarvan bevatten geserialiseerde gegevens altijd een schema-preambule.
De preambule kan de header of een schema-id bevatten. Vanwege de kleinere coderingsgrootte wordt Avro aanbevolen voor streaminggegevens. Omdat het een header heeft die van toepassing is op een set records, is het een goede keuze voor tabellaire gegevens.
MessagePack
MessagePack is een binaire serialisatie-indeling die is ontworpen om compact te zijn voor verzending via de kabel. Er zijn geen berichtschema's of controle van berichttypen. Deze indeling wordt niet aanbevolen voor bulkopslag.
CBOR
Beknopte binaire objectweergave (CBOR) (Specificatie) is een binaire indeling die kleine coderingsgrootte biedt. Het voordeel van CBOR over MessagePack is dat het voldoet aan IETF in RFC7049.