Il pilastro delle prestazioni si concentra sulla progettazione, lo sviluppo, la convalida e l'operatività di soluzioni che soddisfano i requisiti non funzionali a livello di prestazioni (in genere associate ai tempi di risposta), capacità (grandezze di carico supportate, base utenti e throughput raggiunti) e scalabilità (capacità di soddisfare organicamente la domanda variabile e i carichi crescenti). A differenza di un ambiente di calcolo "tradizionale" composto da un'infrastruttura a capacità fissa, un ambiente hybrid cloud consente alle soluzioni di scalare dinamicamente la propria capacità e il consumo di risorse via via che la domanda aumenta e diminuisce, a condizione che le soluzioni siano progettate per utilizzare al meglio queste funzionalità.
L'analisi delle prestazioni consente inoltre di migliorare l'esperienza dell'utente attraverso miglioramenti del design del prodotto basati su evidenze e di raggiungere gli obiettivi aziendali grazie alla scalabilità e alla capacità integrate.
Raccogliere le aspettative degli utenti nella fase di definizione del prodotto, quantificare i requisiti aziendali e utilizzarli come base per la successiva architettura e progettazione del prodotto
I componenti all'interno di una soluzione ben architettata possono essere scalati indipendentemente, ad esempio aggiungere un'altra istanza di un servizio, tuttavia aggiungere o rimuovere componenti può avere effetti a catena in altre parti della soluzione. Ad esempio, aggiungere un altro server web per gestire un picco di traffico web potrebbe richiedere più code di messaggi per comunicare con i servizi back-end. Conoscere in anticipo le dipendenze di scalabilità può aiutare a comprendere il comportamento operativo della soluzione ed evitare l'esaurimento delle risorse a causa dell'overscaling di una singola risorsa
Le soluzioni hybrid cloud ben progettate utilizzano al meglio le architetture multipiattaforma e le strategie di scalabilità e bursting per ottimizzare le prestazioni, la sicurezza, i costi operativi e le aspettative degli utenti finali. Ad esempio, eseguono workload su infrastrutture on-premise con solide garanzie di prestazioni e costi operativi fissi e utilizzano il cloud service durante i periodi di picco del workload.
Spostare i dati è costoso. Le soluzioni ben progettate utilizzano al meglio la portabilità e la mobilità dei workload containerizzati e collocano i servizi il più vicino possibile ai dati che consumano
Le soluzioni devono scegliere la piattaforma e le risorse giuste per massimizzare il valore delle loro architetture. Una soluzione hybrid cloud è in grado di estendersi su più cloud, inclusa l'infrastruttura on-premise, offrendo agli architetti la libertà di scegliere la combinazione di risorse ottimale per soddisfare le esigenze di prestazioni della loro soluzione
Le prestazioni devono essere "incorporate" in una soluzione all'inizio della sua progettazione. Lasciare le considerazioni sulle prestazioni alla fine della progettazione della soluzione, o peggio, dell'implementazione, porta spesso a prestazioni non ottimali che non possono essere risolte senza rivedere ampie parti dell'architettura della soluzione. Le pratiche di Solution Design aiutano gli architetti a creare soluzioni ad alte prestazioni ed evitare approcci progettuali che possono limitare le prestazioni della soluzione.
Le soluzioni dovrebbero essere progettate per aumentare o ridurre la propria capacità di elaborazione aggiungendo o rimuovendo unità discrete (server, servizi, interfacce di rete e così via), anziché modificare la capacità delle unità esistenti, ad esempio aggiungendo più CPU a un server. Per raggiungere questo obiettivo, le soluzioni devono adottare i seguenti principi di architettura:
I componenti stateless sono componenti che non mantengono lo stato del client o della sessione (ad esempio un'identità utente o gli input di dati forniti nella chiamata precedente) tra le interazioni, eliminando le dipendenze tra i client e qualsiasi istanza specifica di un componente. Questa mancanza di dipendenza tra i componenti e i loro consumatori significa che la soluzione può essere ampliata o ridotta aggiungendo o rimuovendo istanze dei componenti senza alcun impatto sugli utenti dei servizi offerti da questi componenti. Un buon esempio di componente stateless è un cassiere in un supermercato; finché c'è almeno un cassiere disponibile, i clienti possono pagare la spesa e i cassieri possono essere aggiunti o rimossi in base all'attuale volume di clienti. Il contrario si verifica se i clienti venissero assegnati a un cassiere specifico all’inizio della spesa. Se il cassiere assegnato rallenta o, peggio, non è più disponibile, i clienti devono attendere o ricominciare da capo e le prestazioni complessive del supermercato (misurata in clienti all'ora) ne risente.
Evitare attività di lunga durata. Se una soluzione deve supportare attività di lunga durata (ad esempio eseguire un calcolo scientifico complesso), l'attività dovrebbe essere progettata per scalare orizzontalmente o verticalmente attraverso un meccanismo di interruzione e checkpoint che consenta alla soluzione di fermare e riavviare l'attività via via che le risorse vengono aggiunte o rimosse.
Dati ai margini. I componenti stateless possono, in teoria, scalare all'infinito e sono riutilizzabili tra i client. Le soluzioni ad alte prestazioni spostano lo stato, ovvero i dati dell'utente e dell'applicazione, verso l'applicazione client e i database ai margini dell'architettura della soluzione, senza mantenere alcuno stato nei livelli di architettura intermedi.
Risorse:
Stateful o stateless?
Progettare soluzioni come insiemi di componenti altamente coesi e scarsamente accoppiati consente di ridimensionare i componenti in modo indipendente, in base alla domanda del servizio che forniscono. Gli approcci architetturali come l'architettura orientata ai servizi e i microservizi incorporano questa pratica come principio di progettazione centrale, ossia un insieme di servizi coesi che comunicano attraverso API di alto livello e liberamente accoppiate.
Lo spostamento dei dati tra i componenti di una soluzione è spesso l'elemento di una transazione più dispendioso in termini di tempo. I componenti devono essere progettati per ottimizzare la frequenza e il volume delle comunicazioni per la larghezza di banda disponibile. Ad esempio, un'applicazione che esegue chiamate ripetute per recuperare valori individuali da un database potrebbe avere prestazioni "abbastanza buone" quando viene implementata su una rete locale, ma potrebbe avere un ritardo quando il componente del database viene trasferito a un provider di cloud service.
Lo stile architetturale REST (Representational State Transfer) comunemente usato nelle applicazioni web è un buon esempio del tipo di equilibrio presente in una soluzione ben progettata; lo stato rappresentativo completo di una risorsa viene trasferito come documento JSON, XML o altro che bilancia la quantità di informazioni trasferite con l'alta latenza di un'interazione web.
La cache aiuta a limitare la domanda di risorse e servizi che producono dati. Si consiglia di utilizzare la cache per i dati di lunga durata, relativamente statici e/o dati la cui produzione è "costosa". Le soluzioni ben progettate implementano meccanismi di cache a tutti i livelli dell'architettura della soluzione, posizionando le cache il più vicino possibile al consumatore per limitare le comunicazioni tra consumatore e cache e migliorare il tempo di risposta complessivo.
Gli architetti devono tenere presente che il caching può essere eccessivo. Un meccanismo di cache mal progettato o una cache troppo grande possono influire negativamente sulle prestazioni complessive della soluzione. Gli architetti devono valutare il tipo e la strategia di caching e poi misurare l'efficacia della cache durante i test e l'analisi delle prestazioni.
La messaggistica asincrona che utilizza code di messaggi, modelli di callback o altri mezzi, consente alle soluzioni di scalare in modo efficiente e di degradare gradualmente sotto carico se le risorse vengono esaurite. Le soluzioni ben progettate utilizzano al meglio la comunicazione asincrona, in particolare le code di messaggi, per offrire agli utenti finali un'esperienza utente ed evitare di "perdere" richieste se un componente fallisce. Lo stesso meccanismo può essere utilizzato anche per collegare sistemi con livelli di servizio o orari di funzionamento diversi. Ad esempio, un'applicazione web 24x7, collegata a un sistema di registrazione attivo dalle 9 alle 17 tramite una coda di messaggi consente all'applicazione web di accettare richieste da parte degli utenti finali anche quando il sistema di registrazione non è disponibile.
Le soluzioni cambiano nel tempo e le loro prestazioni possono variare di pari passo. L'integrazione di una strumentazione delle prestazioni che consenta ai team di sviluppo, test e operazioni di raccogliere in modo non intrusivo le metriche delle prestazioni dell'applicazione aiuta a sviluppare e testare un prodotto robusto che utilizza metodi basati sull'evidenza. La strumentazione aiuta anche nei test funzionali, nell'analisi dei difetti, diventando un aiuto prezioso per mantenere le prestazioni di una soluzione e aiutare a individuare le cause dei problemi di prestazioni in produzione. La strumentazione configurabile e non invasiva supporta il monitoraggio del prodotto, garantendo l'observability della soluzione nelle operazioni e supportando così i team DevOps e SRE.
La pianificazione, il collaudo e l'analisi delle prestazioni sono un insieme di pratiche e approcci che vengono applicati alle soluzioni IT con lo scopo di garantire la qualità e la capacità della soluzione di raggiungere i risultati aziendali previsti.
Di solito l'analisi si applica ad attributi di qualità come le prestazioni della soluzione, la capacità, la scalabilità e alcuni aspetti della disponibilità, della continuità aziendale e della sostenibilità in generale. L'analisi include l'identificazione e la quantificazione dei requisiti aziendali relativi alla qualità, la progettazione e l'esecuzione dei test per acquisire metriche specifiche che riflettono come la soluzione si comporta rispetto a un insieme di aspettative, tra cui tempi di risposta, throughput o carichi supportati.
Inoltre, in senso più ampio, l'ambito delle prestazioni include l'analisi della capacità di una soluzione, delle unità totali di lavoro che la soluzione può soddisfare e della sua scalabilità (quanto bene risponde alle variazioni della domanda). L'analisi delle prestazioni serve anche a dimostrare che i prodotti rimangono funzionali e stabili in condizioni di operatività estrema. L'obiettivo dell'analisi delle prestazioni non è solo quello di catturare lo stato attuale delle prestazioni della soluzione, ma anche di individuare i colli di bottiglia e di collaborare con gli stakeholder per migliorare la qualità e l'usabilità della soluzione.
Considerando la natura complessa e olistica delle prestazioni del prodotto e della gestione della capacità, dovrebbe estendersi attraverso le diverse fasi del SLDC, dalla progettazione del prodotto al supporto operativo, fino all'SRE. Questo garantisce sia una corretta gestione dei requisiti del cliente, sia il rilevamento precoce dei problemi e una risposta rapida agli incidenti in produzione.
Dal punto di vista aziendale, è importante considerare le prestazioni della soluzione nel suo complesso, che devono riflettersi in requisiti olistici non funzionali. Tuttavia, per i test delle prestazioni a livello di unità, per i test delle prestazioni precoci che implementano il paradigma shift-left e per l'analisi della causa principale dei problemi di prestazioni, potrebbe essere necessario specificare requisiti di basso livello, limitare la durata delle singole chiamate, la latenza e così via.
Pertanto, i requisiti di prestazioni di alto livello vengono in genere forniti a livello di processo o di transazione, ad esempio "Il processo di erogazione del prestito deve essere completato in meno di 2 minuti", indipendentemente dal modo in cui le prestazioni dei singoli passaggi e sottoprocessi contribuiscono al risultato finale. La creazione di un budget delle prestazioni che assegna obiettivi a ogni fase del processo nella fase di sviluppo fornisce parametri misurabili per i team di sviluppo delle funzionalità, aiuta a identificare potenziali aree problematiche e permette di concentrare gli sforzi di ottimizzazione delle prestazioni e correzione delle prestazioni dove risultano più efficaci.
I budget per le prestazioni dovrebbero considerare tutti i livelli della soluzione, dall'hardware fino al codice dell'applicazione. Escludendo anche solo uno di questi livelli, c'è il rischio che la soluzione non soddisfi le aspettative degli utenti.
Quando si testano le prestazioni, la conferma viene dai risultati effettivi, ovvero solo testando la soluzione end-to-end possiamo essere certi che soddisfi tutti i suoi requisiti. Questo riflette la natura olistica dell'analisi delle prestazioni. Il test dei componenti (ad esempio database, middleware ecc.) fornisce insight preziosi sull'analisi delle prestazioni di una soluzione e aiuta a individuare eventuali colli di bottiglia. Tuttavia, il test dei componenti da solo non è sufficiente, poiché le interazioni tra i componenti possono generare colli di bottiglia imprevisti o altri ostacoli, portando a risultati non ottimali.
Concentrarsi sulla percezione dell'utente significa dare importanza principalmente ai tempi di risposta percepiti e alla reattività complessiva dell'interfaccia utente. Il degrado delle capacità è solitamente invisibile agli utenti fino a quando le prestazioni del prodotto non ne risentono. Uno studio del 1968 ha scoperto che esistono tre ordini di grandezza distinti nelle interazioni uomo-computer:
Da ciò si è dedotto che un tempo di risposta di 2 secondi sarebbe l'ideale; 2 secondi o poco più sono quindi un buon obiettivo di tempo di risposta per le soluzioni hybrid cloud, laddove possibile. Ovviamente, le aspettative degli utenti dipendono da ciò che stanno facendo; ad esempio, nessuno si aspetta che l'animazione di un pulsante duri 2 secondi, ma 2-3 secondi rappresentano un buon obiettivo generale per le applicazioni rivolte agli utenti.
Partendo da questo principio, le soluzioni dovrebbero incorporare il test dei tempi di risposta dell'utente quale parte del loro ciclo di controllo qualità, utilizzando strumenti di testing dell'interfaccia utente. Per quanto le latenze delle chiamate API siano importanti per le prestazioni complessive del prodotto, è la performance percepita dall’utente la chiave per attrarre e mantenere la base utenti.
Gli utenti hanno spesso aspettative diverse rispetto a ciò che costituisce una "buona" prestazione. Ad esempio, un "power user" che usa un'applicazione più volte al giorno ha aspettative di prestazioni molto diverse rispetto a chi usa la stessa applicazione magari una volta al mese. Gli utenti hanno spesso difficoltà a quantificare cosa significhi per loro prestazioni "buone", fermandosi a requisiti vaghi come "abbastanza veloce" (che è un obiettivo difficile da definire e raggiungere). Inoltre, la percezione individuale delle prestazioni di un prodotto rivolto agli utenti varia da persona a persona. Ad esempio, per alcuni è accettabile un tempo di login di 10 secondi (soprattutto se si tratta di un evento singleton), mentre per altri potrebbe essere troppo lento (soprattutto se il login avviene frequentemente nel corso del workflow).
Per aiutare a quantificare e gestire le aspettative degli utenti, si consiglia di:
Monitorare e comunicare i limiti delle prestazioni ai clienti.
L'uso improprio o l'errata configurazione di un prodotto o di un componente della soluzione può essere una fonte di scarse prestazioni e di un'esperienza utente negativa. Per evitare questa situazione, gli architetti dovrebbero:
Essere consapevoli dei vincoli di prestazioni all'interno della soluzione e comunicarli proattivamente agli utenti. Ad esempio, se una soluzione utilizza un canale di comunicazione lento/a bassa larghezza di banda, l'architetto dovrebbe informare gli utenti finali che il download di immagini ad alta risoluzione ne risentirà.
Consentire ai sistemi di rilevare e comunicare quando le richieste non rientrano nei parametri di progettazione della soluzione, laddove possibile. Ad esempio, il sistema potrebbe avvisare attivamente gli utenti quando tentano di scaricare file di grandi dimensioni tramite un canale lento.
Un approccio comune ai test delle prestazioni è verificare che la soluzione raggiunga i suoi obiettivi di tempo di risposta al carico massimo previsto, presupponendo che, se la soluzione funziona bene al carico massimo atteso, sarà adatta a carichi inferiori. Il problema di questo approccio è che fornisce un solo punto dati per ogni carico massimo testato, quasi come un esercizio pass/fail.
Una soluzione ben progettata viene testata con un approccio esplorativo, al fine di valutarne la reattività su una gamma di carichi che variano per dimensioni, mix di tipi di utenti e mix di funzioni testate. Questo fornisce al team di sviluppo della soluzione informazioni preziose e sfaccettate su come i componenti della soluzione interagiscono influenzando le prestazioni, così come sui potenziali colli di bottiglia e sul modo in cui scalare la soluzione per gestire workload minori o maggiori.
Questo approccio consente di evitare ulteriori test se gli obiettivi di carico previsti cambiano e si devono raccogliere metriche delle prestazioni in condizioni di carico diverse. L'interpolazione/estrapolazione delle dipendenze esistenti tra prestazioni e intensità del carico consente di calcolare le metriche delle prestazioni per qualsiasi carico all'interno dello spettro dei carichi inizialmente testati (da zero fino ai valori di rottura, e oltre).
L'approccio tipico al test delle prestazioni segue lo schema semplificato "Misurare i tempi di risposta a specifici carichi/throughput". Questo approccio verifica se i tempi di risposta delle transazioni chiave ai carichi massimi soddisfano i livelli di servizio (SLA) stabiliti. Solitamente, i carichi testati sono limitati a "basso", "picco" e "stress". Questo approccio può rispondere alle domande sui tempi di risposta a carichi tipici, ma non fornisce una visione completa delle prestazioni del sistema in tutte le possibili condizioni operative.
L'approccio più avanzato di *Exploratory Performance Testing* è finalizzato alla creazione di un *Performance Snapshot* della soluzione testata. Lo snapshot include un set completo di metriche delle prestazioni, raccolte nel più ampio spettro di carichi supportato, dalle misurazioni di un singolo utente ai carichi post-breakpoint (laddove possibile, tranne quando il sistema si arresta in modo anomalo). Ciò include una raccolta dei tempi di risposta delle transazioni, del throughput delle transazioni e dei dati sul consumo delle risorse raccolti in condizioni di carico incrementali. Per "transazione" si intende un lavoro finito del sistema (dalle macro transazioni come login o aggiornamento dell'account), alle singole transazioni secondarie (come la chiamata di autenticazione all'interno della transazione di login), oppure semplici richieste http.
Il Performance Snapshot, ovvero l'insieme completo dei dati sulle prestazioni, include le metriche di prestazioni sopra indicate per la gamma di carico "lineare" a basso carico (dove i thread elaborati individualmente non percepiscono la presenza reciproca e i tempi di risposta non aumentano con l'aumento del carico), la gamma "non lineare" (dove i tempi di risposta aumentano con l'aumentare del carico), i punti di saturazione (dove i throughput cessano di aumentare con l'aumento del carico e raggiungono i livelli di saturazione) e l'intervallo post-breakpont (dove le prestazioni diminuiscono dopo che i throughput raggiungono il massimo e i tempi di risposta superano i livelli SLA).
Coprire l'intera gamma di carichi di solito non richiede più sforzo da parte dei team di test rispetto ai soli test ai livelli di “picco” e “stress” e ai test di resistenza, poiché si utilizzano gli stessi script di test (e il principale sforzo consiste generalmente nella creazione di tali script). Tuttavia, i vantaggi della creazione di uno snapshot delle prestazioni sono i seguenti:
Non è necessario dedicare tempo e fatica a cercare di indovinare la giusta configurazione di test che produca il throughput "giusto" delle transazioni ("picco" o "stress"), poiché basta aumentare il carico e coprire *tutte* le grandezze di carico e i throughput supportati.
Si può stabilire a quali carichi i tempi di risposta iniziano ad aumentare, dove superano i livelli SLA e dove i throughput raggiungono i livelli massimi.
Questo permette di misurare direttamente la capacità del sistema, ad esempio il carico a cui si raggiunge la condizione di breakpoint (il tempo di risposta supera lo SLA, le capacità raggiungono i livelli massimi, oppure l'uso delle risorse del sistema entra nella "zona rossa" specificata, ad esempio l'uso della CPU raggiunge il 90%, o il sistema va in crash, qualunque cosa succeda prima). Questo significa che non è necessario utilizzare i tipici approcci basati su ipotesi per l'analisi e la pianificazione della capacità.
Nel caso in cui le condizioni operative previste in produzione cambino (ad esempio se l'azienda ridefinisce i carichi medi e di picco previsti), non è necessario eseguire nuovamente i test delle prestazioni, poiché le metriche desiderate per i diversi carichi possono essere ottenute semplicemente tramite interpolazione o estrapolazione dei risultati dei test esistenti.
La copertura di tutto lo spettro di carichi anziché di poche grandezze predefinite consente di avere una visione completa delle prestazioni del sistema e di non trascurare eventuali problemi di prestazioni, evitando di testare il prodotto solo in condizioni estreme.
Assicurarsi che i test includano il raggiungimento dei breakpoint delle prestazioni del sistema significa sapere dove sono i colli di bottiglia, quale collegamento, componente o livello fallirà per primo via via che i carichi aumentano. Questo permette di fornire un feedback utile e basato su evidenze ai team di architettura e progettazione per migliorare la robustezza e le prestazioni del prodotto.
Esistono diversi tipi di test delle prestazioni che possono essere eseguiti su una soluzione. Una soluzione ben progettata li utilizza tutti.
L'obiettivo deve essere quello di ottenere il massimo dalla varietà di dati sulle prestazioni acquisiti durante i test: