Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Ridurre al minimo il coordinamento per ottenere la scalabilità
La maggior parte delle applicazioni cloud è costituita da più servizi applicativi, ad esempio front-end Web, database, processi aziendali e creazione di report e analisi. Per ottenere scalabilità e affidabilità, ciascuno di questi servizi deve eseguire più istanze.
I sistemi non coordinati, in cui il lavoro può essere gestito in modo indipendente senza la necessità di passare messaggi tra computer, è in genere più semplice da ridimensionare. Il coordinamento non è in genere uno stato binario, ma uno spettro. Il coordinamento avviene a livelli diversi, ad esempio dati o calcolo.
Cosa accade quando due istanze provano a eseguire operazioni simultanee che influiscono su determinati stati condivisi? In alcuni casi, è necessario il coordinamento tra i nodi, ad esempio per mantenere le garanzie ACID. In questo diagramma Node2 è in attesa che Node1 rilasci un blocco di database:
Il coordinamento limita i vantaggi di scalabilità orizzontale e crea colli di bottiglia. In questo esempio, man mano che si scala l'applicazione aggiungendo più istanze, noterai un aumento nella contesa di blocco. Nel peggiore dei casi, le istanze front-end impiegano la maggior parte del tempo in attesa sui blocchi di accesso.
La semantica "esattamente una volta" è un'altra fonte frequente di coordinamento. Per esempio, un ordine deve essere elaborato esattamente una volta. Due lavoratori ascoltano nuovi ordini.
Worker1 prende in carico un ordine per l'elaborazione. L'applicazione deve garantire che Worker2 non duplichi il lavoro, ma anche che, in caso di arresto anomalo di Worker1, l'ordine non venga eliminato.
È possibile utilizzare un modello, come ad esempio Scheduler Agent Supervisor, per il coordinamento tra i lavoratori, ma in questo caso, una soluzione migliore potrebbe essere suddividere il lavoro. A ogni ruolo di lavoro viene assegnato un determinato intervallo di ordini (ad esempio, per area di fatturazione). Se un ruolo di lavoro ha un arresto anomalo, una nuova istanza riprende dal punto in cui la precedente si è interrotta, senza che vi sia conflitto fra le diverse istanze.
Consigli
Usare componenti disaccoppiati che comunicano in modo asincrono. I componenti dovrebbero idealmente usare eventi per comunicare tra loro.
Accogliere la coerenza eventuale. Quando i dati vengono distribuiti, si coordinano per applicare le garanzie di coerenza di alto livello. Ad esempio, si supponga che un'operazione aggiorni due database: invece di inserirla in un unico ambito di transazione, è preferibile che il sistema possa far fronte alla coerenza finale, magari usando il modello di transazione di compensazione per eseguire il rollback in modo logico dopo l'errore.
Usare gli eventi di dominio per sincronizzare lo stato. Un evento di dominio è un evento che registra quando si verifica ciò che ha significance all'interno del dominio. I servizi interessati possono essere in ascolto dell'evento, invece di usare una transazione globale per coordinare tra più servizi. Se viene usato questo approccio, il sistema deve tollerare la coerenza finale (vedere elemento precedente).
Considerare modelli come CQRS e event sourcing. Questi due modelli possono aiutare a ridurre la contesa tra i carichi di lavoro di lettura e i carichi di lavoro di scrittura.
Il modello CQRS separa le operazioni di lettura da quelle di scrittura. In alcune implementazioni, la lettura dati è fisicamente separata dalla scrittura dati.
Nel modello Event Sourcing, le modifiche di stato vengono registrate come una serie di eventi in un archivio dati in sola aggiunta. L'accodamento di un evento al flusso è un'operazione atomica, che richiede un blocco minimo.
Questi due modelli sono complementari tra loro. Se l'archivio di sola scrittura in CQRS usa il sourcing degli eventi, l'archivio di sola lettura può ascoltare gli stessi eventi per creare uno snapshot leggibile dello stato corrente, ottimizzato per le query. Prima di adottare CQRS o event sourcing, essere consapevoli delle problematiche di questo approccio.
Dati e stato della partizione. Evitare di inserire tutti i dati in uno schema di dati, condiviso tra molti servizi delle applicazioni. Un'architettura di microservizi applica questo principio, rendendo ogni servizio responsabile del proprio archivio dati. All'interno di un singolo database, il partizionamento dei dati in partizioni può migliorare la concorrenza, perché un servizio che scrive in una partizione non influisce sulla scrittura di un servizio in una partizione diversa. Anche se il partizionamento aggiunge un certo grado di coordinamento, è possibile usare il partizionamento per aumentare il parallelismo per una migliore scalabilità. Partizionare lo stato monolitico in blocchi più piccoli in modo che i dati possano essere gestiti in modo indipendente.
Progettare operazioni idempotenti. Quando possibile, progettare operazioni che siano idempotenti, In modo tale che possano essere gestite con una semantica dell'almeno una volta. Ad esempio, è possibile inserire gli elementi di lavoro in una coda: Se un ruolo di lavoro si arresta in modo anomalo durante un'operazione, un altro ruolo di lavoro acquisisce l'elemento di lavoro. Se il lavoratore deve aggiornare i dati e emettere altri messaggi come parte della sua logica, è necessario usare il modello di elaborazione dei messaggi idempotenti.
Quando possibile, usare la concorrenza ottimistica. Il controllo della concorrenza pessimistica usa blocchi di database per evitare conflitti. Questo può causare prestazioni non ottimali e ridurre la disponibilità. Con il controllo della concorrenza ottimistica, ogni transazione modifica una copia o un'istantanea dei dati. Quando viene eseguito il commit della transazione, il motore di database convalida la transazione e rifiuta tutte le transazioni che hanno influenza sulla coerenza del database.
Il database SQL di Azure e SQL Server supportano la concorrenza ottimistica tramite l'isolamento dello snapshot. Alcuni servizi di Archiviazione di Microsoft Azure supportano la concorrenza ottimistica tramite l'uso di valori Etag, tra cui Azure Cosmos DB e Azure Storage.
Prendere in considerazione MapReduce o altri algoritmi paralleli e distribuiti. A seconda dei dati e del tipo di lavoro da eseguire, è possibile suddividere il lavoro in attività indipendenti che possono essere eseguite da più nodi che funzionano in parallelo. Vedere Big compute architecture style (Stile dell'architettura Big compute).
Utilizzare l'elezione del leader per il coordinamento. Nei casi in cui sia necessario coordinare le operazioni, assicurarsi che il coordinatore non diventi un singolo punto di guasto nell'applicazione. Usando il modello di elezione del leader, un'istanza rappresenta il leader in qualsiasi momento e funge da coordinatore. Se il leader fallisce, viene designata una nuova istanza come leader.