Transakcje między mikrousługami REST?

195

Załóżmy, że mamy użytkownika, mikrousługi REST portfela i bramę API, która skleja rzeczy. Kiedy Bob rejestruje się w naszej witrynie, nasza brama API musi utworzyć użytkownika za pośrednictwem mikrousługi użytkownika i portfela za pośrednictwem mikrousługi portfela.

Oto kilka scenariuszy, w których może się nie udać:

  • Tworzenie Boba użytkownika kończy się niepowodzeniem: to jest OK, po prostu zwracamy komunikat o błędzie do Boba. Używamy transakcji SQL, więc nikt nigdy nie widział Boba w systemie. Wszystko w porządku :)

  • Użytkownik Bob został utworzony, ale zanim można utworzyć nasz Portfel, nasza brama API ulega awarii. Mamy teraz użytkownika bez portfela (niespójne dane).

  • Użytkownik Bob został utworzony, a gdy tworzymy Portfel, połączenie HTTP zostaje zerwane. Utworzenie portfela mogło się powieść lub nie.

Jakie rozwiązania są dostępne, aby zapobiec występowaniu tego rodzaju niespójności danych? Czy istnieją wzorce, które pozwalają transakcjom obejmować wiele żądań REST? Przeczytałem stronę Wikipedii dotyczącą zatwierdzania dwufazowego, która wydaje się dotyczyć tego problemu, ale nie jestem pewien, jak zastosować go w praktyce. Te rozproszone transakcje atomowe: projekt RESTful również wydaje się interesujący, chociaż go jeszcze nie przeczytałem.

Alternatywnie wiem, że REST może po prostu nie pasować do tego przypadku użycia. Czy byłby to właściwy sposób na rozwiązanie tej sytuacji, aby całkowicie zrezygnować z usługi REST i użyć innego protokołu komunikacyjnego, takiego jak system kolejki komunikatów? A może powinienem egzekwować spójność w kodzie aplikacji (na przykład poprzez zadanie w tle, które wykrywa niespójności i je naprawia, czy też posiadając atrybut „stan” w moim modelu użytkownika z wartościami „tworzenia”, „utworzonych” itp.)?

Olivier Lalonde
źródło
3
Ciekawy link: news.ycombinator.com/item?id=7995130
Olivier Lalonde
3
Jeśli użytkownik nie ma sensu bez portfela, po co tworzyć dla niego osobną mikrousługę? Może w ogóle coś jest nie tak z architekturą? Dlaczego potrzebujesz ogólnej bramy API, btw? Czy jest jakiś konkretny powód?
Vladislav Rastrusny
4
@VladislavRastrusny był to fikcyjny przykład, ale można sobie wyobrazić obsługę portfela jako obsługiwaną na przykład przez Stripe.
Olivier Lalonde
Możesz użyć menedżera procesów do śledzenia transakcji (wzorzec menedżera procesów) lub poprosić każdą mikrousługę o to, jak wywołać wycofanie (wzorzec menedżera sagi) lub wykonać jakieś zatwierdzenie dwufazowe ( blog.aspiresys.com/software-product-engineering / producteering /… )
andrew pate
@VladislavRastrusny „Jeśli użytkownik nie ma sensu bez portfela, po co tworzyć dla niego osobną mikrousługę” - na przykład poza tym, że użytkownik nie może istnieć bez portfela, nie ma wspólnego kodu. Tak więc dwa zespoły zamierzają samodzielnie opracować i wdrożyć mikrousługi użytkowników i portfeli. Czy nie chodzi w ogóle o robienie mikrousług?
Nik

Odpowiedzi:

148

Co nie ma sensu:

  • rozproszone transakcje z usługami REST . Usługi REST z definicji są bezstanowe, więc nie powinny być uczestnikami granicy transakcyjnej obejmującej więcej niż jedną usługę. Scenariusz przypadku użycia rejestracji użytkownika ma sens, ale projekt z mikrousługami REST do tworzenia danych użytkownika i portfela nie jest dobry.

Co spowoduje bóle głowy:

  • EJB z transakcjami rozproszonymi . Jest to jedna z tych rzeczy, które działają w teorii, ale nie w praktyce. W tej chwili staram się, aby transakcja rozproszona działała dla zdalnych komponentów EJB w instancjach JBoss EAP 6.3. Rozmawiamy ze wsparciem RedHata od tygodni, ale to jeszcze nie działało.
  • Rozwiązania do zatwierdzania dwufazowego ogólnie . Myślę, że protokół 2PC jest świetnym algorytmem (wiele lat temu zaimplementowałem go w C z RPC). Wymaga kompleksowych mechanizmów odzyskiwania po awarii, z ponownymi próbami, repozytorium stanów itp. Cała złożoność jest ukryta w ramach transakcji (np .: JBoss Arjuna). Jednak 2PC nie jest odporne na błędy. Są sytuacje, których transakcja po prostu nie może zostać ukończona. Następnie musisz ręcznie zidentyfikować i naprawić niespójności bazy danych. Może się zdarzyć raz na milion transakcji, jeśli masz szczęście, ale może się zdarzyć raz na 100 transakcji, w zależności od platformy i scenariusza.
  • Sagas (transakcje kompensacyjne) . Narzut związany z tworzeniem operacji kompensacyjnych oraz mechanizm koordynacji aktywujący kompensację na końcu. Ale odszkodowanie również nie jest odporne na błędy. Nadal możesz mieć niespójności (= jakiś ból głowy).

Jaka jest prawdopodobnie najlepsza alternatywa:

  • Ostateczna spójność . Ani transakcje rozproszone podobne do ACID, ani transakcje kompensujące nie są odporne na awarie i oba mogą prowadzić do niespójności. Ostateczna spójność jest często lepsza niż „okazjonalna niekonsekwencja”. Istnieją różne rozwiązania projektowe, takie jak:
    • Możesz stworzyć bardziej niezawodne rozwiązanie za pomocą komunikacji asynchronicznej. W twoim scenariuszu, gdy Bob się zarejestruje, brama API może wysłać wiadomość do kolejki NewUser i od razu odpowiedzieć użytkownikowi, mówiąc: „Otrzymasz wiadomość e-mail z potwierdzeniem utworzenia konta”. Obsługa klienta w kolejce może przetworzyć wiadomość, wykonać zmiany bazy danych w jednej transakcji i wysłać wiadomość e-mail do Boba, aby powiadomić o utworzeniu konta.
    • Mikrousługa użytkownika tworzy rekord użytkownika i rekord portfela w tej samej bazie danych . W takim przypadku sklep portfela w mikrousługi użytkownika jest repliką głównego sklepu portfela widoczną tylko dla mikrousługi portfela. Istnieje mechanizm synchronizacji danych oparty na wyzwalaczu lub okresowo uruchamiany w celu wysyłania zmian danych (np. Nowych portfeli) z repliki do wzorca i odwrotnie.

Ale co jeśli potrzebujesz synchronicznych odpowiedzi?

  • Zmodeluj mikrousługi . Jeśli rozwiązanie z kolejką nie działa, ponieważ odbiorca usługi potrzebuje natychmiastowej odpowiedzi, wolałbym przebudować funkcje użytkownika i portfela, aby były one kolokowane w tej samej usłudze (lub przynajmniej w tej samej maszynie wirtualnej, aby uniknąć transakcji rozproszonych) ). Tak, jest to krok dalej od mikrousług i bliżej monolitu, ale uratuje cię od bólu głowy.
Paulo Merson
źródło
4
Ostateczna spójność działała dla mnie. W takim przypadku kolejka „NewUser” powinna być wysoka i dostępna.
Ram Bavireddi,
@RamBavireddi do Kafka lub RabbitMQ obsługują odporne kolejki?
v.oddou
@ v.oddou Tak, robią.
Ram Bavireddi,
2
@PauloMerson Nie jestem pewien, jak się różnisz Kompensowanie transakcji do ostatecznej spójności. Co się stanie, jeśli w ostatecznej konsekwencji utworzenie portfela nie powiedzie się?
balsick
2
@balsick Jednym z wyzwań związanych z ostatecznymi ustawieniami spójności jest zwiększona złożoność projektu. Często wymagane są kontrole spójności i zdarzenia korygujące. Wygląd rozwiązania jest różny. W odpowiedzi sugeruję sytuację, w której rekord Portfela jest tworzony w bazie danych podczas przetwarzania wiadomości wysłanej za pośrednictwem brokera wiadomości. W takim przypadku możemy ustawić kanał Dead Letter, tzn. Jeśli przetworzenie tego komunikatu spowoduje błąd, możemy wysłać wiadomość do kolejki niedostarczonych komunikatów i powiadomić zespół odpowiedzialny za „Portfel”.
Paulo Merson
66

