Nowoczesny stos transakcyjny

Nowoczesny stos transakcyjny

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Transakcyjne bazy danych od dawna są najważniejszym elementem projektowania aplikacji. Dlaczego? Ponieważ niezawodna baza danych jest generalnie ostatecznym punktem egzekwowania poprawności w chaotycznym, rozproszonym świecie. Bez nich przepłacalibyśmy i zaniżali opłaty. Stracilibyśmy pasażerów próbujących wrócić do domu z lotniska i stracilibyśmy przedmioty w naszych koszykach. Nasze konta internetowe zostałyby utracone, zduplikowane lub uszkodzone i przestałyby działać. 

W rzeczywistości transakcyjna baza danych (nazywana ogólnie OLTP — skrót od przetwarzania transakcji online — baza danych) była tak ważna dla rozwoju aplikacji, że z biegiem czasu konsumowała coraz więcej funkcji aplikacji. Jednak mikrousługi i inne nowoczesne architektury aplikacji wprowadziły nowe komplikacje do projektowania aplikacji: programiści musieli zarządzać danymi w różnych usługach i zapewnić spójność między nimi, co zmusiło ich do samodzielnego zbudowania złożonych mechanizmów synchronizacji i przetwarzania danych. 

I tak, jako branża, obserwujemy rosnącą świadomość, że poza tradycyjnym modelem potrzebne są gwarancje transakcyjne. Widzimy się pojawienie się systemów, które rozszerzają silne gwarancje transakcyjne poza bazę danych, na same rozproszone aplikacje

Śledziliśmy te rozwiązania przez ostatnie kilka lat. Generalnie dążą do umożliwienia transakcyjnego zarządzania stanem w dużej rozproszonej aplikacji, bez tworzenia wyzwań związanych ze skalowaniem i przy jednoczesnym zapewnieniu nowoczesnego środowiska programistycznego. 

Uważamy, że te rozwiązania można z grubsza podzielić na dwie kategorie. Jedna kategoria to orkiestracja przepływu pracy. Zasadniczo gwarantuje to, że blok kodu zostanie wykonany do końca, nawet w przypadku awarii. Można go więc używać do deterministycznego zarządzania rozproszoną maszyną stanów bez popadania w zakłopotanie. Druga kategoria to baza danych + przepływ pracy, który rozszerza tradycyjny projekt bazy danych OLTP, umożliwiając wykonanie dowolnego kodu w tym samym celu. 

Jest to wciąż bardzo rozwijająca się dziedzina i istnieje wiele nieporozumień związanych z nomenklaturą, tym, jak każde narzędzie jest używane w praktyce i kto powinien z nich korzystać. Aby pomóc w lepszym zrozumieniu, zapytaliśmy praktyków z wiodących organizacji inżynierskich o ich stos transakcyjny i sposób, w jaki myślą o trzech kluczowych koncepcjach obciążeń transakcyjnych: stanie aplikacji, logice biznesowej i danych biznesowych. 

Zanim jednak przyjrzymy się tym nowym stosom, oto krótka, półtechniczna dygresja, która pomoże zrozumieć, jak do tego doszliśmy.

Transakcje, gwarancje i nowoczesne aplikacje 

Bardzo przybliżona wersja jest taka: istnieje zestaw zadań — transakcji — które albo chcesz wykonać wszystkie, albo żadnego. Wszystko pomiędzy (częściowe wykonanie) zakończy się zepsuciem. Trudno to zagwarantować wszystko w systemie rozproszonym, ale bazy danych radzą sobie dobrze z transakcjami. Dlatego najłatwiejszym sposobem obsługi gwarancji w wielu systemach jest po prostu dokonanie większości transakcji i pozwolenie bazie danych na ich obsłużenie.

