Progettazione di applicazioni di carichi di lavoro cruciali in Azure

Quando si progetta un'applicazione, i requisiti di applicazione funzionali e non funzionali sono critici. Questa area di progettazione descrive i modelli di architettura e le strategie di scalabilità che consentono di rendere l'applicazione resiliente agli errori.

Importante

Questo articolo fa parte della serie di carichi di lavoro cruciali di Azure Well-Architected Framework . Se non si ha familiarità con questa serie, è consigliabile iniziare con What is a mission-critical workload?.

Architettura dell'unità di scalabilità

Tutti gli aspetti funzionali di una soluzione devono essere in grado di ridimensionare per soddisfare le modifiche della domanda. È consigliabile usare un'architettura di unità di scalabilità per ottimizzare la scalabilità end-to-end tramite la compartimentazione e anche per standardizzare il processo di aggiunta e rimozione della capacità. Un'unità di scala è un'unità logica o una funzione che può essere ridimensionata in modo indipendente. Un'unità può essere costituita da componenti di codice, piattaforme di hosting di applicazioni, stamp di distribuzione che coprono i componenti correlati e persino le sottoscrizioni per supportare i requisiti multi-tenant.

È consigliabile questo approccio perché risolve i limiti di scalabilità delle singole risorse e l'intera applicazione. Consente di eseguire scenari di distribuzione e aggiornamento complessi perché un'unità di scalabilità può essere distribuita come un'unica unità. È anche possibile testare e convalidare versioni specifiche dei componenti in un'unità prima di indirizzare il traffico utente a esso.

Si supponga che l'applicazione mission-critical sia un catalogo prodotti online. Ha un flusso utente per l'elaborazione di commenti e valutazioni del prodotto. Il flusso usa le API per recuperare e pubblicare commenti e valutazioni e supportare componenti come un endpoint OAuth, un archivio dati e code di messaggi. Gli endpoint API senza stato rappresentano unità funzionali granulari che devono adattarsi alle modifiche su richiesta. La piattaforma applicazione sottostante deve anche essere in grado di ridimensionare di conseguenza. Per evitare colli di bottiglia delle prestazioni, i componenti e le dipendenze downstream devono essere ridimensionati anche in un grado appropriato. Possono ridimensionare in modo indipendente, come unità di scala separate o insieme, come parte di una singola unità logica.

Unità di scalabilità di esempio

L'immagine seguente mostra gli ambiti possibili per le unità di scalabilità. Gli ambiti vanno dai pod di microservizi ai nodi del cluster e ai stamp di distribuzione a livello di area.

Diagramma che mostra più ambiti per le unità di scalabilità.

Considerazioni relative alla progettazione

  • Ambito. L'ambito di un'unità di scala, la relazione tra unità di scalabilità e i relativi componenti devono essere definiti in base a un modello di capacità. Prendere in considerazione i requisiti non funzionali per le prestazioni.

  • Limiti di scalabilità. I limiti e le quote di scalabilità delle sottoscrizioni di Azure potrebbero avere un impatto sulla progettazione dell'applicazione, sulle scelte tecnologiche e sulla definizione di unità di scalabilità. Le unità di scalabilità consentono di ignorare i limiti di scalabilità di un servizio. Ad esempio, se un cluster del servizio Azure Kubernetes in un'unità può avere solo 1.000 nodi, è possibile usare due unità per aumentare tale limite a 2.000 nodi.

  • Carico previsto. Usare il numero di richieste per ogni flusso utente, la frequenza di richiesta di picco prevista (richieste al secondo) e i modelli di traffico giornalieri/settimanali/stagionali per informare i requisiti di scala principali. Fattore anche nei modelli di crescita previsti per il traffico e il volume di dati.

  • Prestazioni ridotte accettabili. Determinare se un servizio danneggiato con tempi di risposta elevati è accettabile sotto il carico. Quando si esegue la modellazione della capacità necessaria, le prestazioni necessarie della soluzione sotto carico sono un fattore critico.

  • Requisiti non funzionali. Gli scenari tecnici e aziendali hanno considerazioni distinte sulla resilienza, sulla disponibilità, sulla latenza, sulla capacità e sull'osservabilità. Analizzare questi requisiti nel contesto dei flussi utente end-to-end chiave. Si avrà una flessibilità relativa nella progettazione, nel processo decisionale e nelle scelte tecnologico a livello di flusso utente.

Suggerimenti per la progettazione

  • Definire l'ambito di un'unità di scala e i limiti che attivano la scalabilità dell'unità.

  • Assicurarsi che tutti i componenti dell'applicazione possano ridimensionare in modo indipendente o come parte di un'unità di scalabilità che include altri componenti correlati.

  • Definire la relazione tra unità di scalabilità, in base a un modello di capacità e ai requisiti non funzionali.

  • Definire un timbro di distribuzione a livello di area per unificare il provisioning, la gestione e l'operazione delle risorse dell'applicazione a livello di area in un'unità di scala eterogena ma interdipendente. Poiché il carico aumenta, è possibile distribuire altri francobolli, all'interno della stessa area di Azure o di quelli diversi, per ridimensionare orizzontalmente la soluzione.

  • Usare una sottoscrizione di Azure come unità di scalabilità in modo che i limiti di scalabilità all'interno di una singola sottoscrizione non limitino la scalabilità. Questo approccio si applica a scenari di applicazioni su larga scala che hanno un volume di traffico significativo.

  • La capacità necessaria per il modello intorno ai modelli di traffico identificati consente di assicurarsi che la capacità sufficiente venga eseguita durante il provisioning in momenti di picco per evitare il degrado del servizio. In alternativa, ottimizzare la capacità durante le ore di punta.

  • Misurare il tempo necessario per eseguire operazioni di scalabilità orizzontale e scalabilità orizzontale per garantire che le variazioni naturali nel traffico non creino un livello inaccettabile di riduzione del servizio. Tenere traccia delle durate dell'operazione di scalabilità come metrica operativa.

Nota

Quando si distribuisce in un'area di destinazione di Azure, assicurarsi che la sottoscrizione della zona di destinazione sia dedicata all'applicazione per fornire un limite di gestione chiaro e per evitare l'antipattern Di prossimità rumoroso.

Distribuzione globale

Non è possibile evitare errori in qualsiasi ambiente altamente distribuito. Questa sezione fornisce strategie per attenuare molti scenari di errore. L'applicazione deve essere in grado di resistere a errori regionali e di zona. Deve essere distribuito in un modello attivo/attivo in modo che il carico venga distribuito tra tutte le aree.

Guardare questo video per ottenere una panoramica di come pianificare gli errori nelle applicazioni cruciali e ottimizzare la resilienza:

Considerazioni relative alla progettazione

  • Ridondanza. L'applicazione deve essere distribuita in più aree. Inoltre, all'interno di un'area, è consigliabile usare le zone di disponibilità per consentire la tolleranza di errore a livello di data center. Le zone di disponibilità hanno un perimetro di latenza inferiore a 2 millisecondi tra le zone di disponibilità. Per i carichi di lavoro che sono "chatty" tra zone, questa latenza può introdurre una penalità delle prestazioni e incorrere in costi di larghezza di banda per il trasferimento dei dati interzone.

  • Modello attivo/attivo. È consigliabile una strategia di distribuzione attiva/attiva perché ottimizza la disponibilità e fornisce un contratto di servizio composito più elevato. Tuttavia, può presentare problemi relativi alla sincronizzazione dei dati e alla coerenza per molti scenari dell'applicazione. Affrontare le sfide a livello di piattaforma dati considerando i compromessi di un aumento dei costi e degli sforzi di progettazione.

    Una distribuzione attiva/attiva in più provider di cloud è un modo per mitigare potenzialmente la dipendenza dalle risorse globali all'interno di un singolo provider cloud. Tuttavia, una strategia di distribuzione attiva/attiva multicloud introduce una quantità significativa di complessità intorno a CI/CD. Inoltre, in base alle differenze tra le specifiche e le funzionalità delle risorse tra i provider di servizi cloud, è necessario disporre di stamp di distribuzione specializzati per ogni cloud.

  • Distribuzione geografica. Il carico di lavoro potrebbe avere requisiti di conformità per la residenza geografica dei dati, la protezione dei dati e la conservazione dei dati. Valutare se sono presenti aree specifiche in cui i dati devono risiedere o dove devono essere distribuite le risorse.

  • Origine richiesta. La prossimità geografica e la densità degli utenti o dei sistemi dipendenti devono informare le decisioni di progettazione sulla distribuzione globale.

  • Connettività. Il modo in cui il carico di lavoro è accessibile dagli utenti o dai sistemi esterni influisce sulla progettazione. Valutare se l'applicazione è disponibile tramite internet pubblico o reti private che usano circuiti VPN o Azure ExpressRoute.