To klasyczne pytanie, które zadano mi niedawno podczas wywiadu. Jak zadzwonić do wielu serwisów internetowych i jednocześnie zachować pewną obsługę błędów w środku zadania. Dzisiaj w obliczeniach o wysokiej wydajności unikamy zatwierdzeń dwufazowych. Wiele lat temu czytałem artykuł o tak zwanym „modelu Starbuck” dla transakcji: Pomyśl o procesie zamawiania, płacenia, przygotowywania i odbierania kawy, którą zamawiasz w Starbuck ... Upraszczam rzeczy, ale model zatwierdzania dwufazowego sugerują, że cały proces byłby pojedynczą transakcją owijania wszystkich etapów do momentu otrzymania kawy. Jednak w tym modelu wszyscy pracownicy będą czekać i przestać pracować, aż dostaniesz kawę. Widzisz zdjęcie?

Zamiast tego „model Starbuck” jest bardziej produktywny dzięki przestrzeganiu modelu „najlepszego wysiłku” i kompensacji błędów w procesie. Po pierwsze, upewniają się, że zapłacisz! Następnie są kolejki wiadomości z zamówieniem dołączonym do kubka. Jeśli coś pójdzie nie tak, jak na przykład, że nie dostałeś kawy, to nie jest to, co zamówiłeś itp., Przystępujemy do procesu kompensacji i upewniamy się, że dostaniesz to, czego chcesz lub zwrócimy ci pieniądze. dla zwiększenia wydajności.

Czasami Starbuck marnuje kawę, ale cały proces jest wydajny. Istnieją inne sztuczki do przemyślenia podczas tworzenia usług internetowych, takie jak projektowanie ich w taki sposób, aby można je było wywołać dowolną liczbę razy i nadal zapewniać ten sam efekt końcowy. Więc moje zalecenie to:

  • Nie bądź zbyt precyzyjny w definiowaniu swoich usług internetowych (nie jestem przekonany o szumie w mikrosługach, który ma miejsce w dzisiejszych czasach: zbyt duże ryzyko posunięcia się za daleko);

  • Asynchronizacja zwiększa wydajność, więc wolisz być asynchronicznym, w miarę możliwości wysyłaj powiadomienia pocztą elektroniczną.

  • Zbuduj bardziej inteligentne usługi, aby umożliwić ich „wielokrotne” odwoływanie dowolną liczbę razy, przetwarzając za pomocą UID lub Taskid, które będą postępować zgodnie z zamówieniem od dołu do końca, sprawdzając reguły biznesowe na każdym etapie;

  • Używaj kolejek komunikatów (JMS lub innych) i przekierowuj do procesorów obsługi błędów, które zastosują operacje do „wycofania” poprzez zastosowanie przeciwnych operacji, nawiasem mówiąc, praca z kolejnością asynchroniczną będzie wymagała jakiejś kolejki do sprawdzenia aktualnego stanu procesu, więc zastanów się nad tym;

  • W ostateczności (ponieważ może się to nie zdarzać często) umieść go w kolejce do ręcznego przetwarzania błędów.

Wróćmy do pierwotnego problemu, który został opublikowany. Utwórz konto, utwórz portfel i upewnij się, że wszystko zostało zrobione.

Załóżmy, że usługa internetowa jest wywoływana w celu koordynowania całej operacji.

