☁ Cloud e DevOps

Autoscaling e bilanciamento del carico: reggere i picchi di traffico

Come funzionano bilanciatori di carico e autoscaling: scalabilità verticale e orizzontale, metriche, controlli di salute e applicazioni senza stato.

Un sito che regge cento visitatori contemporanei può crollare quando ne arrivano mille, magari perché un articolo è stato condiviso o è partita una campagna promozionale. Tenere sempre accesi i server necessari per il picco massimo è costoso; tenerne pochi è rischioso. Bilanciamento del carico e autoscaling servono a risolvere questo dilemma, adattando le risorse al traffico reale.

Due modi di crescere

Scalabilità verticale

Si sostituisce il server con uno più potente: più CPU, più memoria. È semplice, non richiede modifiche all'applicazione e funziona bene fino a un certo punto. I limiti sono tre: esiste comunque una macchina più grande possibile, il cambio di taglia richiede spesso un riavvio, e un unico server resta un punto singolo di guasto.

Scalabilità orizzontale

Si aggiungono altri server identici e si divide il lavoro tra loro. Non ha un limite teorico, permette di sopravvivere al guasto di una macchina e si può fare senza interruzioni. In cambio richiede che l'applicazione sia progettata per girare su più copie contemporaneamente, e un componente che distribuisca il traffico: il bilanciatore di carico.

Il bilanciatore di carico

Il load balancer riceve tutte le richieste e le distribuisce tra i server disponibili. I criteri di distribuzione più comuni sono:

  • round robin: le richieste vanno a turno a ogni server;
  • minor numero di connessioni: la richiesta va al server meno impegnato in quel momento;
  • hash dell'indirizzo o di un'intestazione: lo stesso client finisce sempre sullo stesso server.

I bilanciatori lavorano a due livelli diversi. Quelli di livello 4 smistano connessioni TCP o UDP senza guardarne il contenuto: sono veloci e generici. Quelli di livello 7 leggono le richieste HTTP e possono instradare in base a dominio, percorso o intestazioni, gestire i certificati e aggiungere informazioni.

I controlli di salute

Un bilanciatore senza health check continua a inviare richieste a un server bloccato. Con i controlli di salute, interroga periodicamente un indirizzo dell'applicazione, per esempio /health, e smette di usare i server che non rispondono correttamente, rimettendoli in rotazione quando tornano sani.

Un buon controllo di salute verifica che l'applicazione possa davvero servire richieste, ma senza dipendere da troppi servizi esterni: se il controllo fallisce ogni volta che un servizio secondario rallenta, il bilanciatore rischia di escludere tutti i server insieme.

Applicazioni senza stato

La scalabilità orizzontale funziona bene solo se ogni server può gestire qualsiasi richiesta. Questo significa che l'applicazione deve essere senza stato (stateless):

  • le sessioni degli utenti vanno salvate in un archivio condiviso, come Redis o il database, non nella memoria del singolo server;
  • i file caricati vanno in un object storage comune, non sul disco locale;
  • i lavori pianificati devono essere eseguiti da un solo server o coordinati, altrimenti girano tante volte quanti sono i server.

Esiste la scorciatoia delle sessioni appiccicose (sticky sessions), in cui il bilanciatore manda lo stesso utente sempre allo stesso server. Funziona, ma distribuisce il carico in modo meno uniforme e fa perdere le sessioni quando un server viene rimosso. È meglio considerarla una soluzione temporanea.

L'autoscaling

L'autoscaling aggiunge e toglie server automaticamente in base a una metrica. Si configura con pochi parametri:

Parametro Esempio Significato
Minimo 2 Numero di istanze sempre attive, anche di notte
Massimo 10 Tetto oltre il quale non si cresce, per contenere i costi
Metrica CPU media al 60% Valore che il sistema cerca di mantenere
Raffreddamento 5 minuti Attesa minima tra due interventi successivi

Il minimo di due istanze garantisce che un guasto non fermi il servizio. Il massimo protegge da un errore o da un attacco che farebbero crescere la spesa senza limiti.

Scegliere la metrica giusta

La CPU è la metrica più usata, ma non sempre la più adatta. Un'applicazione che passa la maggior parte del tempo ad aspettare il database può essere lenta con la CPU bassa. Alternative valide sono il numero di richieste per istanza, il tempo di risposta o, per i lavori in background, la lunghezza della coda da elaborare.

Tempi di reazione

Una nuova istanza non è pronta all'istante: deve avviarsi, caricare l'applicazione e superare i controlli di salute. Se servono quattro minuti e il picco arriva in trenta secondi, l'autoscaling interviene troppo tardi. Per questo aiutano immagini già pronte con tutto installato, applicazioni che si avviano in fretta e, per gli eventi prevedibili, un aumento programmato delle istanze prima che il traffico arrivi.

Il collo di bottiglia si sposta

Aggiungere server applicativi non serve se il limite è altrove. Spesso, quando le istanze raddoppiano, il database riceve il doppio delle connessioni e diventa lui il problema. Prima di affidarsi all'autoscaling conviene verificare con un test di carico dove il sistema cede davvero: database, cache, servizi esterni con limiti di richieste. Nel mio lavoro questo test rivela quasi sempre un collo di bottiglia inatteso, ed è molto meglio scoprirlo in prova che durante il picco.

In sintesi

  • La scalabilità verticale è semplice ma limitata; quella orizzontale richiede applicazioni progettate per più copie.
  • Il bilanciatore distribuisce le richieste ed esclude, grazie ai controlli di salute, i server non funzionanti.
  • Sessioni, file e lavori pianificati vanno gestiti fuori dal singolo server.
  • L'autoscaling si configura con minimo, massimo, metrica e tempo di raffreddamento, scelti con cura.
  • Un test di carico mostra dove si trova il vero collo di bottiglia prima che arrivi il picco.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica e in psicologia, unisce l'analisi tecnica alla comprensione del fattore umano.

Leggi anche