Per le raccomandazioni di progettazione e le scelte di configurazione a livello di piattaforma, vedere Piattaforma applicazione: Distribuzione globale.

Architettura basata su eventi in modo flessibile

L'accoppiamento consente la comunicazione tra servizi tramite interfacce ben definite. Un accoppiamento libero consente a un componente dell'applicazione di funzionare in modo indipendente. Uno stile di architettura di microservizi è coerente con i requisiti cruciali. Facilita la disponibilità elevata impedendo errori a catena.

Per l'accoppiamento libero, è consigliabile incorporare la progettazione basata su eventi. L'elaborazione di messaggi asincroni tramite un intermediario può creare resilienza.

Diagramma che illustra la comunicazione basata su eventi asincroni.

In alcuni scenari, le applicazioni possono combinare l'accoppiamento libero e stretto, a seconda degli obiettivi aziendali.

Considerazioni relative alla progettazione

  • Dipendenze di runtime. Non è consigliabile limitare l'uso della stessa piattaforma di calcolo, del linguaggio di programmazione, del runtime o del sistema operativo.

  • Ridimensionamento. I servizi devono essere in grado di ridimensionare in modo indipendente. Ottimizzare l'uso delle risorse dell'infrastruttura e della piattaforma.

  • Tolleranza di errore. Gli errori devono essere gestiti separatamente e non devono influire sulle transazioni client.

  • Integrità transazionale. Prendere in considerazione l'effetto della creazione e della persistenza dei dati che si verifica in servizi separati.

  • Traccia distribuita. La traccia end-to-end potrebbe richiedere un'orchestrazione complessa.

Suggerimenti per la progettazione

  • Allineare i limiti dei microservizi ai flussi utente critici.

  • Usare la comunicazione asincrona basata su eventi, se possibile per supportare prestazioni ottimali e scalabilità sostenibile.

  • Usare modelli come Outbox e Sessione transazionale per garantire la coerenza in modo che ogni messaggio venga elaborato correttamente.

Esempio: approccio basato su eventi

L'implementazione di riferimento di Mission-Critical Online usa microservizi per elaborare una singola transazione aziendale. Si applicano operazioni di scrittura in modo asincrono con un gestore messaggi e un ruolo di lavoro. Le operazioni di lettura sono sincrone, con il risultato restituito direttamente al chiamante.

Diagramma che mostra la comunicazione basata su eventi.

Modelli di resilienza e gestione degli errori nel codice dell'applicazione

Un'applicazione mission-critical deve essere progettata per essere resiliente in modo da risolvere il maggior numero possibile di scenari di errore. Questa resilienza ottimizza la disponibilità e l'affidabilità del servizio. L'applicazione deve avere funzionalità di auto-guarigione, che è possibile implementare usando modelli di progettazione come Retries con Backoff e Circuit Breaker.

