Architettura senza server basata su eventi che utilizza le offerte AWS

1

Questo è il mio primo post sullo scambio di stack di Engineering Engineering, quindi fammi sapere se c'è qualcosa di sbagliato in questo.

Sto esaminando le offerte serverless di Amazon per cercare di capire se questa è la strada da percorrere per alcuni nuovi progetti che ho in mente. Sono particolarmente interessato a un modello CQRS basato sugli eventi, in quanto trovo molto interessanti i presunti vantaggi di tale modello in questo caso. Ma sto avendo un po 'di problemi a capire tutti i servizi che Amazon ha da offrire, quali sono i loro pro e contro e come si combinano tutti. Dopodiché darò un po 'di pretesto e in seguito dichiarerò le mie domande.

Userò un'applicazione di esempio per illustrare ciò che sto cercando:

È una semplice applicazione Web (statica), ospitata in S3 e pubblicata su cloudflare.

Ha due azioni: un comando e una query (in termini CQRS).

Il comando invia un evento sul flusso di eventi per incrementare un contatore.

La query ottiene lo stato corrente del contatore, cioè quante volte è stato incrementato.

Questo è tutto, quindi come posso implementarlo utilizzando la tecnologia AWS senza server? Ecco cosa sto pensando finora:

Per inviare il comando per incrementare il contatore, l'applicazione Web invia richieste AJAX a un lambda L1 (tramite un gateway API). Questo lambda L1 invia un evento al flusso di eventi.

Un altro lambda L2 ascolta il flusso di eventi e memorizza un record dell'evento / comando in modo che possa essere riprodotto in un secondo momento, se necessario.

Ancora un altro lambda L3 ascolta il flusso di eventi ed esegue il comando. In altre parole, recupera lo stato corrente del contatore, lo incrementa e persiste atomicamente nel nuovo stato.

Per inviare la query, l'applicazione Web invia una richiesta AJAX a lambda L4 (attraverso un gateway API), che interroga lo stato e restituisce il risultato.

Sembra che dovrebbe essere un progetto abbastanza semplice e minimale. Ecco le mie preoccupazioni finora:

Innanzitutto, quale dovrebbe essere il mio flusso di eventi? Ho visto molti suggerimenti fluttuare, ciascuno più contorto e inventato dell'ultimo. Varie strategie di smontaggio, mix di flussi SNS, SQS, Kinesis, DynamoDB, il tuo nome ... temo che finirò con troppe parti mobili, un sistema poco efficiente in termini di costi che è difficile scalare nel senso che la complessità rende è difficile da sviluppare per

In secondo luogo, posso ottenere l'atomicità? I servizi del flusso di eventi che ho menzionato sopra hanno in genere una sorta di proprietà "almeno una volta la consegna", che deve essere gestita dal consumatore. Un suggerimento che ho visto è quello di rendere ogni evento idempotente, ma ciò non sembra fattibile nella mia applicazione di esempio. Due client potrebbero incrementare il contatore allo stesso tempo e uno degli incrementi potrebbe essere "perso" perché entrambi i comandi direbbero "il contatore ora è 17 (ad esempio)". Si potrebbe argomentare che questo è un comportamento corretto, entrambi i client hanno visto il numero come 16 e hanno voluto incrementarlo a 17, ma diciamo in questa situazione che vorremmo che entrambi gli incrementi contassero verso il totale. Vogliamo che il nostro comando rappresenti solo un delta tra i due stati. C'è un modo per raggiungere questo obiettivo?

In terzo luogo, lambdas L3 e L4 devono essere entrambi in grado di accedere a una sorta di livello di persistenza. Idealmente mi piacerebbe che fosse un database relazionale (SQL) in modo da poter eseguire query avanzate sullo stato dell'applicazione corrente. Non è necessario per il mio esempio di contatore incrementale, ma sarà necessario per i progetti che ho in mente. Penso che questo mi lascia solo con una opzione se voglio rimanere senza server: Serverless Aurora. Per me va bene, ma è a mia conoscenza che Aurora ha bisogno di essere eseguito in un VPC e che lambda deve essere eseguito nello stesso VPC per avere accesso ad Aurora. Sono molto preoccupato per le prestazioni qui, poiché L3 è il singolo punto di congestione nel mio esempio (tutto il resto è solo accodamento o sola lettura). La mia comprensione è che i VPC comportano un costo considerevole delle prestazioni (throughput, numero di connessioni, larghezza di banda) e che lambdas nei VPC può avere avviamenti a freddo di oltre 10 secondi. Come posso affrontare questi problemi? Le campane d'allarme stanno andando nella mia testa, che questo introduce solo più problemi di quanti ne risolva. Probabilmente dovrei eseguire il ping di L4 continuamente in modo che non inizi mai a freddo (il tempo di caricamento di 10 secondi non è accettabile) ea quel punto, sto davvero andando senza server? Se questa è una cattiva idea, ci sono alternative migliori? Devo anche mantenere lo stato in DynamoDB, perdendo capacità di interrogazione?

Questo post è già piuttosto lungo, quindi per ora lascerò a questi tre problemi. Oltre a rispondere direttamente alle mie domande, se potessi aiutarmi a chiarire eventuali equivoci, offrire soluzioni alternative, ecc. Sarei grato!

    
posta Dan 03.08.2018 - 03:50
fonte

1 risposta

1

Non penso che troverai alcuna risposta autorevole a questo, sebbene ci sia un discreto numero di articoli su.

Probabilmente dovresti anticipare (nel primo passaggio, comunque) che uno stato mutabile nella tua soluzione potrebbe avere più di uno scrittore. Quindi dovresti anticipare che tutte le scritture modificabili utilizzano una sorta di predicato / validatore per supportare un PUT condizionale.

Sia DynamoDB che S3 supportano le put condizionali, quindi sono opzioni - ma non sono necessariamente libere, nel senso che dovrai pensare attraverso la tua strategia di storage e implementare la semantica appropriata su di esse

Durante il breakout sul sourcing di eventi in Re: Invent 2017, DynamoDB era la scelta di persistenza principale nella discussione. Dopo alcune discussioni, la conclusione è stata che le scritture in batch non avrebbero funzionato in uno scenario di più scrittori: ogni scrittura condizionale avrebbe inserito una singola riga.

Devi anche pensare a quali garanzie di affidabilità hai bisogno: è sicuro trasmettere gli eventi prima di memorizzarli? L1 dovrebbe riportare il successo prima che le modifiche persistenti siano state verificate?

La mia ipotesi migliore su un MVP sarebbe quella di avere gli endpoint L1 che leggono e scrivono in Dynamo, e quindi associare altri consumatori identienti alle loro spalle (cioè un lambda che legge gli eventi dalla dinamo e li scrive su SNS, Kinesis , ecc.)

A seconda delle tue garanzie, potresti essere in grado di semplificare gli autori in qualche modo tramite L1 - > SNS - > L2 - > Dynamo - > ecc.

when you say mutable writes should use a predicate, do you mean I should write my events like "the state has been updated from 16 to 17", and then make L2 validate that the state is currently 16 before updating?

Sì, pensa "confronta e scambia", If-Match , operazione di test della patch JSON e così via. Se più scrittori devono imporre un invariant, allora hai bisogno di un modo per assicurarti che lo stato che viene sovrascritto sia quello corretto.

    
risposta data 03.08.2018 - 06:01
fonte

Leggi altre domande sui tag