Mój zespół migruje z monolitycznej aplikacji ASP.NET do .NET Core i Kubernetes. Wydaje się, że zmiany w kodzie idą tak dobrze, jak można się spodziewać, ale w miejscu, w którym mój zespół napotyka wiele niezgody, wokół bazy danych.
Obecnie mamy dość dużą bazę danych SQL Server, która zawiera wszystkie dane dla całej naszej firmy. Proponuję, abyśmy podzielili bazę danych w podobny sposób, jak podział kodu - dane katalogowe w jednej (logicznej) bazie danych, dane inwentaryzacyjne w innej, zamówienia w innej itd. - a każda mikrousługa byłaby strażnikiem bazy danych .
Oznacza to, że klucze obce przekraczające granice mikrousług musiałyby zostać usunięte, a sproki i widoki przekraczające granice byłyby zabronione. Wszystkie modele danych mogą, ale nie muszą znajdować się w tej samej fizycznej bazie danych, ale nawet jeśli tak, to nie powinny bezpośrednio ze sobą oddziaływać. Zamówienia mogą nadal odwoływać się do pozycji katalogu według Id, ale integralność danych nie byłaby ściśle egzekwowana na poziomie bazy danych i dane muszą być połączone w kodzie, a nie w SQL.
Widzę ich utratę jako konieczny kompromis w przejściu do mikrousług i uzyskiwaniu korzyści skalowalności. Tak długo, jak mądrze wybieramy nasze szwy i rozwijamy się wokół nich, powinno być OK. Inni członkowie zespołu są przekonani, że wszystko musi pozostać w tej samej monolitycznej bazie danych, aby wszystko mogło być ACID i mieć wszędzie zachowaną integralność referencyjną.
To prowadzi mnie do mojego pytania. Po pierwsze, czy moje stanowisko w sprawie ograniczeń klucza obcego i przyłączenia się jest prawdopodobne? Jeśli tak, to czy ktoś wie o jakichkolwiek wiarygodnych materiałach do czytania, które mógłbym zaoferować moim kolegom? Ich pozycja jest niemal religijna i nie wydaje się, aby zachwiało ich cokolwiek innego niż sam Martin Fowler, który powiedziałby im, że się mylą.
źródło
Odpowiedzi:
Nie ma jednoznacznego rozwiązania, ponieważ zależy to całkowicie od kontekstu - w szczególności, od których wymiarów system ma się skalować i jakie są twoje rzeczywiste problemy. Czy baza danych jest naprawdę twoim wąskim gardłem?
Ta (niestety dość długa) odpowiedź brzmi trochę jak „mikrousług są złe, monolity na całe życie!”, Ale to nie jest moja intencja. Chodzi mi o to, że mikrousługi i rozproszone bazy danych mogą rozwiązać różne problemy, ale nie bez własnych problemów. Aby uzasadnić swoją architekturę, musisz pokazać, że te problemy nie mają zastosowania, można je złagodzić i że architektura ta jest najlepszym wyborem dla potrzeb Twojej firmy.
Rozproszone dane są trudne.
Ta sama elastyczność, która umożliwia lepsze skalowanie, to druga strona słabszych gwarancji. Warto zauważyć, że systemy rozproszone są znacznie trudniejsze do uzasadnienia.
Aktualizacje atomowe, transakcje, spójność / integralność referencyjna i trwałość są niezwykle cenne i nie należy z nich rezygnować pochopnie. Nie ma sensu mieć danych, jeśli są niekompletne, nieaktualne lub całkowicie błędne. Jeśli masz ACID jako wymaganie biznesowe, ale korzystasz z technologii baz danych, która nie jest w stanie zaoferować go od razu (np. Wiele baz danych NoSQL lub architektura DB-per-microservice), Twoja aplikacja musi wypełnić lukę i zapewnić te gwarancje.
Nie jest to niemożliwe, ale trudne do zrobienia. Bardzo trudne. Zwłaszcza w ustawieniu rozproszonym, w którym do każdej bazy danych jest wielu autorów. Ta trudność przekłada się na dużą szansę na błędy, w tym prawdopodobnie upuszczone dane, niespójne dane i tak dalej.
Rozważ na przykład przeczytanie analiz Jepsen dobrze znanych rozproszonych systemów baz danych , być może zaczynając od analizy Cassandry . Nie rozumiem połowy tej analizy, ale TL; DR jest taki, że systemy rozproszone są tak trudne, że nawet wiodące w branży projekty czasami mylą się, w sposób, który może wydawać się oczywisty z perspektywy czasu.
Systemy rozproszone wymagają również większego wysiłku rozwojowego. Do pewnego stopnia istnieje bezpośredni kompromis między kosztami programowania lub spadaniem pieniędzy na mocniejszy sprzęt.
Przykład: wiszące odniesienia
W praktyce nie powinieneś patrzeć na informatykę, ale na wymagania biznesowe, aby sprawdzić, czy i jak można rozluźnić ACID. Np. Wiele relacji z kluczem obcym może nie być tak ważne, jak się wydaje. Rozważ związek produkt - kategoria n: m. W RDBMS możemy zastosować ograniczenie klucza obcego, aby tylko istniejące produkty i istniejące kategorie mogły być częścią tego związku. Co się stanie, jeśli wprowadzimy oddzielne usługi dotyczące produktów i kategorii, a produkt lub kategoria zostaną usunięte?
W takim przypadku może to nie stanowić większego problemu i możemy napisać naszą aplikację, aby odfiltrowała wszelkie produkty lub kategorie, które już nie istnieją. Ale są kompromisy!
Należy pamiętać, że może to wymagać poziomu aplikacji
JOIN
w wielu bazach danych / mikrousługach, co jedynie przenosi przetwarzanie z serwera bazy danych do aplikacji. Zwiększa to całkowite obciążenie i musi przenosić dodatkowe dane przez sieć.Może to zepsuć podział na strony. Np. Zamawiasz kolejne 25 produktów z kategorii i odfiltrowujesz niedostępne produkty z tej odpowiedzi. Teraz Twoja aplikacja wyświetla 23 produkty. Teoretycznie możliwa byłaby również strona z zerowymi produktami!
Od czasu do czasu będziesz chciał uruchomić skrypt, który czyści zwisające odwołania, po każdej odpowiedniej zmianie lub w regularnych odstępach czasu. Zauważ, że takie skrypty są dość drogie, ponieważ muszą żądać każdego produktu / kategorii z bazy danych / mikrousługi, aby sprawdzić, czy nadal istnieje.
Powinno to być oczywiste, ale dla jasności: nie używaj ponownie identyfikatorów. Identyfikatory w stylu autoinkrementacji mogą, ale nie muszą być w porządku. Identyfikatory GUID lub skróty zapewniają większą elastyczność, np. Dzięki możliwości przypisania identyfikatora przed wstawieniem elementu do bazy danych.
Przykład: współbieżne zamówienia
Zamiast tego rozważ stosunek produktu do zamówienia. Co stanie się z zamówieniem, jeśli produkt zostanie usunięty lub zmieniony? Ok, możemy po prostu skopiować odpowiednie dane produktu do pozycji zamówienia, aby były dostępne - aby uprościć wymianę miejsca na dysku. Ale co jeśli cena produktu ulegnie zmianie lub produkt stanie się niedostępny tuż przed złożeniem zamówienia na ten produkt? W systemie rozproszonym rozprzestrzenianie się efektów zajmuje trochę czasu, a kolejność prawdopodobnie przejdzie przez nieaktualne dane.
Ponownie, jak podejść do tego, zależy od wymagań biznesowych. Być może nieaktualne zamówienie jest akceptowalne i możesz później anulować zamówienie, jeśli nie może zostać zrealizowane.
Ale może nie jest to opcja, np. W przypadku wysoce współbieżnych ustawień. Weź pod uwagę 3000 osób, które spieszą się, aby kupić bilety na koncert w ciągu pierwszych 10 sekund, i załóżmy, że zmiana dostępności będzie wymagała 10 ms do rozpowszechnienia. Jakie jest prawdopodobieństwo sprzedania ostatniego biletu wielu osobom? Zależy jak te kolizje są obsługiwane, ale stosując rozkład Poissona z
λ = 3000 / (10s / 10ms) = 3
otrzymujemyP(k > 1) = 1 - P(k = 0) - P(k = 1) = 80%
szansę zderzenia na 10ms interwał. To, czy sprzedaż, a później anulowanie większości zamówień jest możliwe bez popełniania oszustwa, może prowadzić do interesującej rozmowy z działem prawnym.Pragmatyzm oznacza wybieranie najlepszych funkcji.
Dobrą wiadomością jest to, że nie musisz przechodzić na model rozproszonej bazy danych, jeśli nie jest to wymagane w inny sposób. Nikt nie cofnie członkostwa w Microservice Club, jeśli nie wykonasz mikrousług „odpowiednio”, ponieważ nie ma takiego klubu - i nie ma jednego prawdziwego sposobu na zbudowanie mikrousług.
Pragmatyzm wygrywa za każdym razem, więc mieszaj i dopasowuj różne podejścia, gdy rozwiążą twój problem. Może to nawet oznaczać mikrousługi ze scentralizowaną bazą danych. Naprawdę, nie przechodź przez ból rozproszonych baz danych, jeśli nie musisz.
Możesz skalować bez mikrousług.
Mikrousługi mają dwie główne zalety:
Jeśli niezależne skalowanie nie jest wymagane, mikrousługi są znacznie mniej atrakcyjne.
Serwer bazy danych jest już rodzajem usługi, którą można skalować (nieco) niezależnie, np. Dodając repliki odczytu. Wspominasz o procedurach przechowywanych. Zmniejszenie ich może mieć tak duży efekt, że wszelkie inne dyskusje na temat skalowalności są dyskusyjne.
I jest całkowicie możliwe posiadanie skalowalnego monolitu, który obejmuje wszystkie usługi jako biblioteki. Następnie można skalować, uruchamiając więcej instancji monolitu, co oczywiście wymaga, aby każda instancja była bezstanowa.
Zwykle działa to dobrze, dopóki monolit nie będzie zbyt duży, aby można go było rozsądnie wdrożyć, lub jeśli niektóre usługi mają specjalne wymagania dotyczące zasobów, aby można było skalować je niezależnie. Domeny problemowe wymagające dodatkowych zasobów mogą nie obejmować osobnego modelu danych.
Czy masz mocne uzasadnienie biznesowe?
Zdajesz sobie sprawę z potrzeb biznesowych Twojej organizacji i dlatego możesz stworzyć argument oparty na architekturze bazy danych dla mikrousług na podstawie analizy:
I odwrotnie, jeśli nie jesteś w stanie tego wykazać, w szczególności jeśli obecny projekt bazy danych jest w stanie obsłużyć wystarczającą skalę w przyszłości (jak sądzą koledzy), to również masz odpowiedź.
Istnieje również duży składnik YAGNI do skalowalności. W obliczu niepewności jest to strategiczna decyzja biznesowa dotycząca budowania skalowalności (niższe całkowite koszty, ale wiążą się z kosztami alternatywnymi i mogą nie być potrzebne) w porównaniu z odroczeniem prac nad skalowalnością (w razie potrzeby wyższe całkowite koszty, ale masz lepsze idea rzeczywistej skali). Nie jest to przede wszystkim decyzja techniczna.
źródło
Uważam, że oba podejścia są prawdopodobne. Możesz zyskać skalowalność poświęcając zalety ACID i monolitycznych baz danych, a także zachować aktualną architekturę i poświęcić skalowalność i zwinność bardziej rozproszonej architektury. Właściwa decyzja będzie wynikać z obecnego modelu biznesowego i strategii buz na kolejne lata. Z czysto technologicznego punktu widzenia istnieją bóle, które utrzymują monolityczność, a także przechodzą na bardziej rozproszone podejście. Przeanalizuję system i zobaczę, które aplikacje / moduły / procesy biznesowe są bardziej krytyczne do skalowania i oceny ryzyka, kosztów i korzyści, aby zdecydować, które powinny poczekać lub kontynuować w architekturze monolitycznej.
źródło
Twoja postawa jest wiarygodna i poprawna.
Jak przekonać barwionych w wełnę nałogowców dbających, to kolejne pytanie. Powiedziałbym, że masz dwie opcje.
Znajdź konkretny przykład, w którym DB osiągnął swoje granice. Czy masz na przykład „tabele archiwizacji”? Dlaczego to jest w porządku? Jaką maksymalną liczbę zamówień na sekundę możesz przyjąć? itp. Pokaż, że baza danych nie spełnia wymagań, a Twoje rozwiązanie je rozwiązuje.
Zatrudnij drogich kontrahentów, którzy podpowie najlepsze rozwiązanie. Ponieważ są kosztowne i mają blogi, wszyscy im uwierzą
źródło