Il moderno stack transazionale

Il moderno stack transazionale

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

I database transazionali sono stati a lungo il componente più critico della progettazione delle applicazioni. Perché? Perché un database stabile è generalmente il punto di applicazione definitivo per la correttezza in un mondo disordinato e distribuito. Senza di loro pagheremmo più del dovuto e faremmo pagare meno. Perderemmo i motociclisti che cercano di tornare a casa dall'aeroporto e perderemmo gli articoli nei nostri carrelli della spesa. I nostri account online verrebbero persi, duplicati o danneggiati e diventerebbero inutilizzabili. 

In effetti, il database transazionale (generalmente chiamato OLTP, abbreviazione di elaborazione delle transazioni online, database) è stato così centrale per lo sviluppo delle applicazioni che, nel tempo, ha consumato sempre più funzionalità dell'applicazione. Tuttavia, i microservizi e altre moderne architetture applicative hanno introdotto nuove complessità nella progettazione delle applicazioni: gli sviluppatori dovevano gestire i dati tra diversi servizi e garantire la coerenza tra di essi, il che li ha costretti a creare internamente complessi meccanismi di sincronizzazione ed elaborazione dei dati. 

E così, come settore, stiamo assistendo a una crescente consapevolezza che le garanzie transazionali sono necessarie al di fuori del modello tradizionale. Stiamo vedendo il emergere di sistemi che estendono solide garanzie transazionali oltre il database, nelle stesse app distribuite

Abbiamo monitorato queste soluzioni negli ultimi anni. In genere, si sforzano di consentire la gestione transazionale dello stato in un'app distribuita di grandi dimensioni, senza creare problemi di scalabilità e fornendo al tempo stesso un ambiente di programmazione moderno. 

Troviamo che queste soluzioni si dividono approssimativamente in due categorie. Una categoria è orchestrazione del flusso di lavoro. Ciò garantisce sostanzialmente che un blocco di codice venga eseguito fino al completamento, anche in caso di errore. Quindi può essere utilizzato allo scopo di gestire deterministicamente una macchina a stati distribuiti senza diventare traballante. La seconda categoria è banca dati + flusso di lavoro, che estende la tradizionale progettazione di database OLTP, consentendo l'esecuzione di codice arbitrario per lo stesso scopo. 

Questa è ancora un'area molto nascente e c'è molta confusione sulla nomenclatura, su come ogni strumento viene utilizzato nella pratica e su chi dovrebbe usarli. Per ottenere una migliore comprensione, abbiamo chiesto ai professionisti delle principali organizzazioni di ingegneria il loro stack transazionale e come stanno pensando a tre concetti chiave per i carichi di lavoro transazionali: stato dell'applicazione, logica aziendale e dati aziendali. 

Prima di esaminare questi nuovi stack, però, ecco una rapida digressione semi-tecnica per aiutare a capire come siamo arrivati ​​qui.

Transazioni, garanzie e app moderne 

La versione molto approssimativa è questa: ci sono una serie di attività - transazioni - che vuoi fare tutte o nessuna. Qualunque cosa nel mezzo (avendolo fatto parzialmente) finirà in uno stato corrotto. È difficile da garantire nulla in un sistema distribuito, ma i database lo fanno bene con le transazioni. Pertanto, il modo più semplice per gestire le garanzie in molti sistemi è semplicemente eseguire la maggior parte delle transazioni e lasciare che il database le gestisca.

Le app moderne sono grandi sistemi distribuiti con molti utenti che fanno molte cose. Quindi, anche mantenere lo stato dell'app coerente (come tenere traccia di dove si trovano diversi utenti in un flusso di check-out) si trasforma in un problema di transazione distribuita. Nelle tradizionali architetture monolitiche, la gestione delle transazioni tramite SQL con un database OLTP era in qualche modo efficace. Ma nel nuovo e complesso mondo dei microservizi che interagiscono tramite API di livello superiore (ad es. REST o gRPC), le esigenze transazionali sono diventate di natura distribuita. 

Tuttavia, molte aziende che intraprendono il viaggio verso i microservizi non hanno fatto molto per estendere solide garanzie transazionali oltre il database. E, in pratica, questo è quasi sempre OK. Ma con la scalabilità delle applicazioni, crescono le incoerenze nei dati, così come i bug e gli errori non riconciliati che ne derivano nei dati aziendali. Il che, ovviamente, può essere estremamente problematico. Ciò costringe gli sviluppatori di applicazioni a gestire un'ampia gamma di scenari di errore e strategie di risoluzione dei conflitti e a garantire la coerenza dello stato elaborando le proprie strategie attraverso diversi modelli architetturali.

