Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Molte applicazioni cloud usano messaggi asincroni per scambiare informazioni tra i componenti del sistema. Un aspetto importante della messaggistica è il formato usato per codificare i dati del payload. Dopo aver scelto una tecnologia di messaggistica, il passaggio successivo consiste nel definire la modalità di codifica dei messaggi. Sono disponibili molte opzioni, ma la scelta giusta dipende dal caso d'uso.
Questo articolo descrive alcune considerazioni.
Esigenze di scambio di messaggi
Uno scambio di messaggi tra un produttore e un consumatore richiede:
- Forma o struttura che definisce il payload del messaggio.
- Formato di codifica per rappresentare il payload.
- Librerie di serializzazione per leggere e scrivere il payload codificato.
Il producer del messaggio definisce la forma del messaggio in base alla logica di business e alle informazioni da inviare ai consumer. Per strutturare la forma, dividere le informazioni in soggetti discreti o correlati (o campi). Decidere le caratteristiche dei valori per tali campi. Considerare le domande seguenti.
- Qual è il tipo di dati più efficiente?
- Il payload ha sempre campi specifici?
- Il payload ha un singolo record o un set ripetuto di valori?
Scegliere quindi un formato di codifica in base alle esigenze. I fattori specifici includono la possibilità di creare dati altamente strutturati, se necessario, il tempo necessario per codificare e trasferire il messaggio e la possibilità di analizzare il payload. Scegliere quindi un formato di codifica che soddisfi le proprie esigenze.
Il consumer deve comprendere queste decisioni per leggere correttamente i messaggi in arrivo.
Per trasferire i messaggi, il produttore serializza il messaggio in un formato codificato. Durante il ricevimento, l'utente deserializza il payload per accedere ai dati. Questo processo garantisce che entrambe le entità condividono lo stesso modello. Finché la forma rimane invariata, la messaggistica continua senza problemi. Quando il contratto cambia, il formato di codifica deve essere in grado di gestire la modifica senza interrompere il cliente.
Alcuni formati di codifica, ad esempio JSON, sono autodescrittura, il che significa che possono essere analizzati senza fare riferimento a uno schema. Tuttavia, questi formati spesso producono messaggi più grandi. Altri formati potrebbero non analizzare i dati con facilità, ma comportano messaggi più compatti. Questo articolo illustra i fattori chiave che consentono di scegliere il formato corretto.
Considerazioni sul formato di codifica
Il formato di codifica definisce il modo in cui un set di dati strutturati viene rappresentato come byte. Il tipo di messaggio può influenzare la scelta del formato. I messaggi correlati alle transazioni aziendali contengono probabilmente dati altamente strutturati. È anche possibile recuperare i dati strutturati in un secondo momento a scopo di controllo. Per un flusso di eventi, è possibile leggere una sequenza di record il più rapidamente possibile e archiviarla per l'analisi statistica.
Quando si sceglie un formato di codifica, prendere in considerazione i fattori seguenti.
Leggibilità umana
La codifica dei messaggi può essere suddivisa in modo ampio in formati binari e basati su testo.
Con la codifica basata su testo, il payload del messaggio è in testo normale, in modo che una persona possa esaminarla senza usare librerie di codice. Questo approccio semplifica la lettura e la comprensione dei dati. I formati leggibili sono adatti per i dati di archiviazione. Poiché un essere umano può leggere il payload, i formati basati su testo sono più facili da eseguire per il debug e l'invio ai log per la risoluzione degli errori.
Lo svantaggio della codifica basata su testo è che il payload tende a essere più grande. Le dimensioni del payload possono spesso essere ridotte tramite un processo di minificazione, purché possa essere invertito per la leggibilità umana quando necessario. I formati comuni basati su testo sono JSON e YAML.
Crittografia
Se nei messaggi sono presenti dati sensibili, valutare se tali messaggi devono essere crittografati interamente. In alternativa, se è necessario crittografare solo campi specifici e si preferisce ridurre i costi del cloud, è consigliabile usare una libreria come NServiceBus.
Dimensioni della codifica
Le dimensioni dei messaggi influiscono sulle prestazioni di input/output sulla rete. I formati binari sono più compatti rispetto ai formati basati su testo. I formati binari richiedono librerie di serializzazione e deserializzazione. Il payload può essere letto solo quando viene decodificato.
Usa un formato binario se vuoi ridurre l'impronta sulla rete e trasferire i messaggi più velocemente. Questa categoria di formato è consigliata negli scenari in cui l'archiviazione o la larghezza di banda di rete è un problema. Le opzioni per i formati binari includono Apache Avro, Google Protocol Buffers (protobuf), MessagePack e Concise Binary Object Representation (CBOR). I vantaggi e i svantaggi di questi formati sono descritti più avanti in Scelte per i formati di codifica.
Lo svantaggio del formato binario è che il carico utile non è leggibile. La maggior parte dei formati binari usa sistemi complessi che possono essere costosi da gestire. Inoltre, sono necessarie librerie specializzate per decodificare, che potrebbero non essere supportate se si desidera recuperare i dati di archiviazione.
Per i formati non binari, un processo di minificazione rimuove spazi e caratteri non necessari, pur mantenendo la conformità con le specificazioni del formato. Questo approccio consente di ridurre le dimensioni di codifica senza modificare la struttura. Valutare le funzionalità del codificatore per rendere la minimizzazione l'impostazione predefinita. Ad esempio, JsonSerializerOptions.WriteIndented
dei controlli System.Text.Json.JsonSerializer
di .NET gestisce la minificazione automatica durante la creazione di testo JSON.
Informazioni sul payload
Il payload di un messaggio arriva come una sequenza di byte. Per analizzare questa sequenza, il consumer deve avere accesso ai metadati che descrivono i campi dati nel payload. I due approcci principali per l'archiviazione e la distribuzione dei metadati sono:
Metadati taggati. In alcuni formati di codifica, in particolare JSON, i campi vengono contrassegnati con il tipo di dati e l'identificatore, all'interno del corpo del messaggio. Questi formati sono auto-descrittivi perché possono essere analizzati in un dizionario di valori senza fare riferimento a uno schema. Un modo per consentire al consumer di comprendere i campi consiste nell'eseguire query sui valori previsti. Ad esempio, il producer invia un payload in JSON. Il consumatore analizza il JSON in un dizionario e verifica l'esistenza dei campi per comprendere il payload. Un altro modo consiste nel consumatore che applica un modello di dati fornito dal produttore. Ad esempio, se si usa un linguaggio tipizzato in modo statico, molte librerie di serializzazione JSON possono analizzare una stringa JSON in una classe tipizzata.
Schema. Uno schema definisce formalmente la struttura e i campi dati di un messaggio. In questo modello, il producer e il consumer hanno un contratto tramite uno schema ben definito. Lo schema può definire i tipi di dati, i campi obbligatori o facoltativi, le informazioni sulla versione e la struttura del payload. Il produttore invia il payload in base allo schema dello scrittore. Il consumatore riceve il payload applicando uno schema di lettura. Il messaggio viene serializzato e deserializzato usando le librerie specifiche della codifica. Gli schemi possono essere distribuiti in due modi:
Archivia lo schema come preambolo o intestazione nel messaggio, ma separatamente dal payload.
Archiviare lo schema esternamente.
Alcuni formati di codifica definiscono lo schema e usano strumenti che generano classi dallo schema. Il produttore e il consumatore usano queste classi e librerie per serializzare e deserializzare il payload. Le librerie forniscono anche controlli di compatibilità tra lo schema writer e il lettore. Sia protobuf che Apache Avro seguono questo approccio. La differenza principale è che protobuf ha una definizione di schema indipendente dal linguaggio e Avro usa JSON compatto. Un'altra differenza consiste nel modo in cui entrambi i formati forniscono controlli di compatibilità tra gli schemi reader e writer.
Un altro modo per archiviare lo schema esternamente si trova in un Registro di sistema dello schema. Il messaggio contiene un riferimento allo schema e al payload. Il producer invia l'identificatore dello schema nel messaggio. Il consumatore recupera lo schema specificando quell'identificatore da un archivio esterno. Entrambe le parti usano una libreria specifica del formato per leggere e scrivere messaggi. Oltre a archiviare lo schema, un Registro di sistema può fornire controlli di compatibilità per garantire che il contratto tra il producer e il consumer non venga interrotto man mano che lo schema si evolve.
Prima di scegliere un approccio, decidere se le dimensioni dei dati di trasferimento o la possibilità di analizzare i dati archiviati in un secondo momento è più importante.
L'archiviazione dello schema insieme al payload produce una dimensione di codifica maggiore ed è ideale per i messaggi intermittenti. Scegliere questo approccio se il trasferimento di blocchi di byte più piccoli è fondamentale o si prevede una sequenza di record. Il costo per gestire un archivio schemi esterno può essere elevato.
Tuttavia, se la decodifica su richiesta del payload è più importante delle dimensioni, incluso lo schema con il payload o l'approccio ai metadati contrassegnati garantisce la decodifica successiva. Potrebbe esserci un aumento significativo delle dimensioni dei messaggi che influiscono sul costo dell'archiviazione.
Controllo delle versioni dello schema
Man mano che cambiano i requisiti aziendali, la forma dovrebbe cambiare e lo schema si evolverà. Il controllo delle versioni consente al producer di indicare gli aggiornamenti dello schema che potrebbero includere nuove funzionalità. Il controllo delle versioni presenta due aspetti chiave:
Il consumer deve tenere traccia e comprendere le modifiche.
Un modo è consentire al consumer di controllare tutti i campi per determinare se lo schema è stato modificato. Un altro modo consiste nel far sì che il produttore pubblichi un numero di versione dello schema con il messaggio. Quando lo schema si evolve, il produttore aumenta la versione.
Le modifiche non devono influire o interrompere la logica aziendale dei consumatori.
Si supponga che un campo venga aggiunto a uno schema esistente. Se i consumatori che utilizzano la nuova versione ricevono un payload secondo la versione precedente, la loro logica potrebbe risultare compromessa se non riescono a ignorare l'assenza del nuovo campo. Si consideri ora lo scenario opposto. Se un campo viene rimosso nel nuovo schema, i consumer che usano lo schema precedente potrebbero non essere in grado di leggere i dati.
I formati di codifica, ad esempio Avro, consentono di definire i valori predefiniti. Nell'esempio precedente, se il campo viene aggiunto con un valore predefinito, il campo mancante viene popolato con il valore predefinito. Altri formati, ad esempio protobuf, offrono funzionalità simili tramite campi obbligatori e facoltativi.
Struttura del payload
Valutare se i dati nel payload sono strutturati come una sequenza di record o come un singolo payload discreto. La struttura del payload può essere suddivisa in uno dei modelli seguenti:
Matrice/dizionario/valore: Definisce le voci che contengono valori in una o in matrici multidimensionali. Le voci hanno coppie chiave/valore uniche. Il modello può essere esteso per rappresentare strutture complesse. Alcuni esempi includono JSON, Apache Avro e MessagePack.
Questo layout è adatto se i messaggi vengono codificati singolarmente con schemi diversi. Se si dispone di più record, il payload può diventare eccessivamente ridondante. Questa ridondanza può causare l'ingrossamento del payload.
Dati tabulari: Le informazioni sono suddivise in righe e colonne. Ogni colonna indica un campo o l'oggetto delle informazioni e ogni riga contiene valori per tali campi. Questo layout è efficiente per un set ripetuto di informazioni, ad esempio i dati delle serie temporali.
Comma-Separated Valori (CSV) è uno dei formati più semplici basati su testo. Presenta i dati come sequenza di record con un'intestazione comune. Per la codifica binaria, Apache Avro ha un preambolo simile a un'intestazione CSV, ma che genera una dimensione di codifica più compatta.
Supporto della libreria
È consigliabile usare formati noti anziché un modello proprietario. I formati noti sono supportati tramite librerie supportate universalmente dalla community. Con formati specializzati, sono necessarie librerie specifiche. La logica di business potrebbe dover aggirare alcune delle scelte di progettazione dell'API fornite dalle librerie.
Per un formato basato su schema, scegliere una libreria di codifica che esegue controlli di compatibilità tra lo schema reader e writer. Librerie di codifica specifiche, come Apache Avro, si aspettano che il consumatore specifichi sia lo schema di scrittura che quello di lettura prima di deserializzare il messaggio. Questo controllo garantisce che il consumatore sia a conoscenza delle versioni dello schema.
Interoperabilità
La scelta dei formati può dipendere dal carico di lavoro o dall'ecosistema tecnologico specifico.
Per esempio:
Analisi di flusso di Azure offre il supporto nativo per JSON, CSV e Avro. Quando il carico di lavoro usa Analisi di flusso, è opportuno scegliere uno di questi formati.
JSON è un formato di interscambio standard per le API REST HTTP. Se l'applicazione riceve payload JSON dai client e li inserisce in una coda di messaggi per l'elaborazione asincrona, potrebbe essere opportuno usare JSON per la messaggistica anziché ripetere la codifica in un formato diverso.
Questi sono solo due esempi di considerazioni sull'interoperabilità. I formati standardizzati sono in genere più interoperabili rispetto ai formati personalizzati. Nelle opzioni basate su testo, JSON è uno dei più interoperabili.
Scelte per i formati di codifica
I formati di codifica più diffusi seguenti vengono usati per la rappresentazione e la trasmissione dei dati. Tenere presenti le considerazioni prima di scegliere un formato.
JSON (JavaScript Object Notation)
JSON è uno standard aperto, con il relativo formato definito dalla Internet Engineering Task Force (IETF) in RFC 8259. JSON è un formato basato su testo che segue il modello matrice/dizionario/valore.
JSON può essere usato per l'assegnazione di tag ai metadati ed è possibile analizzare il payload senza uno schema. JSON supporta l'opzione per specificare i campi facoltativi, che consentono la compatibilità con le versioni successive e precedenti.
Il vantaggio principale è che è universalmente disponibile. JSON è il formato di codifica più interoperabile e l'impostazione predefinita per molti servizi di messaggistica.
Poiché JSON è un formato basato su testo, non è efficiente in rete e non è ideale quando l'archiviazione è un problema. Usare le tecniche di minificazione quando possibile. Se si restituiscono elementi memorizzati nella cache direttamente a un client tramite HTTP, l'archiviazione di JSON potrebbe ridurre il costo della deserializzazione da un altro formato e quindi serializzare in JSON.
Usare JSON per i messaggi a record singolo o per una sequenza di messaggi in cui ogni messaggio ha uno schema diverso. Evitare di usare JSON per una sequenza di record, ad esempio per i dati delle serie temporali.
Esistono altre varianti di JSON, ad esempio JSON binario (BSON). BSON è una codifica binaria allineata per l'uso con MongoDB.
CSV
CSV è un formato tabulare basato su testo. L'intestazione della tabella indica i campi. Csv è particolarmente adatto per i messaggi che contengono un set di record.
Lo svantaggio di CSV è la mancanza di standardizzazione. Esistono diversi modi per esprimere separatori, intestazioni e campi vuoti.
Buffer di protocollo
Protocol Buffers (o protobuf) è un formato di serializzazione che utilizza file di definizione fortemente tipizzati per definire gli schemi di coppie chiave/valore. Questi file di definizione vengono quindi compilati in classi specifiche del linguaggio usate per serializzare e deserializzare i messaggi.
Il messaggio contiene un payload binario piccolo e compresso, che comporta un trasferimento dei dati più rapido. Lo svantaggio è che il payload non è leggibile per gli esseri umani. Inoltre, poiché lo schema viene archiviato esternamente, questo formato non è ideale per gli scenari che richiedono di recuperare i dati archiviati.
Apache Avro
Apache Avro è un formato di serializzazione binaria che usa un file di definizione simile a protobuf, ma senza un passaggio di compilazione. I dati serializzati invece includono sempre un preambolo dello schema.
Il preambolo può contenere l'intestazione o un identificatore dello schema. A causa delle dimensioni di codifica più piccole, Avro è consigliato per lo streaming dei dati. Inoltre, poiché ha un'intestazione che si applica a un set di record, è particolarmente adatta per i dati tabulari.
Apache Parquet
Apache Parquet è un formato di file di archiviazione a colonne in genere associato ad Apache Hadoop e ai framework di elaborazione dati correlati.
Apache Parquet supporta la compressione dei dati e offre funzionalità limitate per l'evoluzione dello schema. Questo formato viene in genere usato quando altre tecnologie Big Data nel carico di lavoro lo richiedono per la creazione o l'utilizzo dei dati.
MessagePack
MessagePack è un formato di serializzazione binario progettato per essere compatto per la trasmissione in rete. MessagePack non dispone della definizione dello schema e del controllo del tipo. Questo formato non è consigliato per l'archiviazione bulk.
CBOR
CBOR (Specification) è un formato binario che fornisce una piccola dimensione di codifica. Il vantaggio dell'uso di CBOR rispetto a MessagePack è la conformità con IETF in RFC7049.