Mikrousługi i procedury przechowywane

34

Czy procedury składowane są uważane za złą praktykę w architekturze mikrousług?

Oto moje przemyślenia:

  • większość książek o mikrousługach zaleca jedną bazę danych na mikrousługę. Procedury przechowywane zwykle działają na monolitycznej bazie danych.

  • ponownie większość książek o architekturze mikrousługowej stwierdza, że ​​powinny być autonomiczne i luźno powiązane. Używając zapisanych procedur zapisanych, powiedzmy konkretnie w Oracle, ściśle łączy mikrousługę z tą technologią.

  • większość książek o architekturze mikrousług (które przeczytałem) zaleca, aby mikrousług były zorientowane biznesowo (zaprojektowane przy użyciu projektowania opartego na domenie (DDD)). Przeniesienie logiki biznesowej do procedur przechowywanych w bazie danych już tak nie jest.

Masz jakieś przemyślenia na ten temat?

Johnny Alpha
źródło
10
@ RandomUs1r przepraszam, to nie ma dla mnie sensu. Dlaczego struktura DB musi być nierelacyjna? Jasne, może mieć zewnętrzne odniesienia, ale jego wewnętrzna struktura może być w 100% relacyjna
IMil
12
Problem z twoimi punktami polega na tym, że wszystkie twoje przesłanki są błędne. Stwierdzenie, że mikrousługi powinny być autonomiczne i luźno powiązane, oznacza przede wszystkim, że powinny one być luźno ze sobą powiązane ; sposób zarządzania sprzężeniem komponentów wewnętrznych jest inną sprawą - i ma drugorzędne znaczenie (ale nie jest nieważne) - zwłaszcza jeśli można po prostu wymienić całą mikrousługę w aktualizacji. Więc nie ma powodu, dla którego nie można używać sproców w tych granicach. Ponadto DDD nie zabrania sproków ani mieszania paradygmatów; niektóre aspekty niektórych problemów nie są najlepiej dostosowane do OO.
Filip Milovanović
3
Jak monolityczna jest twoja baza danych w związku z projektowaniem i wdrażaniem danych, nie ma to nic wspólnego z korzystaniem z procedur przechowywanych lub z ich brakiem.
RBarryYoung
5
„Procedury przechowywane zwykle działają w bazie danych monolitów”. Powinieneś zdecydowanie odrzucić wszelkie informacje lub porady, które otrzymujesz z dowolnego źródła, które udostępniło ci ten „fakt”.
StingyJack
3
@ RandomUs1r Umm nie, jedyną rzeczą, którą naprawdę tracisz, jest to, że nie możesz używać ograniczeń klucza obcego dla kluczy referencyjnych - co jest raczej celem mikrousług. Po pierwsze, pomysł, że bazy danych NoSql są w jakiś sposób magicznie szybsze, był wielokrotnie obalany, ale nawet jeśli były one szybsze (nie są), dostajesz całą istniejącą infrastrukturę, wiedzę i istniejący kod za darmo - co jest ogromne . CERN i wiele innych zarządza terabajtami danych przy użyciu relacyjnych baz danych. Bazy danych NoSql mają swoje zastosowanie, ale są one niezależne od tego, czy korzystasz z mikrousług, czy nie.
Voo

Odpowiedzi:

45

Nie ma niczego, co wyraźnie zabrania lub przemawia przeciwko używaniu procedur przechowywanych z mikrousługami.

Oświadczenie: Nie lubię procedur przechowywanych z POV dewelopera, ale nie ma to żadnego związku z mikrousługami.

Procedury przechowywane zwykle działają na bazie danych monolitów.

Myślę, że ulegasz logicznemu błędowi.

Obecnie przechowywane procedury maleją. Większość procedur przechowywanych, które są nadal w użyciu, pochodzi ze starszej bazy kodu, która została zachowana. W tamtych czasach monolityczne bazy danych były również znacznie bardziej rozpowszechnione w porównaniu z popularnością mikrousług.

Przechowywane procy i monolityczne bazy danych występują zarówno w starych bazach kodów, dlatego częściej widujesz je razem. Ale to nie jest związek przyczynowy. Nie używasz przechowywanych proc, ponieważ masz monolityczną bazę danych. Nie masz monolitycznej bazy danych, ponieważ używasz przechowywanych proc.

