Apache Avro: het contract tussen modules

Het verkoopteam voegt een kortingspercentage toe aan de order. Het is een kleine wijziging, afgesproken in een vergadering, en de module die orders aanmaakt begint het dezelfde middag te versturen. De financiële module, die al twee jaar orders leest, kent het veld niet en accepteert het bericht niet meer. Niemand had de bedoeling een contract te wijzigen. Er was een contract, het stond alleen nergens geschreven behalve in twee stukken code die het tot dan toe met elkaar eens waren.
In een systeem dat is opgebouwd uit modules die gebeurtenissen uitwisselen, is elke gebeurtenis een overeenkomst. Apache Avro is een van de formaten die die overeenkomst in de data zelf schrijven, en de reden dat het in het ontwerp van de laag Data van Hurukan zit, die in aanbouw is, heeft minder met bytes te maken dan met wat er gebeurt wanneer de overeenkomst moet veranderen.
Het schema reist met de data mee
Een Avro-record is een compacte binaire rij. Op zichzelf is het niet te lezen: de veldnamen, typen en volgorde staan niet in de bytes. Ze staan in het schema, geschreven in JSON, en de specificatie definieert een kleine set typen om het mee te schrijven: null, boolean, int, long, float, double, bytes, string, en de complexe typen record, enum, array, map, union en fixed. Een veld kan een standaardwaarde dragen, en die standaardwaarde is wat verandering later overleefbaar maakt. De huidige release is 1.12.2 (projectblog, gecontroleerd op 21 oktober 2026).
Het schema bereikt de lezer op een van twee manieren. In een bestand zet het Object Container File-formaat het schema in de header, gevolgd door blokken records gescheiden door een synchronisatiemarkering, zodat een bestand dat jaren later wordt gevonden zichzelf nog uitlegt. Op een berichtenbus, waar het schema bij elke gebeurtenis meesturen verspilling zou zijn, zet de single-object encoding van de specificatie een markering van twee bytes en een vingerafdruk van acht bytes van het schema voor elk record; een register bewaart het schema onder die vingerafdruk. Het veelgebruikte Confluent-register doet hetzelfde met een eigen omlijsting, een magic byte en een schema-identificator van vier bytes voor de Avro-bytes (Confluent-documentatie).
Hoe dan ook: de lezer raadt nooit. Hij heeft het schema van de schrijver en zijn eigen schema, en de rest zijn regels.
Oplossing: hoe een lezer een schrijver ontmoet die hij nooit heeft gezien
De specificatie legt vast wat er gebeurt wanneer het schema van de schrijver en dat van de lezer verschillen. Velden worden op naam gekoppeld. Een veld dat de schrijver stuurde en de lezer niet heeft, wordt genegeerd. Een veld dat de lezer verwacht en de schrijver niet stuurde, wordt gevuld vanuit de standaardwaarde van de lezer, en als er geen standaardwaarde is, mislukt het lezen met een duidelijke reden. Sommige typen mogen onderweg worden gepromoveerd: een int mag als long worden gelezen, een long als float of double, een float als double, en string en bytes mogen als elkaar worden gelezen. Een union wordt gekoppeld aan de eerste compatibele tak aan de kant van de lezer.
Uitgeschreven zijn die regels de hele discipline van het kortingsveld. Voeg het toe met een standaardwaarde en de financiële module blijft lezen, en negeert het veld totdat haar is geleerd het te gebruiken. Voeg het toe zonder standaardwaarde en verwijder in dezelfde wijziging een oud veld, en de oudste lezer in het bedrijf valt stil. De regels zijn geen advies; ze bepalen welke versie van de ochtend u krijgt.
Een schemawijziging als voorstel
In Hurukan is het ontwerp dat een gebeurtenisschema een object van de ontologie is als elk ander: het heeft een eigenaar, versies en een plek in het register. Dat maakt van het kortingsveld, in plaats van een codewijziging van één middag, een kort, vastgelegd pad.
Een agent stelt voor. De verkoopmodule heeft een nieuw veld nodig; een agent stelt de schemawijziging op, met de standaardwaarde, het type en de reden, en noemt de modules die deze gebeurtenis lezen.
Het register controleert. De voorgestelde versie wordt getest tegen de schema’s van de lezers volgens de oplossingsregels hierboven. Een wijziging die een bestaande lezer zou stilleggen wordt afgewezen voordat iemand haar ziet, met de naam van de lezer erbij.
De eigenaar keurt goed. Een compatibele wijziging is nog steeds een wijziging van een overeenkomst tussen modules. De eigenaar van de gebeurtenis, een mens, keurt haar goed, en pas dan beginnen producenten de nieuwe versie te schrijven.
Het register bewaart het. De goedkeuring, de versie en het tijdstip worden in het register geschreven, zodat de vraag “wanneer verschenen kortingen op orders, en wie heeft dat toegestaan” een jaar later een antwoord heeft. Dat is hetzelfde pad dat elke wijziging in het systeem volgt: een agent stelt voor, een mens besluit, het systeem legt vast. Het bredere idee staat in de actuele toestand en het register.
Waar Avro niet voor is
Avro draagt gebeurtenissen goed en leest hele records goed. Het is een slechte indeling voor de vraag die superintelligentie het vaakst stelt, enkele velden over een miljoen rijen, omdat elk veld elk ander veld in de weg staat. Daarom worden in het ontwerp gebeurtenissen in Avro, zodra ze zijn geaccepteerd, gebatcht naar kolommen. Welke vorm waar hoort, staat in Parquet en Avro: de gebeurtenis en het register.
Avro duikt ook op op een plek waar weinig mensen kijken: het tabelformaat Apache Iceberg schrijft zijn manifesten, de lijsten van databestanden die een tabel vormen, als Avro-bestanden (Iceberg-specificatie). Het rijformaat dat gebeurtenissen tussen modules draagt, draagt ook de boekhouding van het register.
Wat bij mensen blijft
Een agent kan een schema opstellen, de compatibiliteitscontrole uitvoeren en de lezers benoemen. Hij kan niet beslissen dat een veld waarop de financiële module vertrouwde mag verdwijnen, dat een standaardwaarde van nul een ware uitspraak is over oude orders, of dat een lezer mag falen. Dat zijn beslissingen over de betekenis van het bedrijf, en in Hurukan worden ze genomen door de eigenaar van de gebeurtenis en opgeschreven.
Een test die u vandaag kunt doen
Kies één bericht dat tussen twee van uw systemen beweegt. Zoek waar zijn velden zijn gedefinieerd. Als het antwoord “in de verzendende code” en “in de ontvangende code” is, hebt u twee definities en geen contract. Vraag dan wie, bij naam, het toevoegen van een veld zou goedkeuren. Als er geen naam is, wordt het volgende veld toegevoegd door wie het het eerst nodig heeft, en ontdekt door wie het breekt. De pagina laag Data beschrijft waar dat contract in Hurukan hoort te leven; het overzicht toont de modules eromheen.
- Apache Avro
- schemaregister
- gebeurteniscontracten
- schema-evolutie
- laag Data