Nowoczesne aplikacje to duże systemy rozproszone, w których wielu użytkowników robi wiele rzeczy. Tak więc nawet utrzymywanie spójności stanu aplikacji (np. śledzenie, gdzie różni użytkownicy znajdują się w przepływie płatności) zamienia się w problem z transakcjami rozproszonymi. W tradycyjnych architekturach monolitycznych zarządzanie transakcjami przy użyciu języka SQL z bazą danych OLTP było dość skuteczne. Jednak w nowym, złożonym świecie mikroserwisów wchodzących w interakcje poprzez interfejsy API wyższego poziomu (np. REST lub gRPC) potrzeby transakcyjne mają charakter rozproszony. 

Jednak wiele firm przechodzących na mikroserwisy nie zrobiło wiele, aby rozszerzyć silne gwarancje transakcyjne poza bazę danych. A w praktyce to prawie zawsze OK. Jednak wraz ze wzrostem skali aplikacji rosną niespójności w danych, podobnie jak wynikające z nich błędy i nieuzgodnione błędy w danych biznesowych. Co oczywiście może być bardzo problematyczne. Zmusza to programistów aplikacji do radzenia sobie z szeroką gamą scenariuszy awarii i strategii rozwiązywania konfliktów oraz do zapewnienia spójności stanu poprzez wymyślanie własnych strategii za pomocą różnych wzorców architektonicznych.

Definicje

Dane biznesowe („dane”) odnosi się do danych o znaczeniu biznesowym, tradycyjnie przechowywanych w bazie danych OLTP w celu ich trwałości i przetwarzania (np. informacje o profilu użytkownika, takie jak imię i nazwisko, adres, ocena kredytowa itp.).

Stan aplikacji odnosi się do aktualnego stanu systemu; stan aplikacji jest określony przez wartość przechowywaną w systemie przechowywania danych oraz krok, na którym program jest wykonywany w skończonej maszynie stanów (np. ”, „wysłane”, „zwrócone”).

Logika biznesowa odnosi się do części programu, która zajmuje się tym, jak aplikacja faktycznie działa lub co robi, zamiast szczegółów wykonania (np. „Jeśli dochód_użytkownika > 100 650 USD i punktacja_kredytowa > XNUMX ⇒ zatwierdzona_hipoteka = PRAWDA”).

Na potrzeby tej dyskusji ważne jest rozróżnienie stanu aplikacji i danych biznesowych. Na przykład wiedza, że ​​klient wprowadził swoją kartę kredytową, ale jej nie wyewidencjonowała, to stan aplikacji. Dane karty kredytowej oraz pozycje w koszyku aplikacji są danymi biznesowymi. 

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

W typowym przepływie żądanie pochodzi z front-endu, jest uwierzytelniane, a następnie kierowane przez bramę API lub GraphQL do odpowiedniego punktu końcowego. 

Ten pojedynczy punkt końcowy interfejsu API musi teraz koordynować dziesiątki lub setki mikrousług w celu dostarczenia transakcji biznesowej do klienta końcowego. W tym przypadku programiści zazwyczaj umieszczają wszystko w blobach logiki biznesowej, a następnie używają kombinacji kolejek, pamięci podręcznych i ręcznie kodowanych mechanizmów ponawiania prób, aby pobrać dane do bazy danych — miejmy nadzieję, że zostaną one zatwierdzone jako pełna transakcja.

Wraz ze wzrostem skali aplikacji rośnie również złożoność zarządzania kolejkami i pamięciami podręcznymi, a także liczba ostrych krawędzi w logice uzgadniania, gdy pojawiają się problemy. 

Powstanie stosów transakcyjnych zorientowanych na przepływ pracy i baz danych

OK, więc transakcje są ważne. LAMP w bazie danych nie była wystarczająca do skali. A gigantyczna kula włosów kolejek i logiki ponawiania prób jest zbyt krucha. Aby sobie z tym poradzić, w ciągu ostatnich kilku lat zaobserwowaliśmy pojawienie się nowych rozwiązań, które przywracają zdrowy rozsądek logice transakcyjnej. Można je z grubsza podzielić na podejścia zorientowane na przepływ pracy lub podejścia skoncentrowane na bazie danych.