Pseudo-kod usługi internetowej wyglądałby następująco:

  1. Zadzwoń do mikroserwisu tworzenia konta, przekaż mu trochę informacji i wyjątkowy identyfikator zadania 1.1 Mikrousługa tworzenia konta najpierw sprawdzi, czy to konto zostało już utworzone. Identyfikator zadania jest powiązany z rekordem konta. Mikrousługa wykrywa, że ​​konto nie istnieje, więc tworzy je i przechowuje identyfikator zadania. UWAGA: tę usługę można wywołać 2000 razy, zawsze będzie ona działać tak samo. Usługa odpowiada „paragonem zawierającym minimalne informacje do wykonania operacji cofania, jeśli jest to wymagane”.

  2. Zadzwoń do tworzenia portfela, podając identyfikator konta i identyfikator zadania. Załóżmy, że warunek jest nieprawidłowy i nie można wykonać tworzenia portfela. Wywołanie zwraca błąd, ale nic nie zostało utworzone.

  3. Orkiestrator jest informowany o błędzie. Wie, że musi przerwać tworzenie konta, ale nie zrobi tego sam. Poprosi o to usługę portfela, przekazując „minimalne potwierdzenie cofnięcia” otrzymane na końcu kroku 1.

  4. Usługa Konto odczytuje potwierdzenie cofnięcia i wie, jak cofnąć operację; potwierdzenie cofnięcia może nawet zawierać informacje o innej mikrousługie, którą mógłby nazwać wykonaniem części zadania. W tej sytuacji potwierdzenie cofnięcia może zawierać identyfikator konta i ewentualnie dodatkowe informacje wymagane do wykonania odwrotnej operacji. W naszym przypadku, dla uproszczenia, powiedzmy, że wystarczy usunąć konto, używając jego identyfikatora.

  5. Załóżmy teraz, że usługa internetowa nigdy nie otrzymała sukcesu ani niepowodzenia (w tym przypadku), że cofnięcie utworzenia konta zostało wykonane. Po prostu ponownie wywoła usługę cofania konta. I ta usługa zwykle nie powinna nigdy zawieść, ponieważ jej celem jest, aby konto już nie istniało. Sprawdza więc, czy istnieje i widzi, że nic nie można zrobić, aby go cofnąć. Zwraca więc, że operacja się powiodła.

  6. Usługa internetowa zwraca użytkownikowi, że nie można utworzyć konta.

To jest przykład synchroniczny. Moglibyśmy to zrobić w inny sposób i umieścić skrzynkę w kolejce wiadomości skierowanej do działu pomocy technicznej, jeśli nie chcemy, aby system całkowicie odzyskał błąd ". Widziałem, jak dzieje się to w firmie, w której jest za mało do systemu zaplecza można było podłączyć haki, aby poprawić sytuację. Dział pomocy technicznej otrzymał wiadomości zawierające informacje o tym, co zostało wykonane pomyślnie i miał wystarczającą ilość informacji, aby naprawić rzeczy, podobnie jak nasze potwierdzenie cofnięcia może być wykorzystane w pełni zautomatyzowany sposób.

Przeprowadziłem wyszukiwanie, a strona internetowa Microsoft zawiera opis wzorca dla tego podejścia. Nazywa się to wzorcem transakcji kompensacyjnej:

Kompensacyjny wzorzec transakcji

użytkownik8098437
źródło
2
Czy uważasz, że możesz rozwinąć tę odpowiedź, aby udzielić OP bardziej szczegółowych porad. W tej chwili ta odpowiedź jest nieco niejasna i trudna do zrozumienia. Chociaż rozumiem, w jaki sposób podaje się kawę w Starbucks, nie jest dla mnie jasne, jakie aspekty tego systemu powinny być emulowane w usługach REST.
jwg
Dodałem przykład związany ze sprawą początkowo podany w oryginalnym poście.
user8098437
2
Właśnie dodałem link do wzorca transakcji kompensacyjnej zgodnie z opisem firmy Microsoft.
user8098437,
3
Dla mnie to najlepsza odpowiedź. Tak proste
Oscar Nevarez
1
Należy pamiętać, że kompensowanie transakcji może być całkowicie niemożliwe w niektórych złożonych scenariuszach (co doskonale podkreślono w dokumentach Microsoft). W tym przykładzie wyobraź sobie, że zanim utworzenie portfela nie powiedzie się, ktoś może przeczytać szczegóły dotyczące powiązanego konta, wykonując wywołanie GET w usłudze Konto, co idealnie nie powinno istnieć w pierwszej kolejności, ponieważ utworzenie konta nie powiodło się. Może to prowadzić do niespójności danych. Ten problem izolacji jest dobrze znany we wzorze SAGAS.
Anmol Singh Jaggi
32

Wszystkie systemy rozproszone mają problemy ze spójnością transakcyjną. Najlepszym sposobem na to jest, jak powiedziałeś, zatwierdzenie dwufazowe. Niech portfel i użytkownik zostaną utworzone w stanie oczekiwania. Po utworzeniu wykonaj osobne połączenie, aby aktywować użytkownika.

