In sintesi: lo scaling orizzontale aggiunge istanze di server per distribuire i workloads anziché potenziare le singole macchine. È il fondamento di un'architettura cloud affidabile ed efficiente sul piano dei costi quando il traffico è imprevedibile, ma introduce complessità nella gestione dello stato, nel load balancing e nella configurazione dell'autoscaling che i team devono affrontare prima di raggiungere i limiti di capacità.
Ogni applicazione ha un tetto. Per un po' lo si può alzare potenziando l'hardware: più CPU, più RAM, storage più veloce. A un certo punto, però, un singolo server non riesce più a reggere il ritmo e il costo del potenziamento supera il valore che genera. È in quel momento che la scelta si sposta dallo scaling verticale a quello orizzontale.
Lo scaling orizzontale, ossia aggiungere più server per condividere il carico invece di ingrandirne uno solo, è l'architettura che fa funzionare la maggior parte delle applicazioni cloud moderne. È così che le applicazioni assorbono i picchi di traffico senza cedere, che i team costruiscono ridondanza senza eroismi ingegneristici e che i costi dell'infrastruttura restano proporzionali alla domanda reale invece che a proiezioni nello scenario peggiore.
Questa guida illustra come funziona lo scaling orizzontale, in quali casi ha senso e in quali no, e come i team CloudOps possono implementarlo su AWS, Google Cloud e Kubernetes senza barattare l'affidabilità con la complessità.
Che cos'è lo scaling orizzontale e come funziona?
Lo scaling orizzontale consiste nell'aggiungere più istanze di una risorsa per distribuire i workloads su più nodi, anziché aumentare la capacità di un singolo nodo. Mentre lo scaling verticale potenzia un singolo server (più core CPU, più memoria), quello orizzontale moltiplica il numero di server che gestiscono le richieste. Davanti alla flotta si colloca un load balancer che distribuisce il traffico in entrata sulle istanze disponibili, in modo che nessun nodo diventi un collo di bottiglia.
La meccanica cambia leggermente da piattaforma a piattaforma, ma lo schema resta lo stesso. Su AWS, gli Auto Scaling Groups monitorano le metriche di CloudWatch e avviano o terminano automaticamente le istanze EC2 quando l'utilizzo supera le soglie definite. Su Kubernetes, l'Horizontal Pod Autoscaler (HPA) osserva l'utilizzo di CPU e memoria (o metriche personalizzate) e regola di conseguenza il numero di pod in esecuzione. Su Google Cloud, i Managed Instance Groups svolgono la stessa funzione per i workloads su Compute Engine. In ogni caso, è un livello di controllo a prendere la decisione di scaling, evitando che debba farlo manualmente il team di ingegneria.
Quali sono le implicazioni in termini di prestazioni e capacità?
Lo scaling orizzontale trasforma il modello di capacità da un tetto fisso a un intervallo dinamico. Un sistema scalato verticalmente raggiunge un limite invalicabile quando il tipo di istanza più grande disponibile non basta più a reggere il carico. Un sistema scalato orizzontalmente, se configurato correttamente, può continuare ad aggiungere istanze finché non sono l'architettura o il budget a frenare la crescita.
Il vantaggio prestazionale si amplifica con la distribuzione geografica. Eseguire istanze in più zone di disponibilità significa che il guasto di una singola zona non manda offline l'applicazione: il traffico viene reindirizzato attorno alla zona compromessa mentre le istanze sostitutive si avviano. Il compromesso è la latenza tra nodi: le istanze distribuite che devono comunicare pagano il costo di un round-trip di rete che una configurazione su server singolo non ha, un aspetto critico per le operazioni sensibili alla latenza.
In che modo lo scaling orizzontale incide su costi e gestione delle risorse?
Lo scaling orizzontale allinea il costo dell'infrastruttura alla domanda effettiva in modo più preciso rispetto a quello verticale. Un server scalato verticalmente gira sempre alla dimensione provisionata, indipendentemente dal traffico. Una flotta scalata orizzontalmente può ridursi nelle ore di minor carico ed espandersi durante i picchi, pagando tariffe on-demand per la capacità transitoria e tariffe a riserva per la baseline prevedibile.
Questo allineamento regge, però, solo se le policy di autoscaling sono ben calibrate. Soglie di scale-out mal configurate che si attivano troppo presto, o policy di scale-in che non dismettono le istanze abbastanza in fretta, trasformano il vantaggio di costo in spreco. Una combinazione di pricing basato su commitments per la flotta di baseline (AWS Savings Plans, sconti per uso impegnato su GCP) e capacità on-demand per assorbire i picchi offre alla maggior parte dei team il miglior profilo di costo.
Nel caso specifico dei workloads Kubernetes, il right-sizing di request e limit dei pod conta quanto la policy di scaling stessa. Pod con request di risorse gonfiate compromettono l'efficienza del bin-packing e costringono il cluster a usare più nodi di quelli effettivamente necessari al workload. DoiT PerfectScale for Kubernetes evidenzia automaticamente queste opportunità di right-sizing, individuando i casi in cui le request dei pod non riflettono i pattern d'uso reali.
Quale complessità operativa introduce lo scaling orizzontale?
Più istanze significano più superficie da gestire. Configuration drift, patching su tutta la flotta, aggregazione dei log e distributed tracing diventano molto più difficili rispetto a un singolo server. I team che non si sono attrezzati se ne accorgono subito, quando un bug compare su un tipo di istanza e non su un altro, o quando bisogna correlare i log di 40 pod per ricostruire il percorso di una singola richiesta.
Gli strumenti infrastructure-as-code (Terraform, Pulumi, CloudFormation) sono la mitigazione di base. I pattern di infrastruttura immutabile, in cui le istanze vengono sostituite a partire da un'immagine known-good anziché modificate sul posto, eliminano il configuration drift. Logging centralizzato e distributed tracing rendono gestibile il debug multi-istanza.
Come si confronta lo scaling orizzontale con quello verticale per i team CloudOps?
Scaling verticale (scaling up) e scaling orizzontale (scaling out) non si escludono a vicenda. La maggior parte delle architetture di produzione li usa entrambi: istanze opportunamente dimensionate per il workload, in esecuzione all'interno di una flotta scalata orizzontalmente. Il punto decisionale è quale leva azionare per prima quando la capacità diventa un vincolo.
Lo scaling verticale è più rapido da implementare e non richiede modifiche all'applicazione. Si aggiunge CPU e memoria a un'istanza esistente, si riavvia se necessario e il gioco è fatto. Funziona bene per workloads difficili da distribuire: processi single-thread, applicazioni con forti dipendenze di stato o sistemi legacy non progettati per girare su più istanze. Il tetto è il tipo di istanza più grande disponibile e il costo non scala in proporzione alla domanda.
Lo scaling orizzontale presuppone invece che l'applicazione sia pronta. I servizi stateless, in cui ogni richiesta porta con sé tutto il contesto necessario al server e nessuno stato locale persiste tra una richiesta e l'altra, si distribuiscono bene su qualsiasi numero di istanze. I servizi stateful, in cui l'applicazione memorizza dati di sessione o stato in-process a livello locale, richiedono un'architettura aggiuntiva per funzionare correttamente su una flotta.
Perché le applicazioni stateless sono ideali per lo scaling orizzontale?
Le applicazioni stateless sono la destinazione naturale dello scaling orizzontale, perché qualsiasi istanza può gestire qualsiasi richiesta. Un load balancer può distribuire il traffico in round-robin sulla flotta senza alcuna logica di routing oltre ai controlli di disponibilità. Quando il traffico cresce, nuove istanze si avviano e prendono carico subito. Quando il traffico cala, le istanze terminano senza compromettere alcuno stato in transito.
La maggior parte dei tier web moderni, dei livelli API e dei microservizi è stateless per progettazione. Un'API REST che legge da un database condiviso non si preoccupa di quale server elabori la richiesta. Un microservizio containerizzato che legge da una coda e scrive i risultati su un object storage scala orizzontalmente senza bisogno di coordinamento aggiuntivo, e l'autoscaling mantiene la capacità proporzionale alla domanda senza interventi manuali.
Dove generano criticità i database e i workloads stateful?
Database e servizi stateful non scalano orizzontalmente per impostazione predefinita. Un database relazionale in esecuzione su una singola istanza primaria non può semplicemente essere replicato su cinque nodi pretendendo di gestire un throughput in scrittura cinque volte superiore. Le letture possono scalare orizzontalmente tramite read replica, ma le scritture continuano a passare per il primario, e questo rende i workloads write-intensive un collo di bottiglia a prescindere dal numero di repliche.
I team aggirano il problema partizionando lo stato in un livello condiviso, un database managed, una cache distribuita come Redis o un object store, accessibile a tutte le istanze. I dati di sessione finiscono su Redis o DynamoDB. Gli upload di file vanno su S3 o Cloud Storage. Questa architettura a stato condiviso rende il tier applicativo davvero stateless, preservando al tempo stesso i dati di cui ha bisogno.
In ambito Kubernetes, i workloads stateful che richiedono storage persistente usano gli StatefulSet anziché i Deployment. Gli StatefulSet assegnano a ciascun pod un'identità di rete stabile e una persistent volume claim, un requisito fondamentale per database, code e altri servizi stateful e ordinati.
Quando funziona lo scaling orizzontale e quando no?
Lo scaling orizzontale dà i suoi frutti in condizioni specifiche: pattern di traffico imprevedibili o con picchi, tier applicativi stateless, microservizi distribuiti e workloads con requisiti di disponibilità che impongono ridondanza. In altre condizioni offre meno valore e, in alcuni casi, crea nuovi problemi.
Workloads containerizzati e microservizi sono il caso d'uso più adatto. Ogni servizio scala in modo indipendente in base alla propria domanda, evitando che un picco in una parte del sistema comporti l'over-provisioning del resto. Un cluster Kubernetes con 20 microservizi può scalare ciascun servizio in autonomia, mantenendo elevato l'utilizzo delle risorse senza dover dimensionare tutto sul carico di picco. L'Horizontal Pod Autoscaler di Kubernetes offre ai team un controllo granulare su queste policy di scaling, comprese metriche personalizzate oltre a CPU e memoria.
Le architetture event-driven si prestano particolarmente bene allo scaling orizzontale. Una flotta di worker che consuma da una coda può espandersi e contrarsi in base alla profondità della coda, elaborando i burst senza ritardo e rilasciando istanze quando la coda si svuota. Strumenti come KEDA (Kubernetes Event-Driven Autoscaling) estendono nativamente questo pattern a Kubernetes, scalando i pod in base a sorgenti di eventi esterne come la lunghezza di una coda SQS o il lag di un consumer Kafka.
Quali scelte di load balancing e distribuzione del traffico pesano di più?
Il load balancer è il punto di ingresso di tutto il traffico verso una flotta scalata orizzontalmente, e questo rende la sua configurazione un fattore diretto del comportamento applicativo. La distribuzione round-robin funziona per i servizi stateless in cui tutte le istanze sono equivalenti. Il routing least-connection funziona meglio quando il tempo di elaborazione delle richieste varia in modo significativo, indirizzando le nuove connessioni all'istanza con maggiore capacità disponibile.
Gli health check sono il perno operativo. Un load balancer che invia traffico a un'istanza non integra vanifica il senso stesso di avere una flotta. Gli health check devono verificare la reale readiness dell'applicazione (un endpoint HTTP effettivo che controlla la disponibilità delle dipendenze) e non limitarsi a verificare se l'istanza risponde a una connessione TCP. Health check mal configurati, troppo permissivi o troppo rigidi, generano flapping ed eventi di scaling inutili.
In che modo gestione delle sessioni e consistenza dei dati incidono sullo scaling orizzontale?
La gestione delle sessioni è il punto in cui molte implementazioni di scaling orizzontale si rompono. Un'applicazione che conserva i dati di sessione in memoria locale funziona benissimo su un singolo server. Distribuita su una flotta, la seconda richiesta dello stesso utente potrebbe atterrare su un'istanza diversa che non sa nulla della sessione precedente, e questo provoca fallimenti di autenticazione o la perdita dello stato del carrello.
La soluzione è esternalizzare lo stato di sessione. Redis e Memcached sono le scelte standard per lo storage di sessioni distribuite. Il tier applicativo diventa davvero stateless, perché legge e scrive i dati di sessione sulla cache condivisa anziché in memoria locale. Tutte le istanze vedono lo stesso stato di sessione, indipendentemente da quale elabori la richiesta. Si aggiunge un round-trip di rete per ogni lettura di sessione: un compromesso ragionevole per ottenere scalabilità orizzontale nella maggior parte delle applicazioni.
La consistenza dei dati su istanze distribuite richiede una progettazione esplicita per i workloads write-intensive. Locking distribuito, optimistic concurrency control o pattern di event sourcing affrontano il problema del coordinamento in funzione dei requisiti di consistenza.
Quali scelte di monitoraggio e configurazione dell'autoscaling determinano il successo?
Le policy di autoscaling valgono quanto le metriche che le guidano. L'utilizzo della CPU è la metrica di default per la maggior parte dei servizi managed di autoscaling, ma per molti workloads è un indicatore in ritardo. Un'applicazione sotto pressione di memoria o con backlog in coda può mostrare un utilizzo di CPU normale fino al momento in cui collassa. Metriche personalizzate (profondità della coda di richieste, percentili di latenza, numero di connessioni attive) forniscono alle policy di autoscaling segnali più tempestivi e accurati.
Le policy di scale-out dovrebbero essere aggressive: meglio fare over-provisioning per breve tempo che lasciare degradare l'esperienza utente durante un picco. Le policy di scale-in, al contrario, dovrebbero essere prudenti, con periodi di cooldown e decrementi graduali, per evitare di terminare istanze troppo in fretta dopo un picco. Una flotta che riduce le istanze troppo rapidamente durante un pattern di traffico oscillante tra carico alto e normale entra in thrashing, accendendo e spegnendo continuamente istanze a costo.
La guida all'ottimizzazione dei costi Kubernetes approfondisce come allineare la configurazione dell'autoscaling all'efficienza dei costi, comprese le resource quota a livello di namespace e i pattern di integrazione con il VPA.
Come implementare i pattern di scaling orizzontale ed evitare le insidie più comuni?
L'implementazione segue una sequenza coerente a prescindere dalla piattaforma: validare la natura stateless dell'applicazione, configurare il gruppo di scaling, impostare le policy e fare i test prima che il traffico di produzione vi faccia affidamento.
Su AWS lo stack è composto da Auto Scaling Groups con istanze EC2 (o task ECS per workloads containerizzati), un Application Load Balancer e CloudWatch alarm che guidano le policy di scaling. Le scelte di configurazione critiche sono il numero minimo e massimo di istanze, la metrica di utilizzo target e i periodi di cooldown di scale-in e scale-out. Per un riferimento dettagliato sulla configurazione EC2, la guida a costi, benefici e best practice di AWS EC2 approfondisce la scelta delle istanze e l'ottimizzazione dei costi.
Su Google Cloud, i Managed Instance Groups con policy di autoscaling e un Global External Application Load Balancer offrono lo stack equivalente. I cluster GKE aggiungono l'autoscaling nativo di Kubernetes, con il Cluster Autoscaler che gestisce il numero di nodi e l'HPA che gestisce il numero di pod in modo indipendente.
Su Kubernetes, su qualsiasi cloud, l'architettura aggiunge un ulteriore livello di astrazione. I Deployment definiscono lo stato desiderato dei pod, l'HPA regola il numero di replica in base alle metriche e il Cluster Autoscaler o Karpenter regolano il numero di nodi in base alla pressione di scheduling dei pod. Per i team che costruiscono un'architettura Kubernetes da zero, Kubernetes architecture explained è un riferimento di base utile.
Le insidie più comuni non derivano dalla configurazione di scaling in sé, ma da assunzioni applicative che si rompono in regime distribuito: hostname hardcoded, scritture su filesystem locale, cache in-process che divergono tra istanze e chiamate sincrone a servizi che non scalano allo stesso ritmo. Individuare queste assunzioni prima che l'applicazione vada in produzione evita la sessione di debug che altrimenti scatta durante un picco di traffico.
I Forward Deployed Engineers di DoiT lavorano direttamente con i team CloudOps su questi pattern di implementazione, validando le assunzioni architetturali e configurando policy di scaling allineate al comportamento reale del traffico.
In che modo lo scaling orizzontale sostiene operazioni cloud resilienti?
Lo scaling orizzontale è l'infrastruttura adatta alla realtà del traffico che la maggior parte delle applicazioni cloud si trova ad affrontare davvero: domanda difficile da prevedere, picchi che arrivano senza preavviso e requisiti di disponibilità che non tollerano single point of failure. Una flotta in grado di crescere quando il traffico arriva e di contrarsi quando passa gestisce questa realtà senza che un ingegnere debba intervenire a ogni evento di scaling.
La maturità operativa che fa funzionare lo scaling orizzontale non è una singola modifica di configurazione. È un insieme di pratiche: progettazione applicativa stateless, gestione esternalizzata dello stato, autoscaling guidato da metriche, infrastructure-as-code e strumenti di observability che rendono debuggabile una flotta distribuita. I team che adottano queste pratiche per tempo scalano senza drammi. Quelli che le saltano scalano direttamente verso gli incidenti.
DoiT lavora con i team CloudOps in ogni fase di questo percorso, dall'architettura iniziale dei cluster Kubernetes al right-sizing e all'ottimizzazione dell'autoscaling per flotte consolidate. DoiT PerfectScale for Kubernetes analizza in modo continuo i workloads dei cluster e propone raccomandazioni di right-sizing e scaling, così i team dedicano meno tempo al tuning manuale e più tempo al lavoro che fa avanzare il business. Parli con un ingegnere DoiT per scoprire come questo approccio si applica alla sua architettura.
Domande frequenti sullo scaling orizzontale
Qual è la differenza tra scaling orizzontale e verticale?
Lo scaling orizzontale aggiunge più istanze di una risorsa (più server, più pod, più nodi) per distribuire i workloads. Lo scaling verticale aumenta la capacità di un'istanza esistente (più CPU, più RAM). Lo scaling orizzontale gestisce una domanda imprevedibile e garantisce ridondanza. Lo scaling verticale è più semplice da implementare, ma ha un tetto invalicabile dato dalla dimensione massima di istanza disponibile.
Quando un team CloudOps dovrebbe scegliere lo scaling orizzontale rispetto a quello verticale?
Lo scaling orizzontale funziona al meglio per tier applicativi stateless, microservizi e workloads con traffico variabile o imprevedibile. Lo scaling verticale è più adatto a processi single-thread, applicazioni legacy che non riescono a distribuire lo stato o workloads che richiedono un rapido incremento di capacità senza modifiche applicative. La maggior parte delle architetture di produzione usa istanze opportunamente dimensionate (scaling verticale) all'interno di una flotta scalata orizzontalmente.
Lo scaling orizzontale riduce automaticamente i costi?
Non automaticamente. Lo scaling orizzontale allinea il costo alla domanda meglio di un grande server di dimensione fissa, ma solo se le policy di autoscaling sono ben calibrate e la flotta di baseline usa pricing basato su commitments. Policy di scale-in mal configurate che lasciano istanze attive dopo il calo del traffico, o soglie di scale-out troppo prudenti che richiedono interventi manuali durante i picchi, erodono il vantaggio di costo.
Come gestisce Kubernetes lo scaling orizzontale?
Kubernetes usa l'Horizontal Pod Autoscaler (HPA) per regolare il numero di replica di pod in esecuzione in base all'utilizzo di CPU, memoria o metriche personalizzate. Il Cluster Autoscaler (o Karpenter su AWS) regola il numero di nodi in base alla domanda di scheduling dei pod. I due controller lavorano in tandem: l'HPA scala il livello applicativo, il node autoscaler scala l'infrastruttura sottostante per ospitarlo.
Qual è l'errore di implementazione più grande che i team CloudOps commettono con lo scaling orizzontale?
Dare per scontato che l'applicazione sia stateless quando non lo è. Scritture su filesystem locale, storage di sessione in memoria e cache in-process generano stato nascosto che si rompe quando le richieste dello stesso utente atterrano su istanze diverse. Verificare l'applicazione alla ricerca di queste assunzioni prima di scalare la flotta evita che il problema si manifesti in produzione.