Do tej pory silniki przepływu pracy działają głównie na stanie aplikacji, a nie na danych biznesowych, i często wymagają pewnej złożoności podczas integracji z tradycyjnymi bazami danych. Podejścia zorientowane na bazę danych dodają logikę aplikacji do danych biznesowych, ale nie zapewniają jeszcze takiego samego wyrafinowania w wykonywaniu kodu, jak silniki przepływu pracy. 

Poniższy diagram przedstawia zgrubny szkic tego, w jaki sposób podejście skoncentrowane na przepływie pracy i/lub bazie danych jest używane w aplikacji Javascript/Typescript, zakładając, że oba są używane. Chociaż obecnie są to odrębne elementy tej architektury, zauważyliśmy wczesne oznaki trendu, w którym bazy danych zawierają funkcje przepływu pracy, a przepływy pracy zaczynają przyjmować trwałą pamięć masową. To połączenie możliwości wskazuje, że granice między tymi dwoma podejściami zacierają się i stają się mniej wyraźne w nowoczesnych architekturach. 

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Podejścia skoncentrowane na przepływie pracy w szczegółach 

Przepływ pracy to po prostu bloki kodu, które są wykonywane na podstawie zdarzeń lub liczników czasu, które ewoluują maszynę stanu aplikacji. Transakcyjny przepływ pracy zapewnia wykonanie kodu z silnymi gwarancjami, zapobiegając częściowym lub niezamierzonym stanom w aplikacji. Programiści piszą logikę, a mechanizm przepływu pracy obsługuje transakcje, mutacje i idempotencję. Różne silniki przepływu pracy dokonują różnych kompromisów pod względem tego, ile szczegółów transakcji jest udostępnianych programistom. 

Jako przykład, poniżej znajduje się wizualna reprezentacja przepływu pracy w systemie Orkes (Conductor): 

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Tam są dwa ostre podejścia dzięki którym silniki przepływu pracy zyskują przyczepność. W jednym (typowym dla Temporal.io) programiści piszą kod przy użyciu standardowych języków programowania zaplecza (np. Go lub Java), a system zapewni, że kod zostanie wykonany do końca, nawet podczas awarii. W tym modelu stos wywołań programu jest utrzymywany nawet wtedy, gdy kod oczekuje na zakończenie wywołania blokującego (np. odczyt lub zapis). W tym celu środowisko uruchomieniowe języka jest modyfikowane, aby zapobiec częściowemu wykonywaniu kodu w przypadku awarii. Zaletą tego podejścia jest to, że programiści mogą pisać w znanych językach i łatwo debugować przy użyciu utrzymywanego stosu wywołań. To podejście jest najbardziej popularne wśród zespołów zaplecza zajmujących się dużymi, zaawansowanymi aplikacjami. 

Wadą jest to, że często wymaga dużo pracy integracyjnej i kodu opakowania, aby udostępnić programistom aplikacji użyteczne i bezpieczne interfejsy. Inną wadą jest to, że opiera się na niestandardowej warstwie wykonania, a nie na samym języku, i istnieją skrajne przypadki, w których wykonanie będzie się różnić od środowiska uruchomieniowego języka natywnego. Tak więc, chociaż programiści mogą używać języków, które znają, nadal muszą zrozumieć, jak działa podstawowy system.  

Drugie podejście, bardziej popularne wśród twórców aplikacji (zwłaszcza TypeScript/Javascript), polega na tym, że silnik przepływu pracy służyć jako orkiestrator funkcji asynchronicznych (np. Ingest, Defer i Trigger). W tym modelu zdarzenia lub funkcje stron trzecich są kierowane do silnika przepływu pracy, który następnie wysyła logikę zarejestrowaną przez programistów aplikacji, którzy muszą oddać kontrolę, gdy pojawi się potrzeba zablokowania innej funkcji asynchronicznej. Zaletą jest to, że jest to znacznie lżejsza metoda integracji z programem. Wymusza również wystarczającą strukturę kodu, aby zespół nad nim pracujący mógł go łatwiej zrozumieć. Jednak to podejście może być trudniejsze do debugowania bez obsługi narzędzi, więc debugowanie jest zwykle specyficzne dla platformy.