Definizioni

Dati aziendali ("dati") si riferisce ai dati business-critical tradizionalmente archiviati in un database OLTP per la persistenza e l'elaborazione (ad es. informazioni sul profilo utente come nome, indirizzo, punteggio di credito, ecc.).

Stato dell'applicazione si riferisce allo stato attuale del sistema; lo stato dell'applicazione è determinato da un valore memorizzato in un sistema di archiviazione dati e da quale fase si trova l'esecuzione del programma in una macchina a stati finiti (ad esempio lo stato di un ordine, come "ordine ricevuto", "inventario verificato", "credito verificato" ”, “spedito”, “restituito”).

Logica di business si riferisce alla parte del programma che si occupa di come funziona effettivamente l'applicazione o cosa fa, invece dei dettagli di esecuzione (ad esempio "Se reddito_utente > $100 e punteggio_credito >650 ⇒ mutuo_approvato = VERO").

Ai fini di questa discussione, è importante distinguere lo stato dell'applicazione ei dati aziendali. Ad esempio, sapere che un cliente ha inserito la propria carta di credito ma non ha effettuato il check-out è lo stato dell'applicazione. I dati della carta di credito e gli articoli nel carrello dell'applicazione sono i dati aziendali. 

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

In un flusso tipico, una richiesta proviene dal front-end, viene autenticata e quindi viene instradata tramite un gateway API o GraphQL all'endpoint pertinente. 

Quel singolo endpoint API ora deve orchestrare decine o centinaia di microservizi per consegnare la transazione aziendale al cliente finale. È qui che gli sviluppatori in genere raggruppano tutto in BLOB di logica aziendale e quindi utilizzano una combinazione di code, cache e meccanismi di ripetizione codificati a mano per ottenere i dati nel database, si spera impegnati come transazione completa.

Con l'aumentare della scala dell'applicazione, aumenta anche la complessità della gestione di code e cache, nonché il numero di spigoli vivi nella logica di riconciliazione quando sorgono problemi. 

L'ascesa di stack transazionali incentrati sul flusso di lavoro e sul database

OK, quindi le transazioni sono importanti. LAMP su un database non era sufficiente per la scala. E una gigantesca palla di pelo di code e logica di ripetizione è troppo fragile. Per far fronte a questo, abbiamo visto, negli ultimi anni, l'emergere di nuove soluzioni che riportano la sanità mentale alla logica transazionale. Possono essere approssimativamente classificati come approcci incentrati sul flusso di lavoro o approcci incentrati sul database.

Ad oggi, i motori di flusso di lavoro lavorano principalmente sullo stato dell'applicazione piuttosto che sui dati aziendali e spesso richiedono una certa complessità durante l'integrazione con i database tradizionali. Gli approcci incentrati sul database aggiungono la logica dell'applicazione ai dati aziendali, ma non hanno ancora la stessa complessità di esecuzione del codice dei motori di workflow. 

Il diagramma seguente fornisce uno schizzo approssimativo di come gli approcci incentrati sul flusso di lavoro e/o sul database vengono utilizzati in un'applicazione Javascript/Typescript, supponendo che entrambi siano in uso. Sebbene oggi siano parti distinte di questa architettura, abbiamo visto i primi segni di una tendenza in cui i database stanno incorporando funzionalità di flusso di lavoro e i flussi di lavoro stanno iniziando ad adottare l'archiviazione durevole. Questa fusione di capacità indica che i confini tra i due approcci si stanno sfumando e diventano meno distinti nelle architetture moderne. 

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Approcci incentrati sul flusso di lavoro in dettaglio 

Un flusso di lavoro è costituito semplicemente da blocchi di codice che vengono eseguiti in base a eventi, o timer, che evolvono la macchina a stati dell'applicazione. Il flusso di lavoro transazionale garantisce l'esecuzione del codice con solide garanzie, impedendo stati parziali o imprevisti nell'applicazione. Gli sviluppatori scrivono la logica e il motore del flusso di lavoro gestisce transazioni, mutazioni e idempotenza. Diversi motori di flusso di lavoro fanno diversi compromessi in termini di quanti dettagli della transazione sono esposti agli sviluppatori. 