Per gli errori non temporanei che non è possibile attenuare completamente nella logica dell'applicazione, il modello di integrità e i wrapper operativi devono intraprendere azioni correttive. Il codice dell'applicazione deve incorporare strumentazione e registrazione appropriate per informare il modello di integrità e facilitare la risoluzione dei problemi successivi o l'analisi della causa radice in base alle esigenze. È necessario implementare la traccia distribuita per fornire al chiamante un messaggio di errore completo che include un ID di correlazione quando si verifica un errore.

Gli strumenti come Application Insights consentono di eseguire query, correlare e visualizzare le tracce dell'applicazione.

Considerazioni relative alla progettazione

  • Configurazioni appropriate. Non è raro che i problemi temporanei causano errori a catena. Ad esempio, riprovare senza back-off appropriato esacerbare il problema quando un servizio viene limitato. È possibile ripetere i tentativi di spazio in modo lineare o aumentarli in modo esponenziale per tornare indietro attraverso ritardi in crescita.

  • Endpoint di integrità. È possibile esporre controlli funzionali all'interno del codice dell'applicazione usando endpoint di integrità che le soluzioni esterne possono eseguire il polling per recuperare lo stato di integrità dei componenti dell'applicazione.

Suggerimenti per la progettazione

Ecco alcuni modelli comuni di ingegneria software per applicazioni resilienti:

Modello Summary
Livellamento del carico basato sulle code Introduce un buffer tra consumer e risorse richieste per garantire livelli di carico coerenti. Poiché le richieste del consumer vengono accodate, un processo di lavoro li gestisce in base alla risorsa richiesta a un ritmo impostato dal ruolo di lavoro e dalla capacità della risorsa richiesta di elaborare le richieste. Se i consumer prevedono risposte alle loro richieste, è necessario implementare un meccanismo di risposta separato. Applicare un ordine con priorità in modo che le attività più importanti vengano eseguite prima.
Interruttore Fornisce stabilità attendendo il ripristino o rifiutando rapidamente le richieste anziché bloccando mentre si attende un servizio remoto o una risorsa non disponibile. Questo modello gestisce anche gli errori che potrebbero richiedere un intervallo di tempo variabile da recuperare da quando viene eseguita una connessione a un servizio o una risorsa remota.
A scomparti Tenta di partizionare le istanze del servizio in gruppi in base ai requisiti di carico e disponibilità, isolando gli errori per sostenere la funzionalità del servizio.
Saga Gestisce la coerenza dei dati tra microservizi che dispongono di archivi dati indipendenti assicurandosi che i servizi si aggiornino tra loro tramite canali di eventi o messaggi definiti. Ogni servizio esegue transazioni locali per aggiornare il proprio stato e pubblica un evento per attivare la transazione locale successiva nella saga. Se un aggiornamento del servizio ha esito negativo, la saga esegue transazioni di compensazione per contrastare i passaggi di aggiornamento del servizio precedenti. I singoli passaggi di aggiornamento del servizio possono implementare modelli di resilienza, ad esempio riprovare.
Monitoraggio endpoint di integrità Implementa i controlli funzionali in un'applicazione a cui gli strumenti esterni possono accedere tramite endpoint esposti a intervalli regolari. È possibile interpretare le risposte dagli endpoint usando le metriche operative chiave per informare l'integrità dell'applicazione e attivare risposte operative, ad esempio la generazione di un avviso o l'esecuzione di una distribuzione di rollback di compensazione.
Nuovo tentativo Gestisce gli errori temporanei elegantemente e trasparente.
- Annullare se l'errore è improbabile che sia temporaneo ed è improbabile che abbia esito positivo se l'operazione viene riprovata.
- Riprovare se l'errore è insolito o raro e l'operazione avrà esito positivo se si tenta di ripetere immediatamente.
- Riprovare dopo un ritardo se l'errore è causato da una condizione che potrebbe richiedere un breve periodo di tempo per il ripristino, ad esempio connettività di rete o errori di carico elevato. Applicare una strategia di back-off appropriata come ritardi di ripetizione dei tentativi aumentano.
Limitazione Controlla l'utilizzo delle risorse usate dai componenti dell'applicazione, proteggendoli dal diventare sovradimensionati. Quando una risorsa raggiunge una soglia di carico, semplifica le operazioni con priorità inferiore e riduce le funzionalità non essenziali in modo che le funzionalità essenziali possano continuare fino a quando non sono disponibili risorse sufficienti per tornare alla normale operazione.

