Ostrzeżenie: duży post, kilka opinii, niejasne stwierdzenie „zrób to, co dla ciebie najlepsze”
Zasadniczo odbywa się to jako sposób implementacji „architektury heksagonalnej” wokół bazy danych. Możesz mieć aplikacje internetowe, aplikacje mobilne, aplikacje komputerowe, importery zbiorcze i przetwarzanie w tle, które zużywają bazę danych w jednolity sposób. Z pewnością można to osiągnąć w pewnym stopniu, pisząc bogatą bibliotekę do uzyskiwania dostępu do bazy danych i umożliwiając wszystkim procesom korzystanie z tej biblioteki. I rzeczywiście, jeśli jesteś w małym sklepie z bardzo prostym systemem, jest to prawdopodobnie lepsza droga; To prostsze podejście i jeśli nie potrzebujesz zaawansowanych możliwości bardziej skomplikowanego systemu, po co płacić za złożoność? Jeśli jednak pracujesz z dużym, wyrafinowanym zestawem systemów, z których wszystkie muszą współdziałać z bazą danych na dużą skalę, istnieje „
Niezależność i utrzymanie platformy
Jeśli masz bazę danych i piszesz bibliotekę Python do interakcji z tą bazą danych, a wszyscy wciąga tę bibliotekę do interakcji z bazą danych, to świetnie. Ale powiedzmy nagle, że musisz napisać aplikację mobilną, a ta aplikacja mobilna musi teraz również rozmawiać z bazą danych. I twoi inżynierowie iOS nie używają Pythona, a twoi inżynierowie Androida nie używają Pythona. Może faceci z iOS chcą używać języków Apple, a inżynierowie Androida chcą używać Java. Wtedy utkniesz w pisaniu i utrzymywaniu biblioteki dostępu do danych w 3 różnych językach. Być może twórcy iOS i Androida zdecydują się użyć czegoś takiego jak Xamarin, aby zmaksymalizować kod, który mogą udostępniać. Idealnie, ale prawdopodobnie nadal będziesz musiał przenieść bibliotekę dostępu do danych do .NET. A potem twoja firma właśnie kupiła inną firmę, która „ Aplikacja internetowa to odmienny, ale powiązany produkt, a firma chce zintegrować niektóre dane z platformy firmy z nowo nabytą platformą spółki zależnej. Jest tylko jeden problem: spółka zależna była start-upem i zdecydowała się napisać większość swoich aplikacji w Dart. Dodatkowo, z jakichkolwiek powodów (prawdopodobnie niezależnych od ciebie) zespół mobilny, który pilotował Xamarin, zdecydował, że to nie dla nich, i że wolą używać narzędzi i języków specyficznych dla urządzeń mobilnych, dla których będą opracowywać. Ale kiedy byłeś w tej fazie, twój zespół dostarczył już dużą część twojej biblioteki dostępu do danych w .NET, a inny zespół w firmie pisał jakieś zwariowane rzeczy związane z integracją Salesforce i postanowił zrobić to wszystko w .NET była już biblioteką dostępu do danych dla.
Tak więc teraz, ze względu na bardzo realistyczny obrót wydarzeń, masz bibliotekę dostępu do danych napisaną w Python, .NET, Swift, Java i Dart. Nie są też tak mili, jak byś chciał. Nie można używać ORM tak skutecznie, jak chcesz, ponieważ każdy język ma inne narzędzia ORM, więc musiałeś napisać więcej kodu, niż byś chciał. I nie byłeś w stanie poświęcić tyle czasu na każdą inkarnację, jakiej byś chciał, ponieważ jest ich 5. A wersja biblioteki Dart jest wyjątkowo owłosiona, ponieważ trzeba było stworzyć własne transakcje, ponieważ bibliotek i wsparcia po prostu tak naprawdę nie było. Próbujesz uzasadnić, że z tego powodu aplikacja Dart powinna mieć tylko bazę danych do odczytu, ale firma już zdecydowała, że wszelkie funkcje, które planują, są warte dodatkowego wysiłku. I okazuje się, że istnieje błąd w logice sprawdzania poprawności, który istnieje we wszystkich tych wcieleniach biblioteki dostępu do danych. Teraz musisz napisać testy i kod, aby naprawić ten błąd we wszystkich tych bibliotekach, uzyskać recenzje kodu dotyczące zmian we wszystkich tych bibliotekach, uzyskać kontrolę jakości we wszystkich tych bibliotekach i opublikować zmiany we wszystkich systemach za pomocą wszystkich te biblioteki. W międzyczasie Twoi klienci są niezadowoleni i przeniosą się na Twitter, łącząc wulgaryzmy, których nigdy byś sobie nie wyobrażał. A właściciel produktu decyduje się wcale nie rozumieć sytuacji.
Proszę zrozumieć, że w niektórych środowiskach powyższy przykład nie jest wymyślony. Weź również pod uwagę, że ta sekwencja wydarzeń może się rozwijać w ciągu kilku lat. Ogólnie rzecz biorąc, kiedy dochodzisz do punktu, w którym architekci i ludzie biznesu zaczynają mówić o podłączeniu innych systemów do bazy danych, wtedy chcesz zamienić „umieszczenie interfejsu API REST przed bazą danych” na swoją mapę drogową. Zastanów się, czy na początku, kiedy stało się jasne, że ta baza danych zacznie być współużytkowana przez kilka systemów, przed nią została umieszczona usługa sieci Web / interfejs API REST. Naprawienie błędu sprawdzania poprawności byłoby znacznie szybsze i łatwiejsze, ponieważ robisz to raz zamiast 5 razy. Wydanie poprawki byłoby znacznie łatwiejsze do koordynowania, ponieważ „
TLDR; Łatwiej jest scentralizować logikę dostępu do danych i utrzymywać bardzo cienkich klientów HTTP niż dystrybuować logikę dostępu do danych do każdej aplikacji, która musi uzyskać dostęp do danych. W rzeczywistości Twój klient HTTP może nawet zostać wygenerowany z metadanych. W dużych systemach interfejs API REST pozwala zachować mniej kodu
Wydajność i skalowalność
Niektóre osoby mogą sądzić, że rozmowa z bazą danych zamiast przejścia przez usługę internetową jest szybsza. Jeśli masz tylko jedną aplikację, to z pewnością prawda. Ale w większych systemach nie zgadzam się z sentymentem. Ostatecznie, na pewnym poziomie skali, bardzo korzystne będzie umieszczenie pewnego rodzaju pamięci podręcznej przed bazą danych. Być może używasz Hibernacji i chcesz zainstalować siatkę Infinispan jako pamięć podręczną L2. Jeśli masz klaster 4 rozbudowanych serwerów do obsługi Twojej usługi sieciowej niezależnie od aplikacji, możesz sobie pozwolić na wbudowaną topologię z włączoną replikacją synchroniczną. Jeśli spróbujesz umieścić to w klastrze 30 serwerów aplikacji, narzut związany z włączeniem replikacji w tej konfiguracji będzie zbyt duży, więc „ Będę musiał uruchomić Infinispan w trybie rozproszonym lub w jakiejś specjalnej topologii i nagle Hibernacja musi wyjść z sieci, aby odczytać z pamięci podręcznej. Ponadto Infinispan działa tylko w Javie. Jeśli masz inne języki, będziesz potrzebować innych rozwiązań buforowania. Narzut związany z koniecznością przejścia z aplikacji do usługi internetowej przed dotarciem do bazy danych jest szybko równoważony przez potrzebę korzystania ze znacznie bardziej skomplikowanych rozwiązań buforowania, które generalnie mają własny narzut.
Ponadto ta warstwa HTTP interfejsu API REST zapewnia kolejny cenny mechanizm buforowania. Twoje serwery interfejsu API REST mogą umieszczać nagłówki buforowania w swoich odpowiedziach, a odpowiedzi te mogą być buforowane w warstwie sieci, która skaluje się wyjątkowo dobrze. W małej konfiguracji, z jednym lub dwoma serwerami, najlepszym rozwiązaniem jest po prostu użycie pamięci podręcznej w aplikacji podczas rozmowy z bazą danych, ale na dużej platformie z wieloma aplikacjami działającymi na wielu serwerach chcesz wykorzystać sieć do obsługi twojego buforowania, ponieważ przy odpowiednio skonfigurowanym czymś takim jak kałamarnica, lakier lub nginx można skalować do niesamowitych poziomów na stosunkowo małym sprzęcie. Setki tysięcy lub milionów żądań na sekundę jest o wiele tańsze w przypadku bufora HTTP niż serwera aplikacji lub bazy danych.
Co więcej, posiadanie mnóstwa klientów wskazujących na bazę danych, zamiast skierowania ich wszystkich na kilka serwerów, które z kolei wskazują na bazę danych, może znacznie utrudnić dostrojenie bazy danych i połączeń. Ogólnie rzecz biorąc, większość faktycznego obciążenia na serwerze aplikacji to aplikacje; oczekiwanie na powrót danych z bazy danych jest często czasochłonne, ale generalnie niezbyt drogie obliczeniowo. Być może potrzebujesz 40 serwerów do obsługi obciążenia aplikacji, ale prawdopodobnie nie potrzebujesz 40 serwerów do organizowania pobierania danych z bazy danych. Jeśli poświęcisz to zadanie usłudze sieciowej, prawdopodobnie będzie ona działać na znacznie mniejszej liczbie serwerów niż reszta aplikacji, co oznacza, że będziesz potrzebował znacznie mniej połączeń z bazą danych. Co jest ważne, ponieważ bazy danych na ogół nie
TLDR; Łatwiej jest dostroić, skalować i buforować dostęp do danych, gdy dzieje się to w obrębie jednej dedykowanej usługi internetowej, niż gdy dzieje się tak w wielu różnych aplikacjach korzystających z różnych języków i technologii
Końcowe przemyślenia
Proszę, nie odchodź od myślenia: „Och, zawsze powinienem używać interfejsów API REST, aby uzyskać moje dane” lub „Ten idiota próbuje powiedzieć, że robimy to źle, ponieważ nasza aplikacja internetowa komunikuje się bezpośrednio z bazą danych, ale nasze rzeczy działają dobrze! ” . Najważniejsze jest to, że różne systemy i różne firmy mają różne wymagania; W wielu przypadkach umieszczenie interfejsu API REST przed bazą danych naprawdę nie ma sensu. Jest to bardziej skomplikowana architektura, która wymaga uzasadnienia tej złożoności. Ale gdy złożoność jest uzasadniona, istnieje wiele korzyści z posiadania interfejsu API REST. Umiejętność rozważenia różnych problemów i wybrania odpowiedniego podejścia do systemu jest tym, co czyni dobrego inżyniera.
Ponadto, jeśli interfejs API REST przeszkadza w debugowaniu, prawdopodobnie na tym obrazie brakuje czegoś lub jest on nieprawidłowy. Nie sądzę, że dodanie tej warstwy abstrakcji samo w sobie utrudnia debugowanie. Kiedy pracuję z dużymi, n-poziomowymi systemami, lubię mieć pewność, że mam rozproszony kontekst rejestrowania. Być może, gdy użytkownik zainicjuje żądanie, wygeneruj identyfikator GUID dla tego żądania i zaloguj nazwę użytkownika tego użytkownika oraz zgłoszone przez niego żądanie. Następnie przekaż ten identyfikator GUID, gdy aplikacja komunikuje się z innymi systemami. Dzięki odpowiedniej agregacji i indeksowaniu dzienników możesz zapytać całą platformę o użytkownika zgłaszającego problem, mieć wgląd we wszystkie swoje działania, a oni przeciekają przez system, aby szybko zidentyfikować, co się stało. Znowu jest to bardziej skomplikowana architektura,
Źródła:
http://alistair.cockburn.us/Hexagonal+architecture
https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing