Apache Avro: kontraktet mellan moduler

Två ingenjörer sedda bakifrån vid ett gemensamt bord på ett stilla kontor, en stor väggskärm mellan dem som visar ett abstrakt blågrått diagram över ett formulär och dess versioner, ett utskrivet ark under den enes hand, en enda blå statuslampa på skärmens ram

Handelsteamet lägger till en rabattprocent på ordern. Det är en liten ändring, överenskommen på ett möte, och modulen som skapar order börjar skicka den samma eftermiddag. Ekonomimodulen, som har läst order i två år, känner inte till fältet och slutar ta emot meddelandet. Ingen avsåg en kontraktsändring. Det fanns ett kontrakt, det var bara aldrig nedskrivet någon annanstans än i två kodstycken som brukade vara överens.

I ett system byggt av moduler som utbyter händelser är varje händelse en överenskommelse. Apache Avro är ett av de format som skriver in den överenskommelsen i själva datan, och skälet till att det ingår i designen av Hurukans datalager, som är under uppbyggnad, handlar mindre om byte än om vad som händer när överenskommelsen måste ändras.

Schemat följer med datan

En Avro-post är en kompakt binär rad. På egen hand kan den inte läsas: fältnamnen, typerna och ordningen finns inte i bytena. De finns i schemat, skrivet i JSON, och specifikationen definierar en liten uppsättning typer att skriva det med: null, boolean, int, long, float, double, bytes, string, och de sammansatta record, enum, array, map, union och fixed. Ett fält kan bära ett standardvärde, och det standardvärdet är vad som senare gör en ändring överlevbar. Aktuell version är 1.12.2 (projektets blogg, kontrollerat den 21 oktober 2026).

Schemat når läsaren på ett av två sätt. I en fil lägger formatet Object Container File schemat i huvudet, följt av block av poster åtskilda av en synkmarkör, så att en fil som hittas år senare fortfarande förklarar sig själv. På en meddelandebuss, där det vore slöseri att skicka schemat med varje händelse, lägger specifikationens single-object encoding en tvåbytesmarkör och ett åttabytes fingeravtryck av schemat framför varje post; ett register håller schemat under det fingeravtrycket. Det allmänt använda Confluent-registret gör samma sak med sin egen inramning, en magisk byte och en fyrabytes schemaidentifierare före Avro-bytena (Confluents dokumentation).

Hur som helst gissar läsaren aldrig. Den har skrivarens schema och sitt eget, och resten är regler.

Upplösning: hur en läsare möter en skrivare den aldrig sett

Specifikationen anger vad som händer när skrivarens schema och läsarens schema skiljer sig åt. Fält matchas efter namn. Ett fält som skrivaren skickade och läsaren inte har ignoreras. Ett fält som läsaren förväntar sig och skrivaren inte skickade fylls från läsarens standardvärde, och om det inte finns något standardvärde misslyckas läsningen med ett tydligt skäl. Vissa typer får befordras på vägen: en int får läsas som long, en long som float eller double, en float som double, och string och bytes får läsas som varandra. En union matchas mot den första kompatibla grenen på läsarens sida.

Utskrivna är de reglerna hela disciplinen kring rabattfältet. Lägg till det med ett standardvärde och ekonomimodulen fortsätter läsa, ignorerar fältet tills den lärs att använda det. Lägg till det utan standardvärde och ta bort ett gammalt fält i samma ändring, och den äldsta läsaren i företaget stannar. Reglerna är inte råd; de avgör vilken version av morgonen du får.

En schemaändring som ett förslag

I Hurukan är designen att ett händelseschema är ett objekt i ontologin som vilket annat som helst: det har en ägare, versioner och en plats i registret. Det förvandlar rabattfältet från en eftermiddags kodändring till en kort, registrerad väg.

En agent föreslår. Handelsmodulen behöver ett nytt fält; en agent utarbetar schemaändringen, med standardvärdet, typen och skälet, och namnger de moduler som läser den här händelsen.

Registret kontrollerar. Den föreslagna versionen testas mot läsarnas scheman enligt upplösningsreglerna ovan. En ändring som skulle stoppa en befintlig läsare avvisas innan någon ser den, med läsaren namngiven.

Ägaren godkänner. En kompatibel ändring är fortfarande en ändring av en överenskommelse mellan moduler. Händelsens ägare, en människa, godkänner den, och först då börjar producenterna skriva den nya versionen.

Registret behåller det. Godkännandet, versionen och tidpunkten skrivs in i registret, så att frågan “när dök rabatter upp på order, och vem tillät det” har ett svar ett år senare. Det är samma väg som varje ändring i systemet tar: en agent föreslår, en människa beslutar, systemet registrerar. Den större idén finns i det levande tillståndet och registret.

Vad Avro inte är till för

Avro bär händelser väl och läser hela poster väl. Det är en dålig layout för den fråga superintelligensen oftast ställer, några få fält över en miljon rader, eftersom varje fält ligger i vägen för varje annat. Därför samlas, i designen, händelser i Avro i omgångar till kolumner när de väl har tagits emot. Vilken form som hör hemma var anges i Parquet och Avro: händelsen och registret.

Avro dyker också upp på ett ställe få tittar: tabellformatet Apache Iceberg skriver sina manifest, listorna över de datafiler som utgör en tabell, som Avro-filer (Iceberg-specifikationen). Radformatet som bär händelser mellan moduler bär också registrets bokföring.

Vad som stannar hos människor

En agent kan utarbeta ett schema, köra kompatibilitetskontrollen och namnge läsarna. Den kan inte besluta att ett fält som ekonomimodulen förlitade sig på får försvinna, att ett standardvärde på noll är ett sant påstående om gamla order, eller att en läsare får tillåtas gå sönder. Det är beslut om verksamhetens innebörd, och i Hurukan fattas de av händelsens ägare och skrivs ner.

Ett test du kan göra i dag

Välj ett meddelande som rör sig mellan två av dina system. Ta reda på var dess fält är definierade. Om svaret är “i den sändande koden” och “i den mottagande koden” har du två definitioner och inget kontrakt. Fråga sedan vem som skulle godkänna att ett fält läggs till, med namn. Om det inte finns något namn kommer nästa fält att läggas till av den som behöver det först, och upptäckas av den det går sönder för. Sidan om datalagret beskriver var det kontraktet är tänkt att bo i Hurukan; översikten visar modulerna runt omkring.