Ad esempio, di seguito è riportata una rappresentazione visiva di un flusso di lavoro di check-out in esecuzione su Orkes (Direttore): 

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Ci sono due approcci approssimativi con cui i motori del flusso di lavoro guadagnano trazione. In uno (rappresentato da Temporal.io), gli sviluppatori scrivono codice utilizzando linguaggi di programmazione back-end standard (ad esempio Go o Java) e il il sistema assicurerà che il codice venga eseguito fino al completamento, anche durante un guasto. In questo modello, lo stack delle chiamate di programma viene mantenuto anche se il codice è in attesa del completamento di una chiamata di blocco (ad esempio lettura o scrittura). A tale scopo, il runtime del linguaggio viene modificato per impedire l'esecuzione parziale del codice durante gli errori. Il vantaggio di questo approccio è che gli sviluppatori possono scrivere in linguaggi familiari ed eseguire facilmente il debug con uno stack di chiamate mantenuto. Vediamo questo approccio più popolare tra i team di back-end che si occupano di app grandi e sofisticate. 

Lo svantaggio è che spesso richiede molto lavoro di integrazione e codice wrapper per esporre interfacce utili e sicure agli sviluppatori di applicazioni. Un altro svantaggio è che si basa su un livello di esecuzione personalizzato piuttosto che sul semplice linguaggio e ci sono casi limite in cui l'esecuzione differirà dal runtime del linguaggio nativo. Pertanto, sebbene gli sviluppatori possano utilizzare linguaggi con cui hanno familiarità, devono comunque capire come funziona il sistema sottostante.  

L'altro approccio, più popolare tra gli sviluppatori di applicazioni (in particolare Typescript/Javascript) prevede che il motore del flusso di lavoro fungere da orchestratore di funzioni asincrone (ad es. Inngest, Defer e Trigger). In questo modello, gli eventi o le funzioni di terze parti vengono indirizzati al motore del flusso di lavoro, che invierà quindi la logica registrata dai programmatori dell'applicazione, che devono restituire il controllo una volta che si presenta la necessità di bloccare un'altra funzione asincrona. Il lato positivo è che questo è un metodo molto più leggero di integrazione in un programma. Inoltre impone una struttura sufficiente al codice in modo che il team che ci lavora possa capirlo più facilmente. Tuttavia, questo approccio può essere più difficile da eseguire il debug senza il supporto degli strumenti, quindi il debug tende a essere specifico della piattaforma.

I motori di flusso di lavoro sono particolarmente potenti in quanto consentono l'adozione graduale da parte delle app esistenti. Possono essere applicati in modo frammentario a determinati flussi di lavoro con un ingombro minimo. Detto questo, i due maggiori difetti dei motori di workflow derivano dal fatto che non si estendono al database. Di conseguenza, non esiste un'unica fonte attendibile interrogabile sullo stato dell'applicazione e sui dati aziendali. Inoltre, la semantica transazionale è generalmente diversa dalla semantica del database, richiedendo agli sviluppatori di applicazioni di gestire le condizioni limite. 

Sebbene oggi non sia la norma, vogliamo illustrare le architetture concettuali di come i flussi di lavoro possono in molti casi essere utilizzati come archivi di dati persistenti:

Esempi di architetture solo flusso di lavoro

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Architettura solo flusso di lavoro: app JavaScript

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Architettura solo flusso di lavoro: app che utilizzano microservizi

Approcci incentrati sul database in dettaglio 

Gli approcci incentrati sul database iniziano con un database, ma lo estendono per supportare l'esecuzione di codice arbitrario per consentire flussi di lavoro insieme alla gestione dei dati. Lo fanno dando il controllo ai programmatori in modo che possano prendere decisioni esplicite su mutazioni, transazioni e idempotenza per blocchi di codice regolari, essenzialmente esponendo direttamente la semantica OLTP. Il programmatore è responsabile della separazione della logica aziendale e dei dati aziendali dallo stato dell'applicazione. 

In effetti, la pura vista del database è che lo stato dell'applicazione può sempre essere derivato dai dati aziendali. Questa operazione viene solitamente eseguita memorizzando lo stato dell'applicazione come un insieme di transazioni che modificano i dati aziendali nel database. È più facile pensare a questo come a un database in grado di eseguire blocchi di codice con le stesse solide garanzie dei sistemi di flusso di lavoro sopra descritti. 

