Apache Avro: umowa między modułami

Dwoje inżynierów widzianych od tyłu przy wspólnym stole w cichym biurze, między nimi duży ekran ścienny z abstrakcyjnym niebiesko-szarym schematem formularza i jego wersji, wydrukowana kartka pod jedną dłonią, pojedyncza niebieska lampka stanu na ramie ekranu

Zespół handlu dodaje do zamówienia procent rabatu. To mała zmiana, uzgodniona na spotkaniu, i moduł, który tworzy zamówienia, zaczyna ją wysyłać tego samego popołudnia. Moduł finansów, który czyta zamówienia od dwóch lat, nie zna tego pola i przestaje przyjmować komunikat. Nikt nie zamierzał zmieniać umowy. Umowa była, tylko nigdy nie została zapisana nigdzie poza dwoma fragmentami kodu, które kiedyś się zgadzały.

W systemie zbudowanym z modułów wymieniających zdarzenia każde zdarzenie jest porozumieniem. Apache Avro to jeden z formatów, które zapisują to porozumienie w samych danych, a powód, dla którego znajduje się w projekcie warstwy Data Hurukana, która jest w budowie, dotyczy mniej bajtów, a bardziej tego, co się dzieje, gdy porozumienie musi się zmienić.

Schemat podróżuje z danymi

Rekord Avro to zwarty binarny wiersz. Sam w sobie nie da się go przeczytać: nazw pól, typów i kolejności nie ma w bajtach. Są w schemacie, zapisanym w JSON, a specyfikacja określa niewielki zestaw typów do jego zapisania: null, boolean, int, long, float, double, bytes, string oraz złożone record, enum, array, map, union i fixed. Pole może nieść wartość domyślną i to ona później sprawia, że zmianę da się przeżyć. Aktualne wydanie to 1.12.2 (blog projektu, sprawdzono 21.10.2026).

Schemat dociera do czytelnika na jeden z dwóch sposobów. W pliku format Object Container File umieszcza schemat w nagłówku, a po nim bloki rekordów rozdzielone znacznikiem synchronizacji, więc plik znaleziony po latach nadal sam się tłumaczy. Na szynie komunikatów, gdzie wysyłanie schematu z każdym zdarzeniem byłoby marnotrawstwem, kodowanie pojedynczego obiektu ze specyfikacji stawia przed każdym rekordem dwubajtowy znacznik i ośmiobajtowy odcisk schematu; rejestr przechowuje schemat pod tym odciskiem. Szeroko używany rejestr Confluent robi to samo własną ramką: bajt magiczny i czterobajtowy identyfikator schematu przed bajtami Avro (dokumentacja Confluent).

Tak czy inaczej, czytelnik nigdy nie zgaduje. Ma schemat pisarza i swój własny, a reszta to reguły.

Rozwiązywanie: jak czytelnik spotyka pisarza, którego nigdy nie widział

Specyfikacja określa, co się dzieje, gdy schemat pisarza i schemat czytelnika się różnią. Pola są dopasowywane po nazwie. Pole, które pisarz wysłał, a czytelnik go nie ma, jest ignorowane. Pole, którego czytelnik oczekuje, a pisarz nie wysłał, jest wypełniane wartością domyślną czytelnika, a jeśli jej nie ma, odczyt kończy się błędem z jasnym powodem. Niektóre typy mogą być po drodze awansowane: int można czytać jako long, long jako float albo double, float jako double, a string i bytes można czytać wzajemnie. Unia jest dopasowywana do pierwszej zgodnej gałęzi po stronie czytelnika.

Spisane, te reguły są całą dyscypliną pola rabatu. Dodaj je z wartością domyślną, a moduł finansów czyta dalej, ignorując pole, dopóki nie nauczy się go używać. Dodaj je bez wartości domyślnej i w tej samej zmianie usuń stare pole, a najstarszy czytelnik w firmie się zatrzyma. Reguły nie są radą; decydują, którą wersję poranka dostaniesz.

Zmiana schematu jako propozycja

W Hurukanie projekt zakłada, że schemat zdarzenia jest obiektem ontologii jak każdy inny: ma właściciela, wersje i miejsce w zapisie. To zamienia pole rabatu z popołudniowej zmiany w kodzie w krótką, zapisywaną ścieżkę.

Agent proponuje. Moduł handlu potrzebuje nowego pola; agent przygotowuje zmianę schematu z wartością domyślną, typem i powodem oraz wskazuje moduły, które czytają to zdarzenie.

Rejestr sprawdza. Proponowana wersja jest testowana wobec schematów czytelników według reguł rozwiązywania opisanych wyżej. Zmiana, która zatrzymałaby istniejącego czytelnika, jest odrzucana, zanim ktokolwiek ją zobaczy, z podaniem nazwy czytelnika.

Właściciel zatwierdza. Zgodna zmiana nadal jest zmianą porozumienia między modułami. Właściciel zdarzenia, człowiek, zatwierdza ją i dopiero wtedy producenci zaczynają pisać nową wersję.

Zapis ją przechowuje. Zatwierdzenie, wersja i czas trafiają do zapisu, więc rok później pytanie „kiedy na zamówieniach pojawiły się rabaty i kto na to pozwolił” ma odpowiedź. To ta sama ścieżka, którą przechodzi każda zmiana w systemie: agent proponuje, człowiek decyduje, system zapisuje. Szerszą myśl opisuje tekst stan bieżący i zapis.

Do czego Avro nie służy

Avro dobrze niesie zdarzenia i dobrze czyta całe rekordy. Jest złym układem dla pytania, które superinteligencja zadaje najczęściej, o kilka pól w milionie wierszy, bo każde pole stoi na drodze każdemu innemu. Dlatego w projekcie zdarzenia w Avro są paczkowane do kolumn, gdy zostaną przyjęte. Który kształt należy gdzie, opisuje tekst Parquet i Avro: zdarzenie i zapis.

Avro pojawia się też w miejscu, w które mało kto zagląda: format tabeli Apache Iceberg zapisuje swoje manifesty, listy plików danych składających się na tabelę, jako pliki Avro (specyfikacja Iceberg). Format wierszowy, który niesie zdarzenia między modułami, niesie też księgowość zapisu.

Co zostaje przy ludziach

Agent może przygotować schemat, uruchomić kontrolę zgodności i wskazać czytelników. Nie może zdecydować, że pole, na którym polegał moduł finansów, może zniknąć, że domyślne zero jest prawdziwym stwierdzeniem o starych zamówieniach ani że czytelnikowi wolno się zatrzymać. To decyzje o znaczeniu biznesu i w Hurukanie podejmuje je właściciel zdarzenia, a decyzja zostaje zapisana.

Test, który możesz zrobić dziś

Wybierz jeden komunikat, który przechodzi między dwoma Twoimi systemami. Znajdź, gdzie zdefiniowane są jego pola. Jeśli odpowiedź brzmi „w kodzie wysyłającym” i „w kodzie odbierającym”, masz dwie definicje i żadnej umowy. Potem zapytaj, kto z imienia i nazwiska zatwierdziłby dodanie do niego pola. Jeśli nie ma nazwiska, następne pole doda ten, kto pierwszy go potrzebuje, a odkryje ten, komu to coś zepsuje. Strona warstwy Data opisuje, gdzie ta umowa ma mieszkać w Hurukanie; przegląd pokazuje moduły wokół niej.