Silniki przepływu pracy są szczególnie wydajne, ponieważ umożliwiają stopniowe wdrażanie przez istniejące aplikacje. Można je stosować fragmentarycznie do określonych przepływów pracy przy minimalnym obciążeniu. To powiedziawszy, dwie największe wady silników przepływu pracy wynikają z faktu, że nie obejmują one bazy danych. W rezultacie nie ma jednego, sprawdzalnego źródła prawdy dotyczącego stanu aplikacji i danych biznesowych. Ponadto semantyka transakcyjna zasadniczo różni się od semantyki bazy danych, co wymaga od programistów aplikacji obsługi warunków brzegowych. 

Chociaż nie jest to obecnie normą, chcemy zilustrować koncepcyjne architektury tego, jak przepływy pracy mogą w wielu przypadkach być używane jako trwałe magazyny danych:

Przykłady architektur tylko dla przepływu pracy

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Architektura tylko dla przepływu pracy: aplikacje JavaScript

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Architektura oparta wyłącznie na przepływie pracy: aplikacje korzystające z mikrousług

Podejścia zorientowane na bazę danych w szczegółach 

Podejścia zorientowane na bazę danych zaczynają się od bazy danych, ale rozszerzają ją, aby obsługiwać wykonywanie dowolnego kodu, aby umożliwić przepływy pracy wraz z zarządzaniem danymi. Robią to, przekazując kontrolę programistom, aby mogli podejmować jednoznaczne decyzje dotyczące mutacji, transakcji i idempotencji dla zwykłych bloków kodu — zasadniczo poprzez bezpośrednie ujawnienie semantyki OLTP. Programista jest odpowiedzialny za oddzielenie logiki biznesowej i danych biznesowych od stanu aplikacji. 

Rzeczywiście, widok czysto bazodanowy polega na tym, że stan aplikacji można zawsze wyprowadzić z danych biznesowych. Zwykle odbywa się to poprzez przechowywanie stanu aplikacji jako zestawu transakcji, które modyfikują dane biznesowe w bazie danych. Najprościej jest myśleć o tym jako o bazie danych, która może wykonywać bloki kodu z takimi samymi silnymi gwarancjami, jak opisane powyżej systemy przepływu pracy. 

Wewnętrznie nazywamy to platforma transakcyjna logiki aplikacji (ALTP) podejście, ponieważ ostatecznie rozszerza transakcje OLTP na aplikację. Ale tym, co naprawdę charakteryzuje ALTP, jest to, że w przypadku aplikacji od podstaw może całkowicie wyeliminować potrzebę bezpośredniego zarządzania infrastrukturą zaplecza przez twórców aplikacji.  

Od obiektywu ALTP najczęściej stosowane podejście rozpoczęło się od Firebase, która oferuje pełna obsługa „back-end experience”, w tym autoryzacja, magazyn danych, bazy danych i inne. Firebase i nowsi uczestnicy, tacy jak Supabase, pozostają bardzo popularnymi platformami dla projektów typu greenfield. I chociaż zwykle pozostają wierni swoim korzeniom OLTP — a więc nie obsługują wykonywania dowolnego kodu dla transakcyjnych funkcji zaplecza — Supabase już zaczyna dodawać obsługę przepływów pracy.

Jednakże, oferty ALTP nowej generacji podobnie jak Convex pozwalają na wykonanie dowolnego kodu jako transakcji obok bazy danych. Te oferty umożliwiają pisanie kodu w pełni zgodnego z transakcją w normalnym języku (np. Javascript/Typescript), w którym pojedynczy blok kodu może odczytywać, zapisywać i modyfikować dane — zarówno stan aplikacji, jak i dane biznesowe. W pewnym sensie zapewnia programistom jedno źródło prawdy, które można sprawdzić, i zapewnia prymitywy przepływu pracy, takie jak subskrypcje. 

ALTP rozwiązuje problem, z jakim silniki przepływu pracy są oddzielone od bazy danych, ale w rezultacie wymaga od użytkowników polegania na swojej ofercie bazy danych, a nie na standardowym OLTP, aby uzyskać korzyści. W rezultacie widzimy, że zespoły przyjmują ALTP przede wszystkim dla aplikacji od podstaw, zamiast integrować je z istniejącymi, złożonymi backendami.