Internamente, lo chiamiamo il piattaforma transazionale logica applicativa (ALTP) approccio perché, in definitiva, estende le transazioni OLTP nell'applicazione. Ma ciò che caratterizza davvero ALTP è che, per le app greenfield, può eliminare completamente la necessità per gli sviluppatori di app di gestire direttamente l'infrastruttura di back-end.  

Dall'obiettivo ALTP, l'approccio più comunemente utilizzato è iniziato con Firebase, che offre a "esperienza di back-end" a servizio completo tra cui autenticazione, archivio dati, database e altro. Firebase e i concorrenti più recenti, come Supabase, rimangono piattaforme molto popolari per i progetti greenfield. E mentre tendono a rimanere fedeli alle loro radici OLTP - e quindi non supportano l'esecuzione di codice arbitrario per le funzioni di back-end transazionali - Supabase sta già iniziando ad aggiungere il supporto per i flussi di lavoro.

Però, i offerte ALTP di nuova generazione come Convex consentono l'esecuzione di codice arbitrario come transazione insieme al database. Queste offerte consentono di scrivere codice pienamente conforme alle transazioni in un linguaggio normale (ad es. Javascript/Typescript), in cui un singolo blocco di codice può leggere, scrivere e modificare i dati, sia lo stato dell'applicazione che i dati aziendali. In un certo senso, offre agli sviluppatori un'unica fonte di verità interrogabile e fornisce primitive di flusso di lavoro come gli abbonamenti. 

ALTP risolve il problema che i motori del flusso di lavoro hanno nell'essere disaccoppiati dal database, ma, di conseguenza, richiedono agli utenti di fare affidamento sulla loro offerta di database piuttosto che su un OLTP standard per ottenere i vantaggi. Di conseguenza, vediamo principalmente i team adottare ALTP per le app greenfield, piuttosto che integrarlo in back-end complessi esistenti.

Il moderno stack transazionale PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Il diagramma sopra è un amalgama dei molti operatori con cui abbiamo parlato. Alcuni useranno solo un motore di flusso di lavoro. Alcuni useranno semplicemente un approccio incentrato sul database. Ma molti useranno entrambi, specialmente quando stanno appena iniziando ad adottare i flussi di lavoro. Gli utenti dei motori di flusso di lavoro oggi tendono ad essere team di back-end che si occupano di applicazioni grandi e complesse, sebbene abbiamo visto anche molti team full-stack adottarli. Le soluzioni back-end-as-a-service tendono ad essere più adatte agli sviluppatori di applicazioni e sono più comunemente utilizzate quando l'app guida la selezione della tecnologia. 

La convergenza

Sta diventando chiaro che gli approcci incentrati sul flusso di lavoro e gli approcci incentrati sul database sono in rotta di collisione. La ragione principale di ciò è che mentre lo stato dell'applicazione e lo stato del database sono logicamente distinti, dipendono l'uno dall'altro e un sistema che non copre entrambi è complesso da correggere e da eseguire il debug.  

Ad esempio, considera un motore del flusso di lavoro utilizzato per tenere traccia della macchina a stati per il processo di checkout di un utente e quell'utente aggiunge un articolo a un carrello. In genere, i motori del flusso di lavoro assicurano che una fase di codice venga eseguita anche in caso di errore. Tuttavia, potrebbero esserci casi in cui il motore deve eseguire nuovamente un determinato passaggio durante un errore perché non è del tutto sicuro che il passaggio sia stato completato completamente. Se quel passaggio comporta la scrittura di dati aziendali in un database tradizionale (in questo caso, l'articolo nel carrello) e il database non è a conoscenza del tentativo duplicato, finirà con una voce duplicata. 

Ci sono due modi per affrontare questo problema. Un modo è sottoporre il problema allo sviluppatore dell'applicazione, che utilizzerà un nonce fornito dal sistema del flusso di lavoro per assicurarsi che venga scritto un solo elemento. Ma ciò presuppone che lo sviluppatore comprenda l'idempotenza, che è notoriamente difficile da correggere, e questo elimina gran parte della magia di avere un sistema di flusso di lavoro. L'altro modo consiste nel collegare il motore del flusso di lavoro a un database che sia a conoscenza della semantica transazionale del flusso di lavoro. Questo non è ancora successo, ma non è difficile credere che accadrà. 