To ostatnie połączenie powinno być bezpiecznie powtarzalne (na wypadek utraty połączenia).

Będzie to wymagało, aby ostatnie wywołanie znało obie tabele (aby można było to zrobić w pojedynczej transakcji JDBC).

Możesz też zastanowić się, dlaczego tak bardzo martwisz się o użytkownika bez portfela. Czy uważasz, że spowoduje to problem? Jeśli tak, być może złym rozwiązaniem są osobne wezwania do odpoczynku. Jeśli użytkownik nie powinien istnieć bez portfela, prawdopodobnie należy go dodać do użytkownika (w pierwotnym wywołaniu POST, aby go utworzyć).

Rob Conklin
źródło
Dzieki za sugestie. Usługi użytkownika / portfela były fikcyjne, aby zilustrować tę kwestię. Zgadzam się jednak, że powinienem zaprojektować system tak, aby w jak największym stopniu uniknąć potrzeby transakcji.
Olivier Lalonde
7
Zgadzam się z drugim punktem widzenia. Wydaje się, że to, co twoja mikrousługa, która tworzy użytkownika, powinna również utworzyć portfel, ponieważ ta operacja reprezentuje atomową jednostkę pracy. Możesz także przeczytać ten eaipatterns.com/docs/IEEE_Software_Design_2PC.pdf
Sattar Imamov
2
To jest naprawdę świetny pomysł. Cofnięcia to ból głowy. Ale tworzenie czegoś w stanie oczekiwania jest znacznie mniej inwazyjne. Wszelkie kontrole zostały wykonane, ale nie ma jeszcze żadnych ostatecznych danych. Teraz musimy tylko aktywować utworzone komponenty. Prawdopodobnie możemy to zrobić nawet bez transakcji.
Timo
10

IMHO jednym z kluczowych aspektów architektury mikrousług jest to, że transakcja ogranicza się do pojedynczej mikrousługi (zasada pojedynczej odpowiedzialności).

W obecnym przykładzie tworzenie użytkownika byłoby własną transakcją. Utworzenie użytkownika wypchnęłoby zdarzenie USER_CREATED do kolejki zdarzeń. Usługa Portfela zasubskrybuje wydarzenie USER_CREATED i wykona tworzenie Portfela.

mithrandir
źródło
1
Zakładając, że chcemy uniknąć jakiegokolwiek 2PC i zakładając, że usługa użytkownika zapisuje do bazy danych, nie możemy przesuwać wiadomości do kolejki zdarzeń przez użytkownika, aby była transakcyjna, co oznacza, że ​​nigdy nie zdoła usługa Portfela.
Roman Charkowski
@RomanKharkovski Rzeczywiście ważny punkt. Jednym ze sposobów rozwiązania tego problemu może być rozpoczęcie transakcji, zapisanie użytkownika, opublikowanie zdarzenia (nie jest częścią transakcji), a następnie zatwierdzenie transakcji. (W najgorszym przypadku, bardzo mało prawdopodobne, zatwierdzenie kończy się niepowodzeniem, a osoby reagujące na zdarzenie nie będą mogły znaleźć użytkownika.)
Timo
1
Następnie zapisz zdarzenie w bazie danych oraz encji. Zaplanuj zadanie przetwarzania przechowywanych zdarzeń i wysłania ich do brokera wiadomości. stackoverflow.com/a/52216427/4587961
Yan Khonski
7

Gdyby mój portfel był kolejną wiązką rekordów w tej samej bazie danych SQL, co użytkownik, prawdopodobnie umieściłbym kod użytkownika i portfel w tej samej usłudze i obsłużyłbym to przy użyciu zwykłych funkcji transakcyjnych bazy danych.

Wydaje mi się, że pytasz o to, co się stanie, gdy kod tworzenia portfela wymaga dotknięcia innego systemu lub systemów? Twierdzę, że wszystko zależy od tego, jak skomplikowany lub ryzykowny jest proces tworzenia.

