Jaki jest właściwy sposób synchronizacji danych między mikrousługami?


19

Jestem stosunkowo nowy w architekturze mikrousług. Mamy aplikację internetową o średniej wielkości i rozważam zalety i wady podziału jej na mikrousługi zamiast monolitycznego systemu, który teraz rozwijamy.

O ile dobrze rozumiem, rozważyć microservices Ai Bkażdy z nich polegają na podzbiór danych, że druga. Jeśli wiadomość zostanie opublikowana z Ainformacją, że coś się zmieniło, Bmoże zużyć tę wiadomość i powielić lokalną kopię Ainformacji i użyć go do zrobienia tego, co Btrzeba.

Jednak co się stanie, jeśli nastąpi Bawaria / awaria, a po chwili wróci ponownie. W tym czasie Aopublikował jeszcze dwie wiadomości. Skąd Bwiadomo, jak zaktualizować lokalną kopię Ainformacji?

Oczywiście, jeśli Bjest jedynym konsumentem w Akolejce, to może zacząć ją czytać po powrocie do trybu online, ale co, jeśli są inni konsumenci w kolejce i te wiadomości są konsumowane?

Bardziej konkretnym przykładem jest to, że jeśli Usersusługa ma zaktualizowany adres e-mail, gdy Billingmikrousługa jest wyłączona, jeśli Billingmikrousługa wróci ponownie, skąd wiadomo, że wiadomość e-mail została zaktualizowana?

Kiedy mikrousługi pojawiają się ponownie, czy nadają, mówiąc: „Hej, wróciłem, podaj mi wszystkie swoje aktualne informacje?”

Ogólnie, jakie byłyby najlepsze praktyki branżowe w zakresie synchronizacji danych?


1
Aby tego uniknąć, gdy tylko jest to możliwe.
Telastyn,

1
Dlaczego Orderstrzeba coś wiedzieć Users?
kdgregory,

To tylko przykład. Wymień dwa na dowolne, co ma sens.
noblerare

przekierowanie fan out rozwiąże problem „wiadomość została pochłonięta przez kogoś innego”. ale naprawdę nie jest jasne, co próbujesz osiągnąć.
Ewan,

@Ewan Zaktualizowałem swój oryginalny post, aby lepiej wyjaśnić, o co próbuję zapytać.
noblerare

Odpowiedzi:


5

Zakwestionowałbym cały twój pomysł „wypychania danych do wszystkich innych mikrousług”.

Zwykle, jeśli usługa rozliczeniowa potrzebuje adresu e-mail, po prostu prosi usługę adresową o adres e-mail konkretnego klienta. Nie musi przechowywać kopii wszystkich danych adresowych ani nie będzie informowany, jeśli coś się zmieni. Po prostu pyta i otrzymuje odpowiedź z najnowszych danych.


Myślę, że ta odpowiedź jest dokładnie poprawna. Eliminuje wiele problemów związanych z synchronizacją. W rzeczywistości patrzę teraz na kod, który ma takie problemy, ponieważ różne usługi przechowują kopie informacji i mają takie problemy z synchronizacją.
DaveG

2
Dziękuję za odpowiedź. Dlaczego więc potrzebny jest model pub / sub i kolejki komunikatów? Jeśli próbujemy „pobierać” zamiast „wypychać” dane, martwimy się opóźnieniami usługi.
noblerare

AFAIK, twoja usługa nie musi reagować natychmiast, jeśli coś się zmieni (jak w pubie / sub), ale czasami potrzebuje danych. Potem po prostu wyciągnę to. Jeśli martwisz się opóźnieniami, możesz buforować dane, ale to znowu kosztuje nie wiedząc, czy dane są aktualne. Jeśli twoje pliki są duże, możesz również zapytać, czy coś się zmieni, zanim ponownie coś wyciągniesz.
J. Fabian Meier,

Należy pamiętać, że to rozwiązanie wiąże się z kosztem ścisłego powiązania usługi zależnej, co oznacza, że ​​adres e-mail będzie niedostępny, gdy usługa użytkownika będzie niedostępna. Jeden z początkowych pomysłów na zerwanie z usługami, tak aby można je było niezależnie wdrożyć, skalować itp. Jeśli wszystkie usługi komunikują się ze sobą bezpośrednio bez pamięci podręcznej lub gwarancji wysokiej dostępności, to gdy jeden system jest wyłączony, wszystkie spadać.
dukethrash,