większość książek o mikrousługach zaleca jedną bazę danych na mikrousługę.

Nie ma technicznego powodu, aby te mniejsze bazy danych nie mogły mieć procedur przechowywanych.

Jak wspomniałem, nie lubię przechowywanych proc. Uważam je za nieporęczne i odporne na przyszłe utrzymanie. Myślę, że rozprzestrzenianie sproców w wielu małych bazach danych dodatkowo pogarsza problemy, których już nie lubię. Ale to nie znaczy, że nie da się tego zrobić.

ponownie większość książek o architekturze mikrousługowej stwierdza, że ​​powinny być autonomiczne i luźno powiązane. Korzystając z zapisanych procedur zapisanych np. W Oracle, ściśle łączy mikrousługę z tą technologią.

Z drugiej strony, ten sam argument można wysunąć dla dowolnej ORM, której używa Twoja mikrousługa. Nie każda ORM będzie również obsługiwać każdą bazę danych. Sprzęganie (szczególnie jego szczelność) jest pojęciem względnym. To kwestia bycia tak swobodnie, jak to tylko możliwe.

Sprocs generalnie cierpią z powodu ciasnego połączenia, niezależnie od mikrousług. Odradzam generalnie sproki, ale nie szczególnie, ponieważ używasz mikrousług. To ten sam argument, co poprzednio: nie sądzę, że sproki są właściwą drogą (ogólnie), ale to może być tylko moja stronniczość i nie jest to związane z mikrousługami.

większość książek MSA (które przeczytałem) zaleca, aby mikrousługi były zorientowane na biznes (zaprojektowane przy użyciu DDD). Przeniesienie logiki biznesowej do procedur przechowywanych w bazie danych już tak nie jest.

To zawsze było moim głównym problemem wobec sprocs: logiki biznesowej w bazie danych. Nawet jeśli nie jest to intencją, zwykle kończy się w ten sposób.

Ale znowu ten problem istnieje niezależnie od tego, czy korzystasz z mikrousług, czy nie. Jedynym powodem, dla którego wygląda to na większy problem, jest to, że mikrousługi popychają cię do modernizacji całej architektury, a sproki nie są już tak uprzywilejowane we współczesnych architekturach.

Flater
źródło
4
Nie jestem pewien, czy słuszne jest twierdzenie, że mikrousługi zachęcają do modernizacji całej architektury. Najczęściej kończą się cienką warstwą na tle bałaganu źle zaplanowanego kodu. Mogą być całkiem dobre, jeśli są dobrze wykonane, ale tak naprawdę nie popychają cię w żaden sposób do lepszego kodowania niż jakakolwiek inna architektura. Dobra odpowiedź. Masz ode mnie +1.
T. Sar - Przywróć Monikę
11
@ T.Sar modern to nie to samo co lepsze. Refaktoryzacja (do mikrousług lub cokolwiek innego) oznacza zmianę. Zmiana zmusza cię do wykorzystania bieżących pomysłów. Mamy nadzieję, że to lepsze pomysły.
candied_orange
2
@ T.Sar: Hacki są ponadczasowe i zwykle możesz nadużywać dowolnego systemu (nowoczesnego lub nie), aby robić coś, z czego technicznie sobie poradzi, ale nigdy nie był przeznaczony. Mikrousługi zachęcają cię do zrobienia tego inaczej (a tym samym do ponownej oceny niektórych starych podejść), ale nie mogą tego powszechnie egzekwować . Dzięki uniwersalnemu egzekwowaniu prawa zwykle cierpisz w dziale zgodności / ważnej sprawy z marginesami.
Flater
4
@candied_orange „modern to nie to samo co lepsze” - myślę, że całym sercem się na to zgadzam. Bardzo dobra uwaga.
T. Sar - Przywróć Monikę
3
Współczesność nie jest nawet synonimem „odpowiedniego”.
Laiv
24

Pisanie oprogramowania wymaga ścisłego powiązania z technologią.

Przynajmniej do środowiska wykonawczego zapewnianego przez rozwijany język programowania.