Jeśli chodzi tylko o dotknięcie innego wiarygodnego magazynu danych (powiedzmy, który nie może uczestniczyć w twoich transakcjach SQL), to w zależności od ogólnych parametrów systemu, zaryzykuję znikomą szansę, że drugi zapis nie nastąpi. Mogę nic nie zrobić, ale zgłosić wyjątek i poradzić sobie z niespójnymi danymi za pomocą transakcji kompensacyjnej lub nawet jakiejś metody ad hoc. Jak zawsze mówię moim programistom: „jeśli coś takiego dzieje się w aplikacji, nie pozostanie niezauważone”.

W miarę wzrostu złożoności i ryzyka tworzenia portfela należy podjąć kroki w celu zmniejszenia związanego z tym ryzyka. Powiedzmy, że niektóre kroki wymagają połączenia z wieloma partnerami API.

W tym momencie możesz wprowadzić kolejkę wiadomości wraz z pojęciem częściowo zbudowanych użytkowników i / lub portfeli.

Prostą i skuteczną strategią upewnienia się, że twoje jednostki w końcu prawidłowo się zbudują, jest ponawianie zadań, dopóki się nie powiedzie, ale wiele zależy od przypadków użycia aplikacji.

Zastanawiałbym się też długo i zastanawiałem się, dlaczego miałem krok podatny na awarię w procesie udostępniania.

Robert Moskal
źródło
4

Jednym prostym rozwiązaniem jest utworzenie użytkownika za pomocą usługi użytkownika i użycie magistrali wiadomości, w której usługa użytkownika emituje swoje zdarzenia, a usługa portfela rejestruje się w magistrali wiadomości, nasłuchuje zdarzenia utworzonego przez użytkownika i tworzy portfel dla użytkownika. W międzyczasie, jeśli użytkownik przejdzie do interfejsu Portfela, aby zobaczyć swój Portfel, sprawdź, czy użytkownik został właśnie utworzony i pokaż, że tworzenie portfela jest w toku, sprawdź za jakiś czas

techagrammer
źródło
3

Jakie rozwiązania są dostępne, aby zapobiec występowaniu tego rodzaju niespójności danych?

Tradycyjnie używa się rozproszonych menedżerów transakcji. Kilka lat temu w świecie Java EE mogłeś stworzyć te usługi jako EJB, które zostały wdrożone w różnych węzłach, a twoja brama API wykonywałaby zdalne połączenia z tymi EJB. Serwer aplikacji (jeśli jest poprawnie skonfigurowany) automatycznie zapewnia, przy użyciu zatwierdzania dwufazowego, że transakcja jest zatwierdzona lub wycofana w każdym węźle, aby zagwarantować spójność. Wymaga to jednak, aby wszystkie usługi były wdrażane na tym samym typie serwera aplikacji (tak, aby były kompatybilne), aw rzeczywistości działały tylko z usługami wdrożonymi przez jedną firmę.

Czy istnieją wzorce, które pozwalają transakcjom obejmować wiele żądań REST?

W przypadku SOAP (ok, nie REST) ​​istnieje specyfikacja WS-AT, ale żadna usługa, którą kiedykolwiek musiałem zintegrować, nie obsługuje tego. W przypadku REST JBoss ma coś w przygotowaniu . W przeciwnym razie „wzorzec” oznacza albo znalezienie produktu, który można podłączyć do swojej architektury, albo zbudować własne rozwiązanie (niezalecane).

Opublikowałem taki produkt dla Java EE: https://github.com/maxant/genericconnector

Zgodnie z dokumentem, do którego się odwołujesz, istnieje również wzór Try-Cancel / Confirm i powiązany Produkt Atomikos.

Silniki BPEL obsługują spójność między zdalnie wdrażanymi usługami za pomocą kompensacji.

Alternatywnie wiem, że REST może po prostu nie pasować do tego przypadku użycia. Czy byłby to właściwy sposób na rozwiązanie tej sytuacji, aby całkowicie zrezygnować z usługi REST i użyć innego protokołu komunikacyjnego, takiego jak system kolejki komunikatów?

Istnieje wiele sposobów „wiązania” zasobów nietransakcyjnych do transakcji:

  • Jak sugerujesz, możesz użyć transakcyjnej kolejki komunikatów, ale będzie ona asynchroniczna, więc jeśli zależysz od odpowiedzi, staje się bałagan.
  • Możesz zapisać fakt, że musisz wywołać usługi zaplecza do swojej bazy danych, a następnie wywołać usługi zaplecza za pomocą partii. Znowu asynchronizacja, więc może się popsuć.
  • Można użyć silnika procesów biznesowych jako bramy interfejsu API do koordynowania mikrousług zaplecza.
  • Można użyć zdalnego komponentu EJB, jak wspomniano na początku, ponieważ obsługuje on rozproszone transakcje od razu po wyjęciu z pudełka.

A może powinienem egzekwować spójność w kodzie aplikacji (na przykład poprzez zadanie w tle, które wykrywa niespójności i je naprawia, czy też posiadając atrybut „stan” w moim modelu użytkownika z wartościami „tworzenia”, „utworzonych” itp.)?

Grając w adwokaty diabłów: po co budować coś takiego, skoro istnieją produkty, które robią to za Ciebie (patrz wyżej) i prawdopodobnie robią to lepiej niż możesz, ponieważ są wypróbowane i przetestowane?

Ant Kutschera
źródło
2

Osobiście podoba mi się pomysł Micro Services, modułów zdefiniowanych przez przypadki użycia, ale jak wspomina twoje pytanie, mają problemy z adaptacją dla klasycznych firm, takich jak banki, ubezpieczenia, telekomunikacja itp.

Transakcje rozproszone, jak już wspomniano, nie są dobrym wyborem, ludzie wybierają teraz bardziej spójne systemy, ale nie jestem pewien, czy to zadziała w przypadku banków, ubezpieczeń itp.

Napisałem blog o moim proponowanym rozwiązaniu, może to ci pomóc ...

https://mehmetsalgar.wordpress.com/2016/11/05/micro-services-fan-out-transaction-problems-and-solutions-with-spring-bootjboss-and-netflix-eureka/

posthumecaver
źródło
0

Ostateczna spójność jest tutaj kluczem.

  • Jedna z usług została wybrana, aby stać się głównym operatorem wydarzenia.
  • Ta usługa obsłuży pierwotne zdarzenie za pomocą pojedynczego zatwierdzenia.
  • Główny program obsługi bierze odpowiedzialność za asynchroniczne komunikowanie efektów wtórnych innym usługom.
  • Główny moduł obsługi wykona połączenia innych usług.

Dowódca odpowiada za rozproszoną transakcję i przejmuje kontrolę. Zna instrukcje do wykonania i będzie koordynował ich wykonywanie. W większości scenariuszy będą tylko dwie instrukcje, ale może obsłużyć wiele instrukcji.

Dowódca bierze odpowiedzialność za zagwarantowanie wykonania wszystkich instrukcji, a to oznacza wycofanie się. Gdy dowódca próbuje przeprowadzić zdalną aktualizację i nie otrzymuje odpowiedzi, nie podejmuje ponownej próby. W ten sposób system można skonfigurować tak, aby był mniej podatny na awarie i sam się leczy.

Ponieważ mamy próby, mamy idempotencję. Idempotencja to właściwość bycia w stanie zrobić coś dwa razy w taki sposób, aby wyniki końcowe były takie same, jak gdyby zrobiono to tylko raz. Potrzebujemy idempotencji w zdalnej usłudze lub źródle danych, aby w przypadku, gdy otrzyma instrukcję więcej niż raz, przetwarza ją tylko raz.

Ostateczna spójność To rozwiązuje większość rozproszonych wyzwań transakcyjnych, jednak musimy wziąć pod uwagę kilka punktów tutaj. Po każdej nieudanej transakcji nastąpi ponowienie, liczba prób ponownych prób zależy od kontekstu.

Spójność jest ostateczna, tzn. Gdy system jest niespójny podczas ponownej próby, na przykład jeśli klient zamówił książkę, dokonał płatności, a następnie zaktualizował ilość zapasów. Jeśli operacje aktualizacji zapasów zakończą się niepowodzeniem i przy założeniu, że był to ostatni dostępny zapas, książka będzie nadal dostępna, dopóki operacja ponownej próby aktualizacji zapasów nie powiedzie się. Po ponownej próbie system będzie spójny.

Viyaan Jhiingade
źródło
-2

Dlaczego nie skorzystać z platformy API Management (APIM) obsługującej skrypty / programowanie? Będziesz mógł budować usługę złożoną w APIM bez zakłócania mikrousług. W tym celu zaprojektowałem przy użyciu APIGEE.

sra
źródło