@dukethrash Następnie uczyń je wysoce dostępnymi.
J. Fabian Meier,

5

Po przeprowadzeniu nieco więcej badań natknąłem się na ten artykuł, z którego wyciągnąłem cytaty, które moim zdaniem są pomocne w tym, co chcę osiągnąć (i dla przyszłych czytelników). Umożliwia to przyjęcie modelu programowania reaktywnego zamiast modelu programowania imperatywnego.

Pozyskiwanie zdarzeń

Chodzi o to, aby przedstawić przejście stanu każdej aplikacji w formie niezmiennego zdarzenia. Zdarzenia są następnie zapisywane w formie dziennika lub dziennika w momencie ich wystąpienia (zwane również „magazynem zdarzeń”). Można je również przeszukiwać i przechowywać w nieskończoność, aby przedstawić, w jaki sposób stan aplikacji jako całości ewoluował w czasie.

Pomaga to w osiągnięciu tego, że jeśli mikrousługa ulegnie awarii, a inne związane z nią zdarzenia zostaną opublikowane, a zdarzenia zostaną zużyte przez, powiedzmy, inne przypadki tej mikrousługi, gdy ta mikrousługa powróci, może odnosić się do tego, event storeaby pobrać wszystkie wydarzenia, które przeoczył w okresie upadku.

Apache Kafka jako Broker wydarzeń

Rozważ zastosowanie Apache Kafka, który może przechowywać i wywoływać tysiące zdarzeń na sekundę oraz ma wbudowane mechanizmy replikacji i odporności na uszkodzenia. Ma trwały magazyn zdarzeń, które mogą być przechowywane na dysku w nieskończoność i zużyte w dowolnym momencie (ale nie usunięte) z Tematu (fantazyjna kolejka Kafki), do którego zostały dostarczone.

Zdarzeniom przypisuje się następnie przesunięcia, które jednoznacznie identyfikują je w Temacie - Kafka może samodzielnie zarządzać przesunięciami, łatwo zapewniając semantykę dostarczania „co najmniej raz” lub „co najmniej raz”, ale można je również negocjować, gdy konsument zdarzenia dołącza do Tematu , umożliwiając mikrousługom rozpoczęcie konsumpcji zdarzeń z dowolnego dowolnego miejsca w czasie - zwykle od miejsca, w którym konsument przerwał. Jeśli przesunięcie ostatniego zużytego zdarzenia jest transakcyjnie utrwalane w lokalnej pamięci usług, gdy przypadki użycia „zakończono pomyślnie”, to przesunięcie można łatwo wykorzystać do osiągnięcia semantyki dostarczania zdarzeń „dokładnie raz”.

W rzeczywistości, kiedy konsumenci identyfikują się z Kafką, Kafka rejestruje, które wiadomości zostały dostarczone do którego konsumenta, aby nie mogła go ponownie podać.

Sagi

W przypadku bardziej skomplikowanych przypadków użycia, w których komunikacja między różnymi usługami jest rzeczywiście konieczna, odpowiedzialność za ukończenie skrzynki użycia musi być dobrze rozpoznana - skrzynka użycia jest zdecentralizowana i kończy się dopiero, gdy wszystkie zaangażowane usługi uznają swoje zadanie za pomyślnie ukończone, w przeciwnym razie cała skrzynka użytkowników musi zawieść należy zastosować środki naprawcze w celu przywrócenia dowolnego nieprawidłowego stanu lokalnego.

Właśnie wtedy pojawia się saga. Saga to sekwencja lokalnych transakcji. Każda transakcja lokalna aktualizuje bazę danych i publikuje komunikat lub zdarzenie w celu uruchomienia następnej transakcji lokalnej w sadze. Jeśli lokalna transakcja nie powiedzie się, ponieważ narusza regułę biznesową, saga wykonuje serię transakcji kompensacyjnych, które cofają zmiany wprowadzone w poprzednich transakcjach lokalnych. Przeczytaj to, aby uzyskać więcej informacji.


Nadal nie rozumiem, dlaczego chcesz zbudować tak skomplikowaną strukturę. Zazwyczaj jest to o wiele łatwiejsze, jeśli każda usługa przechowuje własne dane i przekazuje je innym usługom na żądanie.
J. Fabian Meier

^ Ale zmniejszy to dostępność systemu. Skomplikowana struktura może być uzasadniona, jeśli wymagana jest wysoka odporność.
avmohan