Mówiąc bardziej ogólnie, przekonasz się, że twoja mikro-usługa jest ściśle powiązana z kilkoma technologiami:

  • Struktura usługi sieciowej w celu zapewnienia implementacji protokołu HTTP / SSL / SOAP na wysokim poziomie
  • Struktura repozytorium / ORM / DAO w celu zapewnienia trwałości.
  • Ramy manipulacji danymi w celu zapewnienia narzędzi do pracy z danymi.
  • Process / Threading / OS Framework, aby zapewnić dostęp do zasobów systemu operacyjnego, takich jak wielozadaniowość, system plików, pamięć, obliczenia GPU, karty rozszerzeń itp.

Ma to na celu stworzenie mikrousługi od podstaw.

Procedury składowane

Procedura przechowywana to po prostu kolejna technologia, z której możesz skorzystać lub nie skorzystać. W magiczny sposób kod nie jest monolityczny ani mikro.

Chodzi jednak o:

  • Kolejna technologia. Każda technologia obecna w aplikacji zmniejsza prawdopodobieństwo, że każdy programista może czytać, rozumieć i dokonywać mądrych wyborów projektowych dla tej kombinacji technologii.
  • Język wykorzystujący inny paradygmat programowania. Dla osób niebędących ekspertami zdecydowanie zbyt łatwo jest narzucić własną imperatywną, funkcjonalną, OO itd. Perspektywę, co często prowadzi do mniej niż gwiezdnych wyników.
  • API. Które muszą być utrzymywane jak każda inna klasa w bazie kodu. Oznacza to również, że baza danych zapewnia interfejs inny niż ogólny. Utrudnia to zarówno wymianę samego silnika bazy danych, jak i przejrzyste zastosowanie ogólnych zachowań, takich jak buforowanie pamięci.
  • Artefakt. Które muszą być wersjonowane, testowane i wdrażane. Można to zrobić, ale bazy danych to żywe artefakty wymagające innego podejścia. Zwykle nie można po prostu usunąć oryginału i zastąpić go. Często konieczna jest staranna organizacja zmian w czasie w celu migracji systemu do pożądanego stanu.

Każdy z nich to prawdziwy koszt. W niektórych przypadkach koszt jest uzasadniony, w innych nie.

Będziesz płacić prawie taki sam zestaw kosztów, hostując silnik skryptów. Jedyne ograniczenie polega na tym, że możesz wybrać ten sam paradygmat programowania, co język hosta.

Logika biznesowa

Przenoszenie reguł biznesowych do bazy danych to zła praktyka. Po prostu nie z powodu procedur przechowywanych.

Jest to zła praktyka, ponieważ baza danych i logika biznesowa działają na różnych poziomach ścinania.

  • Baza danych w dojrzałych aplikacjach może być używana przez dziesięciolecia. Zasadniczo w tych systemach silnik będzie okresowo aktualizowany, ale sama baza danych została poddana migracji. Nie został zabity i odbudowany od samego początku. Nie ma powodu, dla którego mikrousługa nie może być tak długo przeżywana.

  • Porównaj dekady z tym, jak szybko zmieniają się reguły biznesowe. Z mojego doświadczenia wynika, że ​​stara reguła biznesowa ma prawdopodobnie kilka lat, większość jednak szybko się zmienia i nigdy nie wiadomo, która z nich ulegnie zmianie. Nowy wymóg regulatora, wycofanie starego produktu, zmiany w nagłówku, zmiana liczby pracowników zgłaszających się do szefa itp. Itd. Itd.

Jeśli logika biznesowa zostanie rozłożona na warstwy ścinające, szczególnie na wolniejszą i dłużej żyjącą warstwę, spowoduje to opór przed zmianami. To niekoniecznie jest zła rzecz. W końcu jedyną bazą danych, która nie ma logiki biznesowej, jest potrójny sklep.

Samo określenie schematu tabeli przenosi logikę biznesową do bazy danych.

Architektura

Walczysz z użyciem odpowiedniego narzędzia dla odpowiedniego problemu, nie potrzebując zbyt wielu narzędzi ani nie utrudniając rozwiązania, aby stworzyć i utrzymać rozwiązanie.

To nie jest łatwe.

Ale pomyślmy nie do pomyślenia, w jaki sposób utrzymasz logikę biznesową w kilku językach?

  • Katalog ... umożliwiający śledzenie i utrzymanie każdej implementacji reguły biznesowej.
  • Testy ... które można wykorzystać w odniesieniu do każdej reguły biznesowej, niezależnie od tego, gdzie i jak została wdrożona.
  • Implementacja referencyjna .. tak, że gdy zostaną znalezione rozbieżności, istnieje źródło prawdy (lub przynajmniej źródło debaty).

Ale to też ma swój koszt.

  • Czy lepiej jest pozwolić regułom biznesowym na wiele implementacji? Czy każdy może skorzystać z umiejętności zespołu i przepisów ramowych, ale potrzebuje ścisłej kontroli jakości, aby odeprzeć wiele drobnych kaprysów?
  • A może lepiej mieć jedno źródło prawdy, napisane w jednym języku? Prawdopodobnie tańsze we wdrożeniu, ale także pojedyncze źródło awarii, sam w sobie element monolityczny, który jest odporny na zmiany w obliczu różnych platform, platform, czy jeszcze nie ma wynalezionych narzędzi?
Kain0_0
źródło
8

Przedmówię swoją odpowiedź, mówiąc, że faktycznie utrzymuję kilka mikrousług, które korzystają z procedur przechowywanych. Napisałem też wiele procedur przechowywanych w różnych momentach mojej kariery i zdecydowanie zgadzam się, że rzeczy mogą pójść bardzo, bardzo źle, jeśli zostaną użyte nieprawidłowo.

Krótka odpowiedź brzmi: nie, procedury przechowywane nie są z natury złe w architekturze mikrousług. Ale musisz zrozumieć:

  1. Dodajesz przeszkody do zastąpienia silników pamięci masowej. Jeśli niektóre parametry operacyjne lub wydajnościowe lub ograniczenia funkcji wymagają zmiany silników pamięci masowej, koszt będzie większy, ponieważ będziesz pisać i testować dużo nowego kodu. Uruchamianie więcej niż jednego silnika pamięci masowej (podczas fazy migracji lub w celu wyodrębnienia działań opartych na potrzebach dotyczących wydajności) może powodować problemy ze spójnością, chyba że użyjesz zatwierdzania dwufazowego (2 PC), który sam ma problemy z wydajnością.
  2. Musisz utrzymywać inny interfejs API, co oznacza, że ​​twoje zależności mogą się zepsuć. Dodanie, usunięcie lub zmiana typów parametrów procedur może uszkodzić istniejący kod. To samo dzieje się z tabelami i zapytaniami, ale twoje narzędzia mogą być mniej pomocne w śledzeniu, gdzie coś może pójść nie tak. Problemy z procedurami przechowywanymi zwykle występują w czasie wykonywania, bardzo późno w procesie opracowywania / wdrażania.
  3. Twoje uprawnienia do bazy danych stały się bardziej skomplikowane. Czy procedura działa jako zalogowany użytkownik lub jakaś inna rola? Musisz o tym pomyśleć i sobie z tym poradzić (mam nadzieję, że w sposób zautomatyzowany).
  4. Musisz mieć możliwość bezpiecznej migracji do nowych wersji. Często procedura musi zostać porzucona i ponownie utworzona. Po raz kolejny uprawnienia mogą powodować pewne problemy.
  5. Cofnięcie nieudanej migracji może oznaczać dodatkowy wysiłek. Gdy środowisko produkcyjne jest oddzielone od programistów, sprawy stają się jeszcze trudniejsze.