Ecco alcuni consigli aggiuntivi:

  • Usare SDK forniti dal fornitore, ad esempio gli SDK di Azure, per connettersi ai servizi dipendenti. Usare funzionalità di resilienza predefinite anziché implementare funzionalità personalizzate.

  • Applicare una strategia di back-off appropriata durante la ripetizione delle chiamate di dipendenza non riuscite per evitare uno scenario DDoS auto-inflitto.

  • Definire criteri di progettazione comuni per tutti i team di microservizi dell'applicazione per guidare la coerenza e la velocità nell'uso di modelli di resilienza a livello di applicazione.

  • Implementare modelli di resilienza usando pacchetti standardizzati comprovati, ad esempio Polly per C# o Sentinel per Java.

  • Usare gli ID di correlazione per tutti gli eventi di traccia e registrare i messaggi per collegarli a una determinata richiesta. Restituisce gli ID di correlazione al chiamante per tutte le chiamate, non solo richieste non riuscite.

  • Usare la registrazione strutturata per tutti i messaggi di log. Selezionare un sink dati operativo unificato per le tracce, le metriche e i log dell'applicazione per consentire agli operatori di eseguire facilmente il debug dei problemi. Per altre informazioni, vedere Raccogliere, aggregare e archiviare i dati di monitoraggio per le applicazioni cloud.

  • Assicurarsi che i dati operativi vengano usati insieme ai requisiti aziendali per informare un modello di integrità dell'applicazione.

Selezione del linguaggio di programmazione

È importante selezionare i linguaggi e i framework di programmazione corretti. Queste decisioni sono spesso guidate dai set di competenze o dalle tecnologie standardizzate nell'organizzazione. Tuttavia, è essenziale valutare le prestazioni, la resilienza e le funzionalità complessive di vari linguaggi e framework.

Considerazioni relative alla progettazione

  • Funzionalità del kit di sviluppo. Esistono differenze tra le funzionalità offerte dagli SDK del servizio di Azure in varie lingue. Queste differenze possono influire sulla scelta di un servizio o di un linguaggio di programmazione di Azure. Ad esempio, se Azure Cosmos DB è un'opzione fattibile, Go potrebbe non essere un linguaggio di sviluppo appropriato perché non è disponibile un SDK di prima parte.

  • Aggiornamenti delle funzionalità. Valutare la frequenza con cui l'SDK viene aggiornato con nuove funzionalità per la lingua selezionata. Gli SDK comunemente usati, ad esempio le librerie .NET e Java, vengono aggiornati di frequente. Altri SDK o SDK per altre lingue potrebbero essere aggiornati meno frequentemente.

  • Più linguaggi di programmazione o framework. È possibile usare più tecnologie per supportare vari carichi di lavoro compositi. Tuttavia, è consigliabile evitare sprawl perché introduce complessità di gestione e sfide operative.

  • Opzione di calcolo. Il software legacy o proprietario potrebbe non essere eseguito nei servizi PaaS. Potrebbe anche non essere possibile includere software legacy o proprietario nei contenitori.

Suggerimenti per la progettazione

  • Valutare tutti gli SDK di Azure pertinenti per le funzionalità necessarie e i linguaggi di programmazione scelti. Verificare l'allineamento con i requisiti non funzionali.

  • Ottimizzare la selezione di linguaggi di programmazione e framework a livello di microservizio. Usare più tecnologie in base alle esigenze.

  • Assegnare priorità a .NET SDK per ottimizzare l'affidabilità e le prestazioni. Gli SDK di Azure .NET offrono in genere più funzionalità e vengono aggiornati di frequente.

Passaggio successivo

Esaminare le considerazioni per la piattaforma dell'applicazione.