1

Nawet jeśli się spóźnię, postawiłbym swoje 2 centy na argument, ponieważ uważam, że jest to ważny punkt, gdy chcesz ocenić e zaprojektować architekturę mikrousług opartą na zdarzeniach. Każda mikrousługa dokładnie wie, które zdarzenia wpływają na jej stan i jest w stanie na nie czekać. Gdy mikrousługa nie jest dostępna, powinien istnieć komponent, który przechowuje wiadomości potrzebne z uszkodzonej mikrousługi, dopóki nie będzie w stanie ich „zużyć”. W rzeczywistości jest to model „producent / konsument”, a nie model „publikuj / subskrybuj”. Brokerzy wiadomości (jak Kafka, RabbitMQ, ActiveMQ itp.) Są zwykle najlepszym sposobem na osiągnięcie tego zachowania (chyba że nie wdrażasz czegoś innego, takiego jak pozyskiwanie zdarzeń), zapewniając trwałe kolejki i mechanizm potwierdzenia / nacka.

Teraz mikrousługa wie, że wiadomość jest ostatecznie dostarczana, ale to nie wystarczy: w jaki sposób oczekuje dostarczenia pojedynczej wiadomości? czy może zarządzać dostarczaniem wielu kopii tego samego powiadomienia o zdarzeniu? Jest to kwestia dostawy semantycznej (przynajmniej raz, dokładnie raz)

Końcowe przemyślenia):

  1. Kiedy dodajesz mikrousługę do swojej architektury, która musi pobierać zdarzenia od innych, musisz wykonać pierwszą synchronizację

  2. Nawet broker może zawieść, w tym przypadku wiadomości zostaną utracone

dla obu scenariuszy przydatne byłyby proste mechanizmy ponownego nawodnienia stanu mikrousług. Może to być interfejs API REST lub skrypt, który wysyła komunikaty, ale najważniejsze jest, aby mieć środki do wykonania jakiegoś zadania konserwacyjnego


0

Możesz zamienić normalną kolejkę zdarzeń na model wydawcy / subskrybenta, w którym Ausługa publikuje nową wiadomość w temacie T, a Btyp mikrousług subskrybuje ten sam temat.

Idealnie Bbyłaby to usługa bezstanowa i wykorzystywałaby odłączoną usługę trwałości, tak że Binstancja usługi, która uległa awarii , zostałaby zastąpiona przez odrodzenie jednej lub więcej Binstancji usługi w celu kontynuowania pracy, odczytywanie z tej samej współużytkowanej usługi trwałości.


0

Jeśli A opublikuje wiadomość z informacją, że coś się zmieniło, B może zużyć tę wiadomość i powielić lokalną kopię informacji A i użyć tego do zrobienia tego, co B musi zrobić.

Jeśli chcesz, aby B miał dostęp do wewnętrznych danych A, lepiej byłoby po prostu dać mu dostęp do wewnętrznych baz danych A.

Jednak nie powinieneś tego robić, cały punkt architektury zorientowanej na usługi polega na tym, że usługa B nie widzi stanu wewnętrznego usługi A i jest ograniczona do wysyłania żądań za pośrednictwem interfejsów API REST (i odwrotnie).

W twoim przypadku możesz mieć usługę danych użytkownika, która ma obowiązek przechowywania wszystkich danych użytkownika. Inne usługi, które chcą korzystać z tych danych, żądają ich tylko wtedy, gdy są potrzebne i nie przechowują kopii lokalnej (co przy okazji jest naprawdę przydatne, jeśli myślisz o zgodności z RODO). Usługa danych użytkownika może obsługiwać proste operacje CRUD, takie jak „Utwórz nowego użytkownika” lub „Zmień nazwę dla ID_użytkownika 23”, lub może mieć bardziej skomplikowane operacje, „Znajdź wszystkich standardowych użytkowników z datą urodzin w ciągu najbliższych 2 tygodni i daj im status premium premium ”. Teraz, gdy twoja usługa fakturowania musi wysłać wiadomość e-mail do użytkownika 42, zapyta usługę danych użytkownika „Jaki jest adres e-mail dla ID_użytkownika 42”, wykorzysta swoje dane wewnętrzne ze wszystkimi informacjami rozliczeniowymi do stworzenia wiadomości e-mail, a następnie może przekazać adres e-mail i treść do serwera pocztowego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.