Oto niektóre zastosowania procedur przechowywanych, które moim zdaniem są często warte zachodu:

  1. Egzekwowanie historii edycji (dzienniki kontroli). Do tego celu powszechnie stosuje się wyzwalacze, a wyzwalacze to procedury składowane. W niektórych bazach danych można również całkowicie zabronić wstawiania i aktualizacji dla roli aplikacji: klienci wykonują procedury uruchamiane jako inna rola z odpowiednimi uprawnieniami i egzekwują wszystkie niezbędne zachowania.
  2. Rozszerzenie ograniczeń kontrolnych. Może to doprowadzić Cię do obszaru logiki biznesowej, ale zdarzają się przypadki, w których wbudowane narzędzia ograniczające bazy danych mogą nie być wystarczające dla potrzeb. Często najlepszym sposobem na ekspresowe sprawdzenie czeków jest użycie kodu imperatywnego i ryzykujesz wpuszczeniem złych danych, jeśli zależy to od aplikacji, która zrobi to za Ciebie.
  3. Hermetyzacja złożonych zapytań, gdy widok jest nieodpowiedni lub zbyt skomplikowany. Widziałem kilka przypadków, w których poprawny widok wymaga bardzo złożonego SQL, który można wyrazić o wiele bardziej zrozumiale w procedurze przechowywanej. Jest to prawdopodobnie rzadkie, ale zdarza się.

Ogólnie sugeruję, aby najpierw wypróbować widoki i zastosować procedury tylko w razie potrzeby. Dobrze zaprojektowane widoki mogą faktycznie działać jako interfejs API, wyodrębniając szczegóły dotyczące odpytywania tabel bazowych. Rozszerzanie interfejsu API (widoków) o procedury składowane ma w niektórych okolicznościach sens. Możliwe jest nawet wysyłanie JSON bezpośrednio z zapytania SQL, omijając cały bałagan związany z mapowaniem danych z wyników zapytania do modelu danych aplikacji. To, czy jest to dobry pomysł, należy ustalić na podstawie własnych potrzeb.

Ponieważ powinieneś już zarządzać zasobami bazy danych (schematem, uprawnieniami itp.) Za pomocą zautomatyzowanego narzędzia, nie, procedury przechowywane nie są z natury szkodliwe dla mikrousług.

ngreen
źródło
Myślę, że wszystkie twoje pierwsze punkty mają również zastosowanie, jeśli napiszesz logikę biznesową np. W Javie. Zmiana DB-Engine zmieni charakterystykę wydajności i będzie wymagać ponownego testowania i być może przepisywania instrukcji. Jeśli piszesz instrukcje SQL, np. Jako ciągi w swojej aplikacji, masz ten sam problem ze zmienianiem zmiennych, które psują rzeczy. Musisz zdecydować, czy aplikacja używa użytkownika technicznego, czy indywidualnych użytkowników do łączenia się z bazą danych i tak dalej ...
Falco,
@Falco Myślę, że jeśli używasz wyłącznie JPA, zmiana bazy danych nie powinna być zbyt trudna. Wydajność może zdecydowanie różnić się znacznie i zawsze musi zostać przetestowana. Kilka usług, które utrzymuję, nie są „mikro” w tym sensie, że mogą skanować lub agregować miliony lub miliardy punktów danych i zwracać dowolnie duże (często paginowane) zestawy danych. Nie wyobrażam sobie używania JPA dla nich, ale wyobrażam sobie zmianę bazowych mechanizmów bazy danych (i przepisanie SQL) przy zachowaniu tego samego API.
ngreen
4

Procedury przechowywane są szczegółami implementacji. Funkcje bazy danych, lambdas lub skrypt powłoki przechowywane gdzieś w systemie plików są szczegółami implementacyjnymi i nie mają znaczenia dla architektury.

większość książek o mikrousługach zaleca jedną bazę danych na mikrousługę.

Ok, więc możemy zakodować procedury przechowywane w tych bazach danych.

ponownie większość książek o architekturze mikrousługowej stwierdza, że ​​powinny być autonomiczne i luźno powiązane

Pomiędzy możliwościami biznesowymi, cyklami rozwojowymi, zarządzaniem, wdrożeniami, lokalizacjami zespołu itp. Nie ma nic wspólnego ze szczegółami wdrożenia. Mikrousługi nie rozwiązują problemu technicznego (wręcz przeciwnie). Przychodzą, aby rozwiązać problemy z zarządzaniem i czasem na rynku. To strategia, a nie taktyka. Sposób na szybki i możliwie najmniejszy koszt. Jeśli okaże się, że pewne możliwości biznesowe są bezwartościowe, porzucamy je, nie psując innych możliwości, wdrożeń, zarządzania projektami, wydań ...

