Transkrypcja
Powrót z urlopu i temat odcinka
Cześć Michał.
Cześć Wojtek, świeżo po urlopie, wypoczęty.
Jeszcze na pewno rozmyślałeś o czymś na urlopie.
No oczywiście, jak zwykle rozmyślałem o eventach. A tak, coś czułem. O czym to można rozmyślać na takim urlopie, zwłaszcza po ostatnim odcinku, gdzie okazało się, że już nie będziemy o eventach ostatnio rozmawiać. No to tak pomyślałem, a to sobie pomyśleliśmy.
Architektura sterowana zdarzeniami i komunikatami
No i tak w sumie o tych eventach można by sobie dalej porozmawiać i może nie tylko o eventach, ale w kontekście naszego podtytułu odcinka, czyli: “OK, zadzwonimy do Pana”. Może nie tylko moglibyśmy się skupić na Event Driven Architecture, ale też i na szerszym pojęciu Message Driven Architecture jako takim. Czyli wszelkiej maści.
Antologia tak potocznie zwana, ale nie tylko do sygnalizowania tego, co się zmieniło w domenie, co się zadziało, tylko może do wymuszania tego, inicjowania tych zmian też.
OK, brzmi fajnie.
Więc cóż, taka. Czym jest taka architektura według Ciebie? Czym? Czym się? Czym się charakteryzuje Message Driven, Event Driven?
Czym różni się event od komendy?
I znowu wyjdzie, że nie czytałem książki ostatnio.
Tu nie chodzi o książkę. Czytałem książki, bo myślałem o eventach co dnia, to nie mogę w tym czasie czytać książki. Ale według mnie, i może gdzieś tam to jest inspirowane jakimiś tam książkami, które jednak przeczytałem gdzieś tam kiedyś, to jest taka architektura, która jest, jak nazwa wskazuje zresztą, sterowana. Bądź to eventami, czyli zdarzeniami.
Tutaj przykładem jest. Przykładem np. może być jakiś tam system odcinkowy, popularnie zwany Windą, gdzie wszystko jest eventem, praktycznie każda porcja informacji przesyłana z jednego wątku do drugiego, czy z jakiegoś tam jednego okna. W Windowsie wszystko jest oknem. Tam jest traktowane jako zdarzenie, gdzie niekoniecznie to musi być w innych sytuacjach traktowane podobnie. Bo właśnie chyba na tą okoliczność powstało szersze pojęcie architektury. I nawet ten, i ten to złożenie wzorców, które mieliśmy w poprzednim odcinku.
Eventy, komendy i inne typy komunikatów
Czyli co, uraziłem namingiem? To już pokazuje, że tam nie tylko eventy są. Tam mogą być jeszcze komendy. A jeszcze oprócz tego inne typy komunikatu szeroko rozumianego. To tak jeszcze dla przypomnienia. Może event a komenda? Jakaś taka podstawowa różnica, żebyśmy po raz kolejny wiedzieli, co jest czym.
Na pewno podstawową cechą eventu jest to, że to jest zdarzenie dokonane, które już się zdarzyło w przeszłości i już to jest stało się faktem. Dokonało się. Natomiast komenda to by było coś, co po prostu sygnalizuje konieczność wykonania jakiejś akcji. To jest takie jakby. I trigger. Taki wyzwalacz. Coś w ten deseń. Po prostu komunikat, który po to, żeby ktoś coś dla nas zrobił.
Zastosowania Message Driven Architecture
No i podobnie możemy sobie potraktować inne typy też komunikatów. Bo np. w takim systemie sterowanym komunikatami mogą być sobie komunikaty typu query, jakieś query response, czy jakieś tam inne, nawet jakieś błędy. Też możemy chcieć zgłaszać za pomocą komunikatów. Czyli jak nazwa wskazuje Message Driven.
No tak, dosyć driven. I co nam? Co nam to daje? Właściwie ten message to jest tylko kolejna zabawka, którą sobie wymyśliliśmy, żeby w inny sposób robić te same rzeczy, które robimy od zarania dziejów. Czy rzeczywiście mamy jakieś benefity tego Message Driven?
Ewolucja systemów i integracja
No to sprawdźmy może, bo na razie może wróćmy do świata, gdzie nie byłoby jeszcze tych komunikatów, gdzie byłby w ogóle Message Driven i wszystko byłoby spaghetti-driven, czyli różnica albo szkodliwa po prostu. Czyli pewnie wróćmy do świata sprzed 20-30 lat, kiedy aplikacje generalnie mało się ze sobą integrować miały, gdzie biznesowe wymagania były zawarte prawdopodobnie w jednym module, w jednej aplikacji.
Kiedy wszystko było prostsze?
Kiedy pewnie nie mieliśmy aplikacji mobilnych. Kiedy można było wolno przetwarzać? Tak, kiedy menadżer nie miał problemu z czekaniem na jego ulubione raporty 24 godziny, bo wszystko oczywiście musi się wolno przeliczyć i select zrobić w nocy, żeby to wszystko zrobić. Więc tego typu use case’y te dwadzieścia lat temu wyglądało to troszkę inaczej.
Złożoność systemów i wpływ na architekturę
Faktycznie, jakby powstanie architektur sterowanych zdarzeniami, masażami, właśnie wynika z tego, że nasze systemy, nasze ekosystemy stały się coraz bardziej skomplikowane. Muszą reagować na dane, na sygnały z coraz większej ilości źródeł. Czy to z jakiś rzeczy, z aplikacji mobilnych, z jakiś czujników, z jakiś sensorów, z wielu innych systemów, z którymi się integrujemy, co kiedyś nie było tak powszechne.
Kiedyś ta integracja była bardziej dokonywana przez czynnik ludzki. Czyli ktoś sobie generował raport. Może gdzieś przepisywał te dane do systemu ręcznie, albo w ogóle nie było takiej integracji? Może część rzeczy po prostu istniała na papierze i nigdy nie była w wersji cyfrowej, więc wtedy jakby nie było takiej potrzeby. To wszystko było prostsze. Nie było tych tak wielu, jak to fajnie nazwałeś, sygnałów z zewnątrz, które po prostu musiały wyzwalać coś.
Wyzwania współczesnych systemów
A teraz? Teraz z racji tego, że faktycznie złożoność tych systemów jest coraz większa i też one coraz bardziej ochoczo się komunikują ze sobą, tych sygnałów się narobiło. I zresztą nawet samo podejście domenowo zorientowane też nas zachęca do tego, żeby.
Żeby ich jednak było więcej. Samo podejście zorientowane domenowo zachęca nas do tego, żeby ich było coraz więcej, bo po prostu poszczególne fragmenty domeny są od siebie rozdzielone. Jeżeli mamy gdzieś tam je w osobnych jeszcze jednostkach logicznych, to te jednostki chcą się ze sobą skomunikować. I żeby tak nie musieć się wołać.
Zasada Hollywoodzka i szyny danych
Tak na zasadzie znam ciebie to to od razu do Ciebie wbiję na jakieś API i Ci tam wpiszę to, co trzeba, albo zapytam, co tam dla mnie masz. Może lepiej tutaj zastosować tą maksymę tzw. hollywoodzką: „Zostaw informacje, namiary na siebie, a my zadzwonimy do Ciebie”. Zgodnie z podtytułem odcinka.
Czyli pewnie to to też jakoś wpłynęło na to wszystko. Jak się ludzie zorientowali, że można sobie takie komunikaty przesyłać. Potworzyły się jakieś szyny danych, to zapewne już później popłynęło.
Zalety integracji systemów
No tak. Bo to z kolei sprawiło, że integracje między systemami stały się osiągalne. Czy to technicznie, biznesowo były wymagane. Technicznie stały się w końcu wykonalne w jakiś prosty sposób, więc. Wiadomo, wtedy. Wtedy coraz więcej integracji linii jest w zasięgu. Możemy, możemy systemy ze sobą łączyć, możemy znaleźć nowe biznesowe use case’y na połączenie tych systemów, możemy robić analizę danych, warning, tego typu rzeczy.
Więc to wszystko też sprzyja i prowokuje niejako fakt, że musimy to nasze dane, musimy nasze zmiany stanu pewnych obiektów jednak propagować w troszkę inny sposób niż zwyczajnie update do bazy danych. Musimy jednak dać komuś znać, że u nas coś się zmieniło. Zmieniła się cena tego przedmiotu. Użytkownik kliknął gdzieś tam razy. Może ktoś na tym przeprowadzi jakieś obliczenia? Kto zrobi analizę? Jakieś uczenie maszynowe? Albo zwyczajnie inny mikroserwis będzie chciał podjąć jakąś decyzję w swoim, w swoim zakresie. Więc tak.
Powiadomienia a dane w eventach
Przy czym jeszcze nie jest wcale powiedziane, że ktokolwiek musi z tego skorzystać, ale my i tak informujemy świat, że coś tam się zdarzyło. Nie tak. No i właśnie tutaj mamy do czynienia najczęściej w tym kontekście pewnie ze zdarzeniami, bo jak się zdarzyło, o tym informujemy. I tutaj mamy te eventy.
Ale wracając do tego naszego przykładu sprzed 30 lat. Gdzie tam można było i proceduralnie to wszystko połączyć, zawołać z jednego modułu coś tam. I całe te integracje sprowadzały się do tego, żeby po prostu sekwencja komponentu gdzieś tam się odegrała i wywołując jeden, wywołując kolejny. To gdy zaczęło tego przyrastać przez te nasze 20-30 lat, porobiły się z tego solidne legacy systemy. Już nie jest tak prosto teraz kontynuować w tym samym duchu.
Message Driven Architecture a Legacy Systems
Więc może się okazać, że takie podejście zorientowane na komunikaty też nam się przyda od strony legacy do jakiegoś rozwikłania tego pliku, który nam się tam otworzył.
No tak, tak to na pewno. Natomiast jednym z technik do rzeczywiście rozwiązywania zależności. Do łączenia systemów przez troszkę luźniejsze powiązania niż zaglądanie bezpośrednio do schematu, czy używanie jakiś wewnętrznych serwisów, które do tego nie służą.
Rodzaje eventów: notyfikacje i eventy transfer
OK, to jeszcze może wróćmy, wróćmy na chwilkę do naszych eventów i takie takie podstawowe rzeczy. Event eventowi nierówny. I mamy tutaj oczywiście różne rodzaje tych eventów. Możemy sobie tam różne rzeczy do środka naładować. No i wiadomo, różne klasy preferują różne rodzaje eventów. Czy widzisz tutaj jakiś jakiś podział, który stosujesz właśnie w kontekście konstrukcji, w kontekście użycia danego rodzaju do zastosowania?
No cóż, takie eventy mogą być same w sobie notyfikacje, że coś się tam zdarzyło, jakiegoś typu określonego, i oprócz tego też mogą zawierać jakieś dane, które na przykład opisują dokładnie to, co się zdarzyło. Tak więc. W najprostszym ujęciu notyfikacje nie muszą mieć payloadu, wystarczy, że są i że je odnotowaliśmy, że przeszły. Wiadomo, że jakieś tam metadane są potrzebne, pokroju timestampu, samo tego typu. Żebyśmy mieli po czym rozpoznać. Ale to, że że się coś zdarzyło, to już jest wystarczające.
Eventy z danymi i spójność
Drugi ten typ jest troszkę bogatszy. Bo oprócz tego, że to się zdarzyło, jeszcze to niesie ze sobą jakąś określoną zmianę stanu, np. w domenie. No i wtedy dobrze jest tam zawrzeć jakiś payload. Nie przeczy oczywiście ani jedno, ani drugie. Temu, żeby wszystkie te eventy huczały po jakiejś jednej szynie danych. Na przykład jeżeli to konieczność. Tak, to techniczny środek dostarczania tych eventów czy nawet wyprodukowania jest niezależny.
I tylko jeszcze może dodam. Faktycznie ten podział jest taki najprostszy. Możemy wyróżnić jakieś eventy bardziej domenowe, bardziej integracyjne i różnej technicznej kategorii jest sporo. Im niżej zejdziemy, tym taki podział na notyfikacje i na eventy. Tak zwany event transfer, czyli coś co event, który jednak trochę tego stanu ze sobą zawiera. To jest taki podstawowe poziomu.
Wyzwania kolejności eventów
Trzeba też charakterystyki tych eventów w przypadku zwykłych notyfikacji. Systemy, które takie notyfikacje dostają, czyli subskrybują się na powiadomienia o jakiejś zmianie, muszą raczej pobrać sobie pewnie jakieś jakieś jakieś dane, żeby coś więcej z tej notyfikacji wyciągnąć. No bo jeśli dostaliśmy powiadomienie, że zmieniło się coś w jakimś systemie, to pewnie chcielibyśmy wiedzieć, co się zmieniło, jaki jest obecny stan. Więc sama notyfikacja niesie prawdopodobnie ze sobą jeszcze konieczność pytania jakiegoś systemu o aktualny stan. I to mamy.
Tu mamy świetny przykład na naszą część poświęconą tej zasadzie. Nie wiem, czy w tym, czy w następnym odcinku. Zależnie jak się wyrobimy z czasem, bo dokładnie tak, jak opisujesz, realizowaliśmy to w projekcie całkiem niedawno. Dokładnie. A z kolei ten bogatszy, bogatszy event, który za sobą niesie jakiś stan, na który też mamy jakieś słowa, które pewnie opowiemy w dalszej części, bądź w kolejnym odcinku, to jest event, który dla samego subskrybenta niekoniecznie może pociągać za sobą konieczność odpytania o dany stan, ponieważ dostajemy już wycinek tego stanu czy to DTO, czy jakąś konkretną zmianę tego stanu, więc możemy już wnioskować coś na podstawie danych, które są w payloadzie tego eventu.
Ważność kolejności i odporność na błędy
Natomiast tutaj już wchodzi w grę. Zapewnienie kolejności takich eventów. Bo wiadomo, jeśli zmiany stanu przychodzą nam bez kolejności, to musimy sobie jednak tę kolejność zapewnić, żeby. Czy to nasza logika, czy nasz, czy nasz lokalny. Z tymi danymi jednak miał zachowaną spójność. W sytuacji, kiedy eventy są troszkę opóźnione, to jest to jest temat, który troszkę w sekcji wyzwań sobie poruszymy. Bo jednak kolejność odbierania eventów jest dość ważnym elementem w całym całym tutaj podejściu, żeby nie powiedzieć kluczowym.
Oczywiście to nie od wszystkiego zależy, od zastosowania, od zastosowania. Jeśli mamy oczywiście event na zasadzie user kliknął w jakiś element na stronie i to jest tylko kwestia metryki. Może niekoniecznie aż nam zależy na kolejności takiego zdarzenia. Natomiast jeśli chodzi o rzeczy na zasadzie użytkownik dodał coś do koszyka, coś wyrzucił, czy może jeszcze jakieś bardziej finansowe rzeczy, to tutaj kolejność może mieć kluczowe znaczenie. Także tak. I to są. To są takie dwa, dwa, dwa podstawowe rodzaje tych naszych, tych naszych eventów i dobra.
Przesyłanie eventów i wybór medium
Co dalej możemy z tymi eventami zrobić? Przesyłać, przesyłać, przesyłać, odbierać, nadawać, słuchać. Ignorować możemy. Ignorować, kompensować, kompensować. To kolejne oczywiste bezokoliczniki, ów dobrych do tego, co można by zrobić z eventem albo ogólnie z komunikatem, ale tak, żeby je można było nadawać, odbierać i w ogóle to fajnie by było mieć. Po czym je wysłać gdzieś.
No i po czym posłałeś te eventy kiedyś? Potrzebujemy pewnie jakiejś mniejszej czy większej szyny danych.
No nareszcie, nareszcie! Jest tutaj też oczywiście od use case’a i możemy sobie możemy dobrać odpowiednie rozwiązanie, bo jeśli mamy do dyspozycji, to właściwe, jeśli mamy. Pracujemy z jakimś małym systemem i chcemy sobie tylko w naszym monolicie np. rozdzielić jakieś dwie logiczne, powiedzmy, funkcjonalności i akurat wybraliśmy sobie eventy. No to wtedy pewnie zwykły event loop fajnie poradzi.
Event loop kontra brokery komunikatów
I może niekoniecznie potrzebujemy pełnego brokera, w stylu Kafka czy czegoś podobnego. Czy królika, czy królika zwanego RabbitMQ? No bo to jest tylko na nasze wewnętrzne, że tak powiem, potrzeby. To oczywiście niesie za sobą pewne ograniczenia i trzeba, trzeba to jasno powiedzieć. Czy to. Chodzi o rezystancję tego eventu, czy kolejność dostarczania. Transakcyjne to też powiemy sobie w dalszej części, jakie tu są problemy, jak je rozwiązać.
Ale jeśli chcemy sobie tylko spróbować takiego eventowego podejścia, to jest na pewno dobre. Dobry punkt startowy i nie wymaga. Nie wymaga dokładania kolejnego klocka do naszej infrastruktury w postaci w postaci Kafki czy innego brokera. Tak, bo tutaj chyba można by skorzystać z takiej ilustracji, żeby rozkminić. Kiedy właściwie jakiego medium byśmy potrzebowali do przesłania tych komunikatów?
Awarie i odzyskiwanie komunikatów
Nie. W takim systemie okienkowym właśnie pokroju Windowsa, gdzie wszystko jest oknem, a wszystko, co się przesyła, jest jakimś tam komunikatem. Wyłączając tam oczywiście. Wywołania funkcji systemowych, takich po prostu na piechotę. I wystarczy jakaś tam kolejka, która niekoniecznie musi być per system. Bo. Bo tutaj rzeczy dzieją się w czasie rzeczywistym. I jeżeli ten system zgaśnie. To gaz. Po prostu nie musimy nic więcej o tych eventach wiedzieć. Jak są w stanie znowu to, to znowu hulają nowe eventy i wszystko ładnie działa.
Ale już w takim systemie opartym o event sourcing, jak nam takie medium zgaśnie, to już jest katastrofa. Można by powiedzieć, bo wtedy żadne eventy nie są w stanie się zapisać.
No tak, jak to wszystko dobrze, mogłaby nam zgasnąć baza.
Wybór narzędzia i wymagania
Dokładnie, to jest tego typu awaria. Tak, czyli tutaj musimy sobie do naszego zastosowania dopasować po prostu rozwiązanie, jakie będzie adekwatne, żeby ten cel uzyskać. Przy czym to chyba też nie stoi na przeszkodzie, żeby było więcej niż jedno, jeżeli potrzebujemy. Bo tak się czasem ludzie upierają, że szyna danych, szyna danych, a może niekoniecznie, może to kilka kolejek, ileś tam topiców. Albo może cała ich zgraja nawet.
Tak jak właśnie to mieliśmy w tym całe stado, które tutaj zostało zapowiedziane i tam. Tam po prostu była cała grupa topiców, na których trzeba było nasłuchiwać i te eventy, które na tych co się pojawiały, wcale nie musiały być posypane tak za bardzo. Mogły, ale nie musiały. Ważne, żeby tam była zrobiona robota, którą one kierowały.
Stabilność brokera i odzyskiwanie po awarii
No ale jak już mamy taką szynę danych np. Chcielibyśmy sobie faktycznie Message Driven zastosować i tutaj korci nas cykl event sourcing. To fajnie, jakby na danych potrafiła. Obsłużyć takie przypadki jak na przykład. No i to jest najprostsza awaria, że po prostu komunikaty zostały na nią posłane, ale infrastruktura umarła, nie zostały odebrane. Poszczególne brokery potrafią sobie radzić z tymi sytuacjami. Więc jak? Jak? Jak ten? Jak taki broker wstaje i widzi, że ma taki stan zastany i to wtedy umożliwia odbiór tych komunikatów np. które jeszcze nie trafiły.
Do odbiorców. Czyli tutaj też dobrze jest. Dobrze jest zawsze zważyć za i przeciw, jakie, jakie mamy, jakie mamy wymagania i jakie mamy możliwości tych naszych brokerów czy innych prostszych medium do przesyłania tego.
Eventy w Legacy Systemach
Dokładnie. Więc klasyczne rozpoznanie naszego przypadku i dobranie odpowiedniego narzędzia to zawsze podstawa, niezależnie co robimy i jakiekolwiek inne podejście. Wspomniałeś jeszcze na początku o Legacy i że tutaj. Cała ta eventowa orgia dobrze współgra z Legacy.
No bo przecież dla kasy nie da się tak łatwo zmienić. Jak to? Jak to ma współgrać? No przecież to jest Legacy, więc to już jest Legacy. Pozamiatane. Chcemy np. zrobić jakiś kawałek nowej funkcjonalności w naszym Legacy. Mamy w systemie. Dziejący się proces. No i wiadomo, nie wejdziemy teraz do tego serwisu, nie zrobimy tam nowej, nowej rzeczy. Więc jak bezbolesny sposób w tym Legacy jednak dopiąć jakiś kawałek, żeby coś tam się zadziało?
Rozwikłanie Legacy Systemu
Bezbolesny. To może najmniej bolesny. Najmniej bolesny. Tak. Czyli tak najpierw ładujemy znieczulenie, a później działamy.
Okej, czyli można by było sobie wyobrazić taką sytuację, że mamy takie właśnie spaghetti gdzieś tam, takie potężne, potężne, wystarczająco dobrze splątane, żeby nas bolało. No i wiadomo, że jak takie coś jest, to to ludzie się boją, boją się dotknąć, zwłaszcza jak brakuje testów. Więc gdyby tak pokusić się np. Najpierw wkomponowanie w to całe nasze ustrojstwo. Czegoś takiego, co by tą szynę danych chciało poudawać.
Podglądanie procesu za pomocą eventów
A istnieją implementacje mniejsze lub większe. Praktycznie w każdym języku znanym człowiekowi. Ostatnio, jak szukałem, w .NET w C++ znalazłem kilka takich, które dałyby się użyć w takim kontekście. I można by było spróbować wpiąć takie ustrojstwo właśnie w ten nasz kawałek, gdzie gdzie mamy ten duży plik i na początek niewiele zrobić, tylko po prostu rzucić jakiś event ten czy ów z jakiegoś tam bolącego miejsca i zacząć je zbierać. I mogłoby się okazać, że jak już pozbieramy te eventy. Które tam się zaczynają pojawiać, to to nagle się można podpiąć do tego samego procesu biznesowego z innych miejsc.
Albo można wręcz zacząć myśleć o przemodelowaniu tego procesu biznesowego, żeby on właśnie zaczął się opierać na tych naszych komunikatach. Byłyby to wtedy eventy. Prawdopodobnie, ale niewykluczone, że byłyby też tam i komendy. Czyli de facto moglibyśmy taki proces legacy nawet zacząć lekko forsować. I tak w małych krokach, pewnie tak. Rzeczywiście, to będę pewnie w dalszej części, jak już mielibyśmy rzeczywiste intencje na tak.
Analiza kodu a Event Sourcing
Na początek chcielibyśmy podejrzeć, co się właściwie tam, gdzie i kiedy nie było. Bo taka analiza kodu po prostu na piechotę jest czasem. Nie tyle niewystarczająca, co po prostu nie daje dobrego oglądu sytuacji, bo nie jesteśmy w stanie ogarnąć tego wszystkiego nawet siedząc w debuggerze, bo jak siedzimy w debuggerze to tracimy zależności czasowe bardzo łatwo i pewne rzeczy mogą się po prostu nie zadziać.
Natomiast kiedy pozwolilibyśmy, żeby ten proces płynął i byśmy tylko podsłuchiwali z jego kluczowych miejsc. To wtedy moglibyśmy poskładać sobie ten ciąg naszych zdarzeń. Najpewniej byłyby to eventy. W jakąś sensowną całość i jakoś by to zmotywowało cały ten proces. I być może to by było zaproszenie do tego, żeby ten proces spróbować przepisać właśnie w takiej formie już totalnie eventowej. Czyli moglibyśmy w ogóle.
Change Data Capture (CDC) jako alternatywa
Wyjść z tego, z tego bagna, z tego legacy. Pytanie, czy zaproszenie będzie przyjęte przez biznes, ale. A tak, to jest dobry punkt wyjścia. Warto też jeszcze dodać, że tego typu. I antologia, że tak powiem, można przeprowadzić dość bezboleśnie poprzez tzw. CDC, czyli Change Data Capture. Generalnie polega to na tym, że podpinamy sobie jedną z technologii. Narzędzie do tego typu rzeczy jest np. Debezium.
Czyli podpinamy takie Debezium pod naszą bazę danych i ono bezpośrednio, czytając transaction log, czy po prostu log bazy danych, bo koniec końców baza danych gdzieś tam operuje na pliku i na logu. Takie Debezium potrafi nam wykryć zmiany w poszczególnych tabelach i automatycznie rzucić nam eventami, czy to na Kawkę, czy czy gdzieś jeszcze. Więc możemy i. Baza danych sama z siebie nie jest w ogóle zaangażowana, ani nawet świadoma, że ktoś tam jej z boku tego transaction loga czyta, że ktoś podsłuchuje, że ktoś podsłuchuje.
Bezpieczeństwo i analityka w CDC
Oczywiście musimy to uwzględnić. Pewne pewne rzeczy, wymogi bezpieczeństwa i tego typu sprawy, to jest wymóg oczywisty, ale to mamy wszelkie zasady etyki, zasady etyki i dobrego, dobrych, dobrych praktyk. Ale mamy przynajmniej gwarancję, że tego typu zmiana. Nie wprowadzi żadnej. Żadnego błędu, czy żadnego, żadnego problemu w naszym systemie, bo system nie musimy go ani ponownie wdrażać, restartować. Nic właściwie nie musimy z nim robić, żeby w łatwy sposób wykryć pewne zmiany i wyrzucić pewne zmiany.
Gdzieś tam doszło do eventu, który możemy sobie później gdzieś tam ponownie analizować. Dość powszechne zastosowanie jeśli chodzi o jakieś data mining czy tego typu rzeczy, żeby nie obciążać bezpośrednio tej bazy jakimiś korektami. Żeby wygenerować pewien model na potrzeby takiej zwykłej biznesowej analityki, gdzie taki kluska jest. Mieliśmy upiornego klienta, gdzie jednak jednak te rzeczy na potrzeby analizy. W pierwszym rozwiązaniu były po prostu pobierane bezpośrednio z efektami z bazy.
Unikanie obciążenia bazy danych
Obciążając jednak tą bazę i użytkownicy mieli okazję to odczuć. Więc żeby uniknąć tego typu efektów ubocznych, możemy narzędzia Debezium podpiąć pod bazę danych i w ten sposób nasłuchiwać na już zmianach, jednocześnie w łatwy sposób je publikując, co jest właśnie tym tym wstępem do kolejnych zmian, o których wspomniałeś.
I tutaj jeszcze mamy taką anegdotę z projektu, w którym aktualnie jestem. Można by ją tutaj dodać odnośnie bazy danych i jej obciążania, bo np. mamy tutaj taką główną dyrektywę sformułowaną w ten sposób, że nawet selectów nie wolno robić. Wszystkie zapytania mają się odbywać poprzez procedury i te procedury. Przechodzą solidne code review, tak żeby nic tam się nie skradło, więc tam nie można sobie po prostu podpiąć się do tej bazy, która już teraz jest przeciążona, jest dużo większa niż powinna być. I tam sobie ochoczo odpytywać o dane. W takiej sytuacji podpięcie Kafki i wyciągnięcie eventów byłoby praktycznie niemożliwe, bo technicznie musielibyśmy tutaj zastosować narzędzia CDC.
CDC a reakcje użytkowników
Jednak w miarę. Teraz, żeby to się działo w tle. Żeby to się działo w tle, żeby to po prostu nie. Nie zapaliło też pewnych czerwonych lampek niektórym, niektórym użytkownikom pracującym nad systemem, bo wiadomo, tego typu rzeczy i tego typu nowości są też czasami niechętnie przyjmowane na zasadzie: „nikt niech tu nie będzie grzebał mi w bazie”.
Na co? No jasne, to się wydaje ciekawą alternatywą, kiedy chcielibyśmy złapać jak najwięcej pewnie tych faktów, które tam się dzieją w domenie. Tak jest, wręcz w czasie rzeczywistym nawet przeglądać, bo później można sobie sprawdzać te sekwencje komunikatów, jakie tam trafiły. Na tą naszą szynę wyciągnięte bezpośrednio ze zmian w bazie i to nam może zbudować jakiś tam ogląd tego, jak nasza domena pracuje.
Event Sourcing i Back Pressure
Na mniejszą skalę to właśnie tak, jak kiedyś zrobiliśmy w projekcie, gdzie po prostu zajęliśmy się eventami i rzucaliśmy z tych poszczególnych punktów procesu to, co nas interesowało. Później zaczęliśmy już. Wprowadzać pełnoprawne agregaty, które też obsługiwały komendy biznesowe. Tak więc tam już nam się udało przejść na zakres. I taki taki wspierany. Message Driven Architecture. I okazało się, że bardzo ładnie to rozwikłało. Ten cały nasz back pressure.
No właśnie, bo back pressure i eventy są często często używane w przypadku back pressure’u różnych z różnych systemów. Wiem, że. Zwłaszcza w przypadku mikroserwisów często mamy ten temporary plik, czyli mamy sobie kilka mikroserwisów robiących jakiś tam flow biznesowy. Mamy piękne API, jeden woła drugi, drugi woła trzeci itd. W łóżku nagle któryś system wywala.
Stabilność i skalowalność mikroserwisów
Jak to w mikroserwisach wiadomo, to zawsze jest. Jeśli coś się może zdarzyć, to wiadomo, że prędzej czy później się zdarzy i cały nasz proces oczywiście wtedy też faluje. Więc tutaj eventy i asynchroniczna komunikacja też na pewno jest niezbędnym czynnikiem i elementem zapewnienia stabilności jakiegoś procesu biznesowego, zwłaszcza jeśli jest rozłożony na więcej. Najwięcej mikroserwisów, najwięcej usług.
Bo trzeba pamiętać, że. Mając mając kilka tych mikroserwisów i jeśli nasz proces rozciąga się na kilka mikroserwisów, to nasze SLA nie jest już dostępnością systemu. Nasz wskaźnik dostępności systemu nie będzie tylko obliczany na podstawie dostępności jednego systemu, ale musimy sobie pomnożyć SLA tych wszystkich systemów. Czyli mamy 95% pierwszego mikroserwisu, 90% drugiego i tak sobie mnożymy, mnożymy i ono za każdym.
Komunikacja asynchroniczna a spójność
Za każdym skokiem w naszym procesie, za każdym serwisem. Ono powolutku, powolutku spada, więc i może oczywiście w końcu spaść do niedopuszczalnych wartości, mimo że każdy serwis z osobna jest oczywiście w miarę dobrze dostępny. No bo przecież działa, proszę, ale ten obok nie działa, a jak działa, to nie działa ten trzeci itd. Tutaj te eventy.
Synchroniczna komunikacja, która, która za tym za tym idzie, sprawi, że ten proces jednak będzie bardziej, bardziej stabilny i bardziej odporny na jednostkowe awarie poszczególnych usług. To na pewno tak. Oraz jeszcze to pojęcie, które też się pojawiło w ostatnim odcinku, czyli eventual consistency. Jeżeli zmienimy nasze podejście biznesowe do tego, że takie zmodyfikujemy, żeby akceptowało tą ostateczną spójność danych, to wtedy nawet taka degradacja wesela nam trochę już mniej przeszkadza, bo i tak wiemy, że kiedy już te poszczególne usterki ustąpią, to da się to wszystko zrobić.
Interfejs użytkownika w asynchronicznych systemach
Więc w tym danym momencie, kiedy nam przykład kaskadowo. Dwa lub więcej serwisy się położyły, nie chcą nam coś tam odpowiedzieć. Nawet jeden wystarczy, żeby nam zaburzyć cały proces, to i tak wiemy, że podnosimy całą tą operację. I z dużym prawdopodobieństwem później to zadziała. Jak już się wszystko podniesie.
Tak, tylko tak. Tylko ważne jest, przepraszam. Ważne jest, żeby pamiętać o tym, że. No że tak to się może zdarzyć i pewnie się zdarzy. Tak, tak, no to tutaj fail-over jest nieodłącznym elementem takiej synchronicznej natury procesu, więc musimy być na to gotowi zarówno i w procesie, i w poszczególnych naszych serwisach. Otóż uwierz, powinieneś troszkę inaczej zaprojektować sam interfejs użytkownika, bo to już nie jest tak, że za.
Projektowanie interfejsu i modularny monolit
Pojedynczym requestem mamy jednocześnie odpowiedź, że proces zakończył się tak lub nie. Wszystko jest w porządku, bądź są jakieś błędy, tylko prawdopodobnie musimy. Jednak nawet interfejs troszkę inaczej zaprojektować, biorąc pod uwagę troszkę inny tryb, a mianowicie asynchroniczny naszego procesu pod spodem i tych wszystkich eventów, które jednak jeden za drugim będą pomiędzy naszymi usługami wchodzić dopiero. Wspólnie stworzą i zakończą jakiś tam element procesu biznesowego.
Ten projekt interfejsu użytkownika to już będzie chyba bardziej pochodna projektu samej naszej domeny, czyli po prostu z tego, co nam wyjdzie z procesu biznesowego, bo ten proces nam już pokaże. Tutaj mamy zdarzenie stąd to stamtąd to wszystko musi zostać zebrane. I jak to się wszystko zadziało, to dopiero możemy iść dalej. Nie? Na pewno te asynchroniczne w interfejsie użytkownika też będzie musiała być odzwierciedlona jakoś tam.
Przejście od monolitu do mikroserwisów
Natomiast natomiast eventy same w sobie. Wiadomo, dużo mikroserwisów jest praktycznie niezbędne, jeśli chcemy właśnie w ten elastyczny i skalowalny sposób przeprowadzać tę komunikację. Natomiast w samym monolicie wrócimy troszkę do tego tematu. Rozszerzając pewne pewne elementy, możemy również zastosować w naszym zwykłym, starym monolicie, który gdzieś tam stoi obok.
I tutaj Spring, zwykły taki event bus też może być pierwszym wstępem do takiego zastosowania. Ponieważ jeśli chcemy. Odseparować pewne rzeczy w naszym ciele. Oczywiście zanim przejdziemy do mikroserwisów, które magicznie załatwią wszystko, może warto pokusić się o modularny monolit, czyli. Czyli zrobić tym bardziej modularny, a co za tym idzie, wyznaczyć sobie też pewne granice.
Komunikacja wewnętrzna i API
Pewne konteksty jakiś operacji biznesowych, w których pewne rzeczy się dzieją i inne moduły tego monolitu nie będą wiedziały o tych detalach, które jest tam pod spodem. I znowu coś zepsuć monolit i znowu coś za coś. Monolit? Tak, taki był monolityczny. Tak, tak, tak, taki był łatwy do wnioskowania o nim.
Oczywiście możemy sobie to na wiele sposobów technicznie wykonać, bo równie dobrze możemy w każdym takim naszym module, czy to galowym, czy zwykłym czasowym, wystawić jakieś publiczne API na zasadzie zwykłego serwisu Springowego na przykład. To nie musi być oczywiście testowe API jesteśmy, bo na niczym nie ma sensu, ale możemy to zrobić na podstawie np. takiego API i każdy moduł może sobie taki API wystawić jawnie. Inne moduły poprzez to API się komunikują.
Przygotowanie na ewolucję architektury
Natomiast jeśli później będziemy chcieli sobie takie i takie nasze moduły z takim wystawionym API przenieść na mikroserwisy, to jednak te nasze API będą już musiało być zmienione na jakieś bardziej. RESTful API, jakieś czy coś takiego, to już wtedy już taka komunikacja wewnątrz jednej JVM-ki nie przejdzie, bo to już będziemy w świecie mikroserwisów.
Natomiast jeśli od początku taki modularny monolit zintegruje osobę w środku przez jakąś szynę danych. I od samego początku będziemy mieli tę szynę. Później może być nam troszkę prościej przejść do wydzielania poszczególnych fragmentów do zewnętrznych serwisów, bo one już będą w pewien, z deka poważny sposób, się komunikować właśnie poprzez szynę danych. Więc to jest też jeśli. Liczymy, albo wiemy nawet, że może system, albo jego fragmenty będą w przyszłości wyciągane do mikroserwisów.
Modularność i interfejs danych
Może na początku taka modularność na podstawie lokalnej szyny danych może być fajnym, lokalnej bądź wręcz od razu docelowej szyny danych. Chociaż to oczywiste, to bogatemu zabroni. Kto bogatemu zabroni? Wtedy już w ogóle jesteśmy gotowi do. Automatycznego rozdzielenia takich naszych modułów, bo one już się komunikują przez zewnętrzną usługę. Chociaż oczywiście wiadomo, komunikacja modułów w tym samym VM może być lekkim nadużyciem, Ale oczywiście to może mieć swoje zastosowanie, jeśli wiemy, że za chwilę i tak będziemy coś wynosić. To może być też sposób też sprawdzenie, jak ta komunikacja w naszym naszym teście w ogóle się sprawdza.
No ale może żeby już tej Kafki tak strasznie nie eksploatować, to może dałoby się coś czymś prostszym ogarnąć? I mogłoby się okazać, że po prostu sobie zapewniamy zwyczajnie większą modularność z tych naszych klocków. Wewnątrz tego jest. No po prostu psujemy sobie ten monolit. Dalej już nie jest takim zdrowym monolitem, gdzie wszystko jest ze sobą połączone, a jednak pojawiły się te moduły. I co ciekawe, pojawił się back pressure poprzez. Wydzielenie interfejsów danych. Też wtedy nie. Nie, kod jest naszym interfejsem, a dane są naszym interfejsem. Nie tak jak właśnie w komunikacji opartej o Message Driven czy właśnie te duże message. Może do tej definicji, która tam była koślawo nakreślona na początku, można by dołożyć to, że te dane, które stanowią nasze komunikaty.
Modelowanie i kontraktowanie eventów
To jest właśnie API naszego systemu.
No tutaj to pewnie musimy, musimy te eventy również dobrze zamodelować. To tak jak wszystko tak naprawdę, żeby tak naprawdę ograniczyć zakres rzeczy, które w tych eventach pokazujemy. No bo, jakby nie patrzeć, jeśli coś już wyślemy w świat, to jednak wiążemy się pewnym kontraktem z ludźmi, którzy będą tego nasłuchiwać.
Wyzwania w wersjonowaniu eventów
Co gorsze, w tym wypadku nawet nie wiemy, kto będzie na tym nasłuchiwać, więc publikując powiadomienie może być ktoś — Evil Hacker — może być. To może być po prostu jeden z naszych dziesiątków mikroserwisów. Publikując już pewien kontrakt, kto wie, co gorsze?
Ciężko powiedzieć.
Więc trzeba też pamiętać, że, tak jak z wersjonowaniem API, musimy też ze zmianami w naszym API. Musimy też pamiętać, że te eventy, które publikujemy, są też jednak naszym, naszym API. Tu oczywiście możemy rozdzielić eventy takie bardziej domenowe, bardziej wewnętrzne, które może tylko chodzą w naszym niewielkim bounded context – że to tak nazwiemy. Ale na pewno będziemy też eventy, które wysyłamy w szerszy świat, na który może się subskrybować dowolny w ramach naszej organizacji klient. I tutaj zmiana może być już trudniejsza. Musimy jednak zachować ten kontrakt i musimy mieć pewność, że zmiana w strukturze naszego eventu, zmiana jednak nie pociągnie za sobą kaskadowych problemów u klientów, którzy na te eventy się subskrybują, o których nawet nie wiemy.
Notyfikacje i Event Transfer
Że się na to subskrybują.
To by były te właśnie notyfikacje, które na początku omawialiśmy.
Tak, między innymi tak. Działają również takie, które jednak pociągają. Coś jak event transfer, bo tam jeszcze więcej mamy tego, tego i tam naprawdę jeszcze więcej udostępniamy światu zewnętrznemu. Trzeba jednak pamiętać, żeby jednak to nie spowodowało nieoczekiwanych awarii po stronie różnych, różnych klientów.
Testy kontraktowe i luźne powiązania
Są oczywiście różne narzędzia, które mogą nam troszkę spójność tego naszego kontraktu zapewnić. To testy kontraktowe, które sprawdzają nam, czy jednak gdzieś tam spełniamy, spełniony jest kontrakt, którego oczekujemy i który możemy sobie na naszej stronie wykonać. Mniej więcej, mniej lub więcej weryfikując, że kontrakt jest zachowany.
Czyli tutaj byśmy mieli taką możliwość zastosowania tego samego wzorca w mniejszym i szerszym zakresie. Czyli jak byśmy chcieli sobie zapewnić zmniejszenie coupling pomiędzy modułami w monolicie, to możemy sobie. Tam z mniejszymi, z mniejszym rygorem zarządzania tym naszym API opartym na danych wtedy. Zdefiniować tego typu komunikację. A gdybyśmy chcieli pomiędzy mikroserwisami, to niestety właśnie z tymi wszystkimi przyległościami, o których tutaj ładnie opowiedziałeś. Niemniej jednak jest to to samo podejście. W jednym i drugim przypadku, bo tak po prostu. Emitując jakieś tam określone komunikaty. Oczekujemy, że ktoś, ktoś jednak coś tam z nimi zrobi, więc musimy je wysłać w takiej formie, żeby się dało to zrobić.
Konsekwencje luźnej konwersacji
No tak, jednak. Musimy, musimy zapewnić, zapewnić spójność tej naszej konwersacji, którą którą teraz przenosimy na poziom. Taki bardziej luźny akapit. To jednak niesie ze sobą troszkę ten element ryzyka, że. Nasza konwersacja jest luźniejsza, co jest trochę, trochę celem loose coupling, bo chcemy, żeby komponenty były luźno powiązane, ale przez to też tracimy właśnie te reguły, które nie są już tak jasno zdefiniowane, jak np. w zwykłym wywołaniu linijka po linijce.
Nadchodzące wyzwania i Event Sourcing
Więc to jest coś za coś. Trzeba, trzeba sobie z tego zdawać sprawę, że to może ze sobą ponosić pewne konsekwencje. Natomiast jest jeszcze dużo więcej wyzwań. Kto to, taka architektura niesie? I jakie to mogą być wyzwania?
To może o tych wyzwaniach to już w następnym odcinku.
Dobra, to możemy, bo zaczniemy od nich. A później zobaczymy, gdzie nas to zaprowadzi. Być może do tej stolicy. Być może do końca tablicy i pewnie jeszcze trochę do Event Sourcingu, który też jest częścią EDA i który jeszcze jest. Jeszcze krokiem dalej w takim, takim sterowaniu eventami, ale już naprawdę na bardzo dużą skalę i właściwie jest osobnym podejściem. Architektura.
OK, to dzięki.
Do następnego razu.
Dzięki.
Do następnego.