D'altra parte, gli approcci incentrati sul database si rendono conto che il flusso di lavoro generale è davvero utile per gli sviluppatori di applicazioni. E così stiamo iniziando a vedere i database (come Convex) - che supportano le tradizionali funzioni di database come query, mutazioni, indici, ecc. - implementano funzionalità come la pianificazione e gli abbonamenti. Questi consentono loro di essere utilizzati come motori di flusso di lavoro. Cioè, consentono l'esecuzione di blocchi di codice arbitrari con forti garanzie. 

Come ha detto Ian Livingstone (che ha fornito feedback su questo pezzo), "È il classico "Porti la logica dell'applicazione nel database o il database nella logica dell'applicazione?" giocando di nuovo... questa volta provocato dalla rottura del monolite. Avendo avuto questa dicotomia per decenni, è chiaro che entrambi i modelli persisteranno a breve termine. È molto meno chiaro che rimarrà così a lungo termine. 

Un ringraziamento speciale a 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 ), Sam Lambert (PlanetScale), Tony Holdstock-Brown (Inngest), Matt Aitken (Trigger) per aver recensito questo post e aver fornito il proprio feedback. Inoltre, grazie a Benjamin Hindman (Reboot), Fredrik Björk (Grafbase), Glauber Costa (Chiselstrike), Guillaume Salles (Liveblocks), Maxim Fateev (Temporal), Steven Fabre (Liveblocks) e Viren Baraiya (Orkes) per averci aiutato con la ricerca.

* * *

Le opinioni qui espresse sono quelle del personale di AH Capital Management, LLC ("a16z") citato e non sono le opinioni di a16z o delle sue affiliate. Alcune informazioni qui contenute sono state ottenute da fonti di terze parti, incluse società in portafoglio di fondi gestiti da a16z. Sebbene tratti da fonti ritenute affidabili, a16z non ha verificato in modo indipendente tali informazioni e non fornisce dichiarazioni sull'accuratezza duratura delle informazioni o sulla loro adeguatezza per una determinata situazione. Inoltre, questo contenuto può includere pubblicità di terze parti; a16z non ha esaminato tali annunci pubblicitari e non approva alcun contenuto pubblicitario in essi contenuto.

Questo contenuto viene fornito solo a scopo informativo e non deve essere considerato come consulenza legale, commerciale, di investimento o fiscale. Dovresti consultare i tuoi consulenti in merito a tali questioni. I riferimenti a qualsiasi titolo o risorsa digitale sono solo a scopo illustrativo e non costituiscono una raccomandazione di investimento o un'offerta per fornire servizi di consulenza in materia di investimenti. Inoltre, questo contenuto non è diretto né destinato all'uso da parte di investitori o potenziali investitori e non può in alcun caso essere invocato quando si decide di investire in qualsiasi fondo gestito da a16z. (Un'offerta per investire in un fondo a16z sarà fatta solo dal memorandum di collocamento privato, dal contratto di sottoscrizione e da altra documentazione pertinente di tale fondo e dovrebbe essere letta nella sua interezza.) Eventuali investimenti o società in portafoglio menzionati, citati o descritti non sono rappresentativi di tutti gli investimenti in veicoli gestiti da a16z, e non si può garantire che gli investimenti saranno redditizi o che altri investimenti effettuati in futuro avranno caratteristiche o risultati simili. Un elenco degli investimenti effettuati da fondi gestiti da Andreessen Horowitz (esclusi gli investimenti per i quali l'emittente non ha autorizzato a16z a divulgare pubblicamente e gli investimenti non annunciati in asset digitali quotati in borsa) è disponibile all'indirizzo https://a16z.com/investments /.

Grafici e grafici forniti all'interno sono esclusivamente a scopo informativo e non dovrebbero essere presi in considerazione quando si prende una decisione di investimento. I rendimenti passati non sono indicativi di risultati futuri. Il contenuto parla solo a partire dalla data indicata. Eventuali proiezioni, stime, previsioni, obiettivi, prospettive e/o opinioni espresse in questi materiali sono soggette a modifiche senza preavviso e possono differire o essere contrarie alle opinioni espresse da altri. Si prega di consultare https://a16z.com/disclosures per ulteriori informazioni importanti.

Timestamp:

Di più da Andreessen Horowitz