Zauważ, że „podział” już działa jak agent odsprzęgający. Załóżmy, że mamy dwie usługi: A jest wspierane przez Oracle, a B przez MongoDB. Jeśli nie złamiemy złotej zasady oddzielania, powinno być możliwe upuszczenie Wyroczni A + z nieznacznymi skutkami ubocznymi na B.

Korzystając z zapisanych procedur zapisanych np. W Oracle, ściśle łączy mikrousługę z tą technologią.

Może to spowodować blokadę dostawcy. Wiele razy sprzedawca jest narzucany przez firmę z przyczyn historycznych lub umownych 1 . Ważne jest, aby wiedzieć, jak nie blokować naszego kodu dostawcy. Na przykład niektóre ORM i frameworki implementują nowy język zapytań, który ukrywa wbudowane funkcje i funkcje bazy danych.

Chociaż, jeśli nasze usługi są wystarczająco małe, zablokowanie dostawcy nie stanowi już problemu, ponieważ wpływa na niewielką część całości. Mała część, która powinna być możliwa do szybkiej wymiany (lub izolacji).

większość książek MSA (które przeczytałem) zaleca, aby mikrousług były zorientowane biznesowo (zaprojektowane przy użyciu DDD).

To powinno być nastawione na biznes i tutaj. Nie wszystkie firmy korzystają z DDD. DDD i mikrousług nakładają się w wielu punktach, ale nie są przyczyną. Moglibyśmy skończyć z ekosystemem mikrousług złożonym z usług anemicznych. Lub składa się z połączenia obu: usług implementujących złożoną domenę i głupich anemicznych usług zapewniających POJO bezpośrednio z DB. Nie ma w tym nic złego.

Jeśli chodzi o książki, koncentrują się one tylko na realizacji strategii. Taktyka - jak wykorzystać przetwarzanie rozproszone - jak sprawić, by działał do sukcesu, ale (zwykle) jest niezależny od strategii. Strategie różnią się w zależności od firmy i rzadko zależą od programistów. Dlatego nadal musimy ekstrapolować i dostosować to, co mówią książki, do naszych konkretnych potrzeb, wymagań i ograniczeń. Celem jest, aby strategia biznesowa była opłacalna i zrównoważona.

Zawsze należy pamiętać, że każda architektura jest środkiem do celu. Zasady biznesowe. Nie budujemy ekosystemów mikrousług dla mody lub miłości do sztuki.

Laiv
źródło
1

Tak naprawdę nie ma to nic wspólnego z mikrousługami.

Procedury składowane mogą mieć sens, jeśli twoja usługa ma „warstwową” architekturę w „starym stylu”, w której DB stanowi podstawę usługi, z warstwami dostępu do danych i logiki biznesowej. Interfejs między usługą a bazą danych w takiej architekturze jest bardzo specyficzny dla najbardziej wewnętrznych szczegółów usługi. Zazwyczaj będą istnieć adaptery specyficzne dla usługi dla każdego rodzaju obsługiwanej bazy danych, a specyfika interfejsu API ujawniona przez adapter umożliwia stosowanie procedur przechowywanych w podstawowych warstwach.

Istnieje wiele problemów z takimi architekturami. Co najważniejsze, utrudnia to przetestowanie większości logiki. Te architektury nie są już przychylne.

Jeśli używasz „czystej architektury”, „architektury cebulowej” lub podobnej w nowszym stylu, baza danych będzie wstrzykiwaną zależnością , określoną na zewnętrznych warstwach. Ponieważ jest zdefiniowany w warstwach zewnętrznych, interfejs przewidziany dla bazy danych musi być ogólny . Nie może odzwierciedlać najgłębszych szczegółów usługi, ponieważ dane te muszą być ukryte przed najbardziej zewnętrznymi warstwami architektury. Zdefiniowanie ogólnego interfejsu procedury przechowywanej, który może współpracować z dowolną wiązką testową bazy danych lub jednostki, jest niezwykle trudne i nie jest tak naprawdę konieczne, dlatego procedury przechowywane często nie są praktyczne w tego rodzaju architekturach.

Związek z mikrousługami polega na tym, że mikrousługi są nowe i wznoszące się - już nie robimy monolitów - i że te nowe style architektoniczne są również wznoszące się - nie wykonujemy już płaskich warstw.

Matt Timmermans
źródło