Table of Contents
Le architetture basate su eventi si basano sul flusso affidabile e coerente dei dati tra produttori e consumatori. Come si evolvono i sistemi, la struttura dei dati degli eventi - il suo schema - cambia in modo inevitabilmente. Nuovi campi sono aggiunti, vecchi campi sono deprecati, e talvolta interi modelli di dati cambiano. Senza una strategia deliberata per gestire questi cambiamenti, i sistemi di progettazione degli eventi possono diventare fragili, innescando errori di di disacramento, perdita dei dati o la versione silenziosa di rappresentazione di schema di schema di schema di schema di schema di schema di schema di elaborazione.
Comprendere la versione di evento
La versione degli eventi è la pratica di identificare e tracciare versioni distinte di uno schema di eventi in modo che i produttori e i consumatori possano coesistere in diverse fasi dell'evoluzione. L'obiettivo principale è quello di garantire che gli eventi possano essere interpretati correttamente indipendentemente da quando sono stati prodotti o dalla versione di un produttore.
La versione può essere implementata a vari livelli:
- Schema versioning[[] – La definizione dello schema porta un identificatore di versione (ad esempio ]), che è l'approccio più esplicito e funziona bene con i registri degli schemi.
- Payload versioning[[] – Il payload dell'evento include un campo di versione (ad esempio ]) che dice al consumatore quale schema usare per la deserializzazione.
- I dati di traduzione[] – Le informazioni di versione vengono memorizzate in intestazioni di messaggi o involucri di metadati, separati dal carico di paga.
La versione schematica centralizza la gestione degli schemi e semplifica i controlli di compatibilità, ma spesso richiede la ricerca del registro degli schemi di runtime. La versione di payload è semplice da implementare e funziona in sistemi senza un registro, ma può gonfiare il carico di paga e richiede un'attenta gestione dei campi di versione. La versione di Metadata mantiene pulito lo schema di payload, ma aggiunge complessità alla logica iniziale di analisi del consumatore.
Strategie per lo schema evolutivo
L'evoluzione dello schema è l'insieme di regole e pratiche che governano come gli schemi cambiano nel tempo, mantenendo la compatibilità. Le seguenti strategie formano la base di un piano di evoluzione dello schema robusto.
Convalida dello schema
Le scelte più popolari sono JSON Schema], []]Apache Avro[, e Protocol Buffers (Protobuf)], queste lingue forniscono meccanismi integrati per l'evoluzione, come valori predefiniti, campi opzionali e modalità di compatibilità.
Compatibilità con il retro
Un cambiamento di schema è compatibile all'indietro se un consumatore scritto per il nuovo schema può ancora leggere gli eventi prodotti dal vecchio schema.
- I campi opzionali[[] – I nuovi campi dovrebbero essere facoltativi con i valori predefiniti sensibili (ad esempio o con un valore zero).
- Aggiungo nuovi valori enum[[] – Nuovi valori enum possono essere aggiunti fintanto che non rompono la logica esistente.
- I campi di produzione nullable[[ – Il cambiamento di un campo richiesto a facoltativo è compatibile all'indietro; il contrario è un cambiamento di rottura.
- ]Utilizzando promozioni di tipo[[] – Ampliamento di un campo (ad esempio → []], [] → ]]]]) è spesso sicuro, ma restringimento può causare la perdita di dati.
Compatibilità inoltrata
La compatibilità avanzata assicura che un consumatore anziano possa leggere gli eventi prodotti da un produttore più recente, che è più difficile da raggiungere perché il consumatore non conosce i campi che non è stato programmato per aspettarsi.
- I lettori tolleranti[] – I consumatori dovrebbero ignorare i campi sconosciuti durante la deserializzazione. La maggior parte dei formati di schema supporta questo: l'opzione di Avro , Protobuf e la conservazione di campo sconosciuto, e JSON .
- I valori di default per i nuovi campi[[[] – I produttori possono popolare nuovi campi con valori di default quando il consumatore non può utilizzarli, ma questa è davvero una preoccupazione di compatibilità all’indietro.
- Avoiding construction change[[] – Rinominare i campi, cambiare i tipi, o riorganizzare le strutture nidificate in genere rompe la compatibilità in avanti. Tali cambiamenti richiedono una nuova versione evento.
Versione in Metadata
Un modello comune è quello di utilizzare un intestazione Apache Kafka o un campo in un oggetto di busta. Questo approccio consente ai produttori e ai consumatori di gestire la risoluzione degli schemi allo strato di applicazione senza modificare lo schema di carico stesso. Tuttavia, pone la responsabilità della versione del registro di sistema per eseguire la correzione dello schema di calcolo del consumatore.
Regista di schema
Un registro di schema è un servizio centralizzato che memorizza e convalida gli schemi in più versioni. Esso applica le regole di compatibilità (ad esempio, retro, avanti, pieno o nessuno) e fornisce un modo per i consumatori di recuperare lo schema necessario per deserializzare un evento. Confluent Schema Registry Registry]] è il più ampiamente usato per i sistemi basati su Kafka-CD, ma ci sono alternative di schema open source
Implementare la versione in pratica
Trasferirsi dalla teoria all'implementazione richiede fare scelte concrete su formati di serializzazione, strumenti e processi, le seguenti pratiche sono state provate in sistemi ad alto rendimento, produzione a base di eventi.
Scegliere un formato di serializzazione
Il formato di serializzazione determina come vengono definiti gli schemi, come si evolvono e quale compatibilità ti garantisce.
- Apache Avro[] – Progettato per l'evoluzione dello schema. Supporta modalità di compatibilità arretrate, in avanti e a pieno. Utilizza un formato binario compatto con una forte digitazione. Ben integrato con il Registro di schema Confluent.
- Protocol Buffers (Protobuf)[] – Supporta anche l'evoluzione tramite i numeri di campo e i campi opzionali. Più efficiente di Avro per alcuni carichi di lavoro. Funziona bene in sistemi poliglot con gRPC. Le regole di compatibilità sono meno integrate ma possono essere applicate con strumenti di terze parti come Buf.
- JSON Schema[] – Lettura umana, ampiamente supportato e facile da debug. Nessuna serializzazione binaria incorporata; tipicamente utilizzata con JSON. L'evoluzione è gestita tramite la spec (ad esempio ], ]]).
In molte organizzazioni, la scelta è già sostenuta da infrastrutture esistenti. Se stai iniziando fresco, Avro offre la più matura portautensili per l'evoluzione degli schemi per lo streaming degli eventi, mentre Protobuf è un forte contendente per la comunicazione dei microservizi.
Mantenere la compatibilità Matrici
Con l'aumento del numero di schemi e versioni, diventa essenziale documentare le versioni compatibili con le quali. Una versione di schema di matrice di compatibilità con le versioni di schema dei produttori di mappe dei consumatori, evidenziando eventuali incompatibilità conosciute. Questa matrice può essere mantenuta come file YAML nel repository di schemi o generata automaticamente da un registro di schema.
Ad esempio, una matrice potrebbe registrare che [] è compatibile con ] ma non è compatibile con il futuro, il che significa che i vecchi consumatori si romperanno se ricevono eventi v2. Questo costringe un rollout coordinato: tutti i consumatori sono aggiornati prima che qualsiasi produttore pubblichi v2, o il produttore continua a inviare eventi v1 fino a quando la flotta di consumo è pronta.
Automatizzazione della Testa di Compatibilità
Integrare i controlli di validazione e compatibilità dello schema nel vostro canale CI/CD. Ogni volta che un produttore cambia uno schema, il gasdotto dovrebbe:
- Registrare il nuovo schema contro il registro di schema con una modalità di compatibilità specificata.
- Se la registrazione non riesce, interrompere la costruzione e richiedere al team di fissare lo schema (o urtare esplicitamente la versione evento).
- Eseguire test di integrazione con i consumatori effettivi che esercitano il nuovo schema per catturare problemi di runtime.
- Se successo, pubblicare la nuova versione schema insieme a una voce changelog.
Strumenti come Il plugin Maven[]] o []] script di shell personalizzati[[] (e ora GitHub Actions) possono automatizzare questo. Per Protobuf, il Buf CLI fornisce un comando robusto che applica le regole di compatibilità.
Comunicazione e documentazione
Mantenere un changelog per ogni tipo di evento, notando ciò che è cambiato, perché e quali garanzie di compatibilità si applicano. Utilizzare uno strumento di documentazione dello schema (ad esempio, Backstage, un sito generato dal tuo registro di schema) in modo che i team possano navigare negli schemi disponibili e nella loro storia. Quando un cambiamento di rottura è inevitabile, annunciarlo bene in anticipo, fornire una finestra di migrazione è aggiornata e garantire che tutti i nuovi utenti dispiegano.
Maneggiare i cambiamenti di rottura
Nonostante i migliori sforzi per evitarli, a volte devono accadere cambiamenti di rottura (ad esempio, rinominare un campo, cambiare un tipo di dati, ristrutturare oggetti nidi).
- Argomenti correlati[[] – Produrre eventi su un nuovo argomento (ad esempio []]) mentre i vecchi consumatori continuano a leggere dal vecchio argomento. Questo è pulito ma duplica infrastrutture e richiede ai consumatori di sottoscrivere entrambi i temi durante la migrazione.
- Event version bumps[[] – Tenere lo stesso argomento ma aumentare il numero di versione principale dell'evento. I consumatori devono controllare la versione e decidere come deserializzare. Questo evita la proliferazione dell'argomento ma aggiunge logica di ramificazione nei consumatori.
- Dual writes[[] – Per un periodo di transizione, il produttore emette sia i vecchi che i nuovi formati di eventi. Questo è spesso usato come pietra stepping mentre i consumatori sono migrati.
Qualunque percorso scegli, abbina sempre il cambiamento di rottura con una chiara politica di deprecazione e un rollout monitorato.
Considerazioni avanzate
Quando la versione di eventi e l'evoluzione dello schema si intersecano con sourcing eventi, ambienti poliglotti o negozi di eventi specializzati, si presentano nuance aggiuntive.
Sourcing e Schema Evolution
In sistemi di gestione degli eventi, gli eventi sono la fonte della verità e non vengono mai eliminati o modificati. L'evoluzione dello schema diventa una preoccupazione critica del design perché ogni evento passato deve rimanere interpretabile per sempre. La pratica consigliata è quella di memorizzare gli eventi in un formato che supporta l'evoluzione schema nativamente (ad esempio, Avro o Protobuf con un registro di schema) e di aggiungere sempre campi con di default piuttosto che modificare quelli esistenti.
Versione in ambienti poliglot
Avro e Protobuf hanno entrambi una generazione di codice robusta per molte lingue, ma ogni lingua può gestire campi sconosciuti o valori di default leggermente in modo diverso.
Versione con Event Stores
EventStoreDB supporta tipi di eventi e proiezioni, ma l'evoluzione dello schema è ancora una vostra responsabilità. Con Kafka, il registro degli schemi è lo strumento principale. Tuttavia, quando si utilizza Kafka come un negozio di eventi a lungo termine, si considera l'aggiunta di una politica di ritenzione che compatta o elimina eventi vecchi solo dopo che tutti i consumatori sono stati migrati a un nuovo schema di rischio.
Conclusioni
La versione degli eventi e l'evoluzione degli schemi non sono facoltative in qualsiasi sistema a gestione eventi che si aspetti di vivere oltre un singolo ciclo di rilascio.Adottando i registri, scegliendo il formato di serializzazione giusto e automatizzando i controlli di compatibilità, i team possono evolvere i loro schemi di dati con fiducia.