Buduję nową aplikację i czytałem o architekturze mikrousług. Sama architektura ma wiele sensu z punktu widzenia rozwoju, wdrażania i zarządzania cyklem życia. Jednak pojawił się jeden problem związany z obsługą danych podstawowych.
Na przykład mam 2 aplikacje - powiedzmy aplikację Sprzedaż i aplikację do sprzedaży biletów. Załóżmy, że obie te aplikacje są zbudowane jako własne mikrousługi. Jednak obie te aplikacje, jeśli zostaną wdrożone (zakładając, że są wdrażane osobno, mówią, że Sales używa MongoDB, a Ticketing używa MariaDB), musiałyby mieć dostęp do tych samych danych podstawowych, np. Konta, Produkty. Oznaczałoby to, że dla danego podmiotu danych podstawowych istniałaby aplikacja właściciela (np. W przypadku rachunków może to być aplikacja Sprzedaż) oraz zainteresowana strona (np. Aplikacja do sprzedaży biletów musiałaby mieć informacje o rachunkach).
Można to osiągnąć na wiele sposobów: - Replikacja danych od głównego do zainteresowanego - Synchroniczny odczyt od zainteresowanego do drugiego (zależność synchronizacji nie jest zalecana w paradygmacie architektury mikro-usług) - Własne scentralizowane repozytorium
Również w obrębie kont może istnieć podstawowa część, która jest wspólna zarówno dla sprzedaży, jak i sprzedaży biletów (np. Nazwa konta, adres itp.). Jednak niektóre aspekty konta mogą dotyczyć WYŁĄCZNIE sprzedaży, a inne TYLKO sprzedaży biletów.
Wszelkie przemyślenia / najlepsze praktyki / opinie dotyczące którejkolwiek z wyżej wymienionych opcji?
Odpowiedzi:
Należałem do zespołu, który z powodzeniem zbudował architekturę mikrousług za pomocą magistrali usług.
Początkowo wierzyliśmy, że mikrousługi i architektura sterowana zdarzeniami pozwolą nam naprawić bazową współdzieloną bazę danych.
Dowiedzieliśmy się, że mikrousługi i architektura sterowana zdarzeniami wymagały od nas pozbycia się bazowej współdzielonej bazy danych.
Uważam, że udostępnianie danych jest niezwykle trudne w przypadku mikrousług - dla mnie jest to zbyt trudne. Odradzam usługom wzajemne wyświetlanie danych. Jeśli nie możesz go zapytać, nie możesz przypadkowo wprowadzić zależności.
Jeśli zrobić danych jednostek, na pewno tylko jedna z nich może kiedykolwiek własny rekord; jest to jedyna usługa zapisująca do rekordu, a każdy inny użytkownik tych samych danych powinien mieć dostęp tylko do odczytu.
Niestety, nawet ta niewielka zarządzana ilość udostępniania powoduje znaczące powiązanie między twoimi usługami. Co jeśli jedna usługa nie chce danych w tym kształcie? Być może chce agregacji. Czy otrzymujesz usługę „właściciela / zapisu” do zapisu danych zbiorczych na rzecz innej usługi? Radziłbym nie.
Co jeśli właściciel chce utrwalić dane w innym kształcie? Następnie każdą usługę czytnika należy zaktualizować. To koszmar konserwacji.
Najlepszym rozwiązaniem, jakie mieliśmy, było znaczne powielenie i denormalizacja naszych danych. Mikrousługi utrzymywały własne kopie danych, na których im zależało.
Wiadomości były często publikowane z wystarczającą ilością danych towarzyszących do ich przetworzenia.
Na przykład możesz sobie wyobrazić, że usługa wysyłki pocztowej może potrzebować śledzenia zmian adresu klienta, na wypadek, gdyby musiał coś opublikować. Ale jeśli wiadomość „Produkt gotowy do wysyłki” zawiera adres docelowy jako część danych wiadomości, usługa wysyłki nie musi już w ogóle śledzić zmieniających się adresów związanych z klientami; tylko adresy punktu w czasie związane z przesyłkami.
Nie mogę zasugerować, jak zaprojektować rozwiązania z synchronizowanymi danymi. Nasze rozwiązania danych zostały zbudowane wokół idei „ostatecznej spójności”.
Gdy klient aktualizuje swój adres, usługa adresowa przetwarza początkowe polecenie z interfejsu użytkownika. Gdy dane są poprawne, publikuje zdarzenie, aby powiadomić wszystkie inne zainteresowane usługi o „Zaktualizowano adres klienta” - z pełnym adresem dołączonym jako dane. Usługi te zaktualizują swoje własne magazyny danych o te części danych, które są dla nich ważne.
Chodzi o to, że za każdym razem, gdy usługa musi podjąć ważne działanie, powinna mieć kopię informacji na tyle aktualną, aby działać poprawnie, niezależnie od tego, czy jest śledzona niezależnie, czy też jako część wiadomości, na którą odpowiada.
źródło
Wspólne przechowywanie danych byłoby sprzeczne z architekturą mikrousług. Chodzi o to, że jeśli istnieją Konta, powinna istnieć usługa ich obsługi i nie powinno istnieć żaden inny sposób interakcji z tymi Kontami oprócz dokładnej obsługi. Twoje mikrousługi nie byłyby niezależne, gdyby współużytkowały wspólną pamięć masową, a każda zmiana w mechanizmie pamięci, sprawdzanie poprawności lub inne ograniczenia musiałyby zostać wprowadzone w obu usługach. W praktyce tak się nigdy nie dzieje i wkrótce prowadzi do uniknięcia poważnych zmian w obu aplikacjach.
Dlatego skorzystaj z usługi jako jedynego sposobu dostępu do swoich danych, np. Kont. Może się zdarzyć, że implementacja funkcji w innej usłudze wymaga zmiany w usłudze Konta, i to jest OK. Pamiętaj tylko, że logika specyficzna dla każdej usługi powinna być w tej usłudze i jak najmniej konkretnych rzeczy powinno być dostępnych w mikrousługach Konta.
źródło
Nie ten sam. Każda mikrousługa powinna wykonać własne mapowanie kont, produktów itp. Zakładamy, że każda mikrousługa będzie miała inny sposób pracy z podmiotami.
W Domain Driven Design jest to powszechne, gdy każdy ograniczony kontekst (w tej samej aplikacji!) Może odwzorować ten sam byt w inny sposób.
Jeśli potrzebujesz więcej informacji, polecam książkę Building Microservices: Design Fine-Grained Systems
źródło
Czy zastanawiałeś się nad pojęciem rekordów szkieletów opartych na zestawie głównym?
Na przykład jedna mikrousługa obsługuje konta, a druga obsługuje produkty. Trzeci może przechowywać zapisy z obu stron dla swojego konkretnego celu.
źródło