Ridurre al minimo il coordinamento

Archiviazione di Azure
Database SQL di Microsoft Azure
Azure Cosmos DB

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 varia in grado e si verifica a livelli diversi, come i livelli di dati o di elaborazione.

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:

Diagramma del 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.

Diagramma del coordinamento

È 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 Archiviazione di Azure.

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.

Gestire il coordinamento tra client connessi occasionalmente

La coerenza finale da sola non è sufficiente quando i client disconnessi utilizzano una risorsa condivisa con un limite fisso, ad esempio postazioni per un evento. Più client possono operare sulla stessa capacità apparente e sincronizzare successivamente i rispettivi record non può annullare la sovrallocazione di tale risorsa, ad esempio ammettendo più persone di quante la sede dell'evento possa ospitare. Ecco alcuni consigli di coordinamento da usare in questo scenario:

  • Partizionare la quota, non solo i dati. Prima che un client si disconnetta, assegnagli una riserva esclusiva della capacità disponibile. Il cliente può approvare le operazioni offline solo finché la relativa prenotazione dispone di capacità. Assicurarsi che la capacità usata centralmente, la capacità disponibile centralmente e la quantità completa di tutte le prenotazioni in sospeso non superino il limite globale. Quando il client si riconnette, confrontare quanto ha consumato e restituire la capacità inutilizzata.

  • Decidere chi assorbe il problema. Se i client devono operare offline senza prenotazioni esclusive, scegli una delle tre possibili opzioni di business: mantenere un buffer di capacità fisso dimensionato sulla massima domanda offline aggregata, rendere in sola lettura le operazioni che modificano la capacità quando i client sono disconnessi, oppure accettare occasionali casi di sovraallocazione.

  • Mostra errori di riconciliazione a un operatore. Inserisci in una coda di revisione i conflitti che il flusso di lavoro non può risolvere automaticamente. Utilizzare il modello di transazione di compensazione per le azioni che il sistema può invertire. Indirizzare risultati irreversibili o ambigui a un operatore che può applicare i criteri aziendali definiti.