Nowoczesny stos transakcyjny PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Powyższy diagram jest amalgamatem wielu operatorów, z którymi rozmawialiśmy. Niektórzy po prostu użyją silnika przepływu pracy. Niektórzy po prostu użyją podejścia skoncentrowanego na bazie danych. Ale wielu będzie używać obu — zwłaszcza gdy dopiero zaczynają wdrażać przepływy pracy. Dzisiejsi użytkownicy silników przepływu pracy to zazwyczaj zespoły zaplecza zajmujące się dużymi, złożonymi aplikacjami, chociaż widzieliśmy też wiele zespołów, które je wdrażają. Rozwiązania typu back-end jako usługa są zwykle bardziej przyjazne dla programistów aplikacji i są częściej stosowane, gdy wybór technologii zależy od aplikacji. 

Konwergencja

Staje się jasne, że podejście zorientowane na przepływ pracy i podejście skoncentrowane na bazie danych znajdują się na kursie kolizyjnym. Głównym tego powodem jest to, że chociaż stan aplikacji i stan bazy danych są logicznie różne, są od siebie zależne, a system, który nie obejmuje obu, jest skomplikowany, aby uzyskać właściwy i debugować.  

Jako przykład rozważmy mechanizm przepływu pracy używany do śledzenia automatu stanu dla procesu realizacji zakupu przez użytkownika, a ten użytkownik dodaje element do koszyka. Zazwyczaj silniki przepływu pracy zapewniają wykonanie kroku kodu nawet w przypadku awarii. Mogą jednak wystąpić sytuacje, w których silnik będzie musiał ponownie uruchomić dany krok podczas awarii, ponieważ nie ma całkowitej pewności, czy krok został w pełni ukończony. Jeśli ten krok obejmuje zapisanie danych biznesowych w tradycyjnej bazie danych (w tym przypadku pozycji w koszyku), a baza danych nie jest świadoma ponownej próby zduplikowanej, zakończy się to zduplikowanym wpisem. 

Można sobie z tym poradzić na dwa sposoby. Jednym ze sposobów jest przekazanie problemu programiście aplikacji, który użyje identyfikatora jednorazowego dostarczonego przez system przepływu pracy, aby upewnić się, że zostanie napisany tylko jeden element. Ale zakłada to, że programista rozumie idempotentność, co jest bardzo trudne do uzyskania, a to eliminuje wiele magii posiadania systemu przepływu pracy. Innym sposobem jest powiązanie mechanizmu przepływu pracy z bazą danych, która jest świadoma semantyki transakcyjnej przepływu pracy. To jeszcze się nie stało, ale nie trudno w to uwierzyć. 

Z drugiej strony podejście zorientowane na bazę danych zdaje sobie sprawę, że ogólny przepływ pracy jest naprawdę przydatny dla twórców aplikacji. I tak zaczynamy widzieć bazy danych (takie jak Convex) — które obsługują tradycyjne funkcje bazodanowe, takie jak zapytania, mutacje, indeksy itp. — implementują funkcje takie jak planowanie i subskrypcje. Dzięki temu mogą być używane jako silniki przepływu pracy. Oznacza to, że umożliwiają wykonywanie dowolnych bloków kodu z silnymi gwarancjami. 

Jak ujął to Ian Livingstone (który przekazał opinię na temat tego utworu): „To klasyczne „Czy przenosisz logikę aplikacji do bazy danych, czy bazę danych do logiki aplikacji?” znowu się rozgrywa… tym razem wywołane rozbiciem monolitu”. Mając tę ​​dychotomię przez dziesięciolecia, jasne jest, że oba modele utrzymają się w krótkim okresie. Jest o wiele mniej jasne, że tak pozostanie na dłuższą metę. 

Specjalne podziękowania dla Charly Poly (Defer), Dan Farrelly (Inngest), David Khourshid (Stately), Ian Livingstone (Cape Security), Enes Akar (Upstash), James Cowling (Convex), Jamie Turner (Convex), Paul Copplestone (Supabase ), Samowi Lambertowi (PlanetScale), Tony'emu Holdstock-Brownowi (Inngest), Mattowi Aitkenowi (Trigger) za przejrzenie tego wpisu i przekazanie opinii. Ponadto podziękowania dla Benjamina Hindmana (Reboot), Fredrika Björka (Grafbase), Glaubera Costy (Chiselstrike), Guillaume'a Sallesa (Liveblocks), Maxima Fateeva (Temporal), Stevena Fabre'a (Liveblocks) i Virena Baraiyi (Orkes) za pomoc w badanie.

* * *

Wyrażone tutaj poglądy są poglądami poszczególnych cytowanych pracowników AH Capital Management, LLC („a16z”) i nie są poglądami a16z ani jej podmiotów stowarzyszonych. Niektóre informacje w nim zawarte zostały pozyskane ze źródeł zewnętrznych, w tym od spółek portfelowych funduszy zarządzanych przez a16z. Chociaż pochodzi ze źródeł uważanych za wiarygodne, a16z nie zweryfikowała niezależnie takich informacji i nie składa żadnych oświadczeń dotyczących trwałej dokładności informacji lub ich adekwatności w danej sytuacji. Ponadto treści te mogą zawierać reklamy osób trzecich; a16z nie przeglądał takich reklam i nie popiera żadnych zawartych w nich treści reklamowych.

Te treści są udostępniane wyłącznie w celach informacyjnych i nie należy ich traktować jako porady prawnej, biznesowej, inwestycyjnej lub podatkowej. Powinieneś skonsultować się w tych sprawach z własnymi doradcami. Odniesienia do jakichkolwiek papierów wartościowych lub aktywów cyfrowych służą wyłącznie celom ilustracyjnym i nie stanowią rekomendacji inwestycyjnej ani oferty świadczenia usług doradztwa inwestycyjnego. Ponadto treść ta nie jest skierowana ani przeznaczona do użytku przez jakichkolwiek inwestorów lub potencjalnych inwestorów iw żadnym wypadku nie można na nich polegać przy podejmowaniu decyzji o zainwestowaniu w jakikolwiek fundusz zarządzany przez a16z. (Oferta inwestycji w fundusz a16z zostanie złożona wyłącznie na podstawie memorandum dotyczącego oferty prywatnej, umowy subskrypcyjnej i innej odpowiedniej dokumentacji takiego funduszu i należy ją przeczytać w całości.) Wszelkie inwestycje lub spółki portfelowe wymienione, wymienione lub opisane nie są reprezentatywne dla wszystkich inwestycji w pojazdy zarządzane przez a16z i nie można zapewnić, że inwestycje będą opłacalne lub że inne inwestycje dokonane w przyszłości będą miały podobne cechy lub wyniki. Lista inwestycji dokonanych przez fundusze zarządzane przez Andreessena Horowitza (z wyłączeniem inwestycji, w przypadku których emitent nie wyraził zgody na publiczne ujawnienie przez a16z oraz niezapowiedzianych inwestycji w aktywa cyfrowe będące w obrocie publicznym) jest dostępna pod adresem https://a16z.com/investments /.

Wykresy i wykresy zamieszczone w niniejszym dokumencie służą wyłącznie celom informacyjnym i nie należy na nich polegać przy podejmowaniu jakichkolwiek decyzji inwestycyjnych. Wyniki osiągnięte w przeszłości nie wskazują na przyszłe wyniki. Treść mówi dopiero od wskazanej daty. Wszelkie prognozy, szacunki, prognozy, cele, perspektywy i/lub opinie wyrażone w tych materiałach mogą ulec zmianie bez powiadomienia i mogą się różnić lub być sprzeczne z opiniami wyrażanymi przez innych. Dodatkowe ważne informacje można znaleźć na stronie https://a16z.com/disclosures.

Znak czasu:

Więcej z Andreessen Horowitz