Scalabilita — Cheat Sheet

Tag: scalability, architecture, distributed-systems, backend, performance, caching

Livello: intermedio

TL;DR: Principi di scaling orizzontale e verticale, gestione dello stato, caching, partizionamento dei dati e disaccoppiamento asincrono.

Concetti chiave

Scalabilita verticale (scale up): aumento di CPU, RAM o disco sulla singola istanza.

Scalabilita orizzontale (scale out): aggiunta di nodi computazionali dietro un load balancer.

Stateless architecture: delegare sessioni e stati ad archivi centralizzati per permettere scaling orizzontale istantaneo.

Load balancing: distribuzione del traffico tramite algoritmi Round Robin, Least Connections o IP Hash.

Caching multi-livello: memoria applicativa locale, cluster distribuiti (Redis/Memcached) e CDN edge caching.

Database scaling: replica in lettura (Read Replicas) per carichi read-heavy.

Database sharding: partizionamento orizzontale dei dati basato su shard key per write-heavy.

Disaccoppiamento asincrono: code di messaggi (RabbitMQ, Kafka, SQS) per livellare picchi e assorbire carichi improvvisi.

Database connection pooling: prevenzione dell'esaurimento socket sotto alto traffico concorrente.

Rate limiting e throttling: protezione dei servizi critici dal sovraccarico computazionale.

Domande tipiche e risposte pronte

Q: Come affronti il problema della scalabilita di una web application monolitica?R: Rimuovo lo stato in memoria spostando sessioni su Redis, introduco un reverse proxy/load balancer e configuro read replicas per le letture del database.

Q: Quando conviene scalare verticalmente rispetto a orizzontalmente?R: Lo scale up e' rapido e riduce la complessita architetturale iniziale, ma ha un tetto hardware; passo a scale out appena servono alta disponibilita e carichi distribuiti.

Q: Come gestisci i colli di bottiglia causati da scritture frequenti sul database?R: Implemento code asincrone per buffering, valuto sharding su base tenant/entita e uso scritture in batch o database orientati all'append-only.

Insidie e errori comuni

Salvare stato utente o file direttamente sul filesystem locale del server applicativo.

Mancanza di indici appropriati nel database scambiata erroneamente per saturazione hardware.

Thundering herd problem: scadenza simultanea di chiavi in cache che travolge il database primario.

Scelta errata della shard key, che porta a hotspot su un unico nodo del cluster.

Mancata gestione del backpressure nei consumer di messaggi asincroni.

Session stickiness prolungata sul load balancer che sbilancia il traffico tra nodi.

Snippet e comandiTypeScript

// Pattern cache-aside con fallback e time-to-live
async function getUserData(userId: string): Promise<User> {
  const cacheKey = `user:${userId}`;
  const cached = await redis.get(cacheKey);

  if (cached) {
    return JSON.parse(cached);
  }

  const user = await db.user.findUnique({ where: { id: userId } });
  if (user) {
    await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
  }
  return user;
}

Bash

# Test di carico rapido via Apache Bench per verificare throughput
ab -n 10000 -c 100 http://localhost:8080/api/health

Da ripassare

[ ] Pattern di caching: Read-Through, Write-Through e Write-Behind

[ ] Teorema CAP e implicazioni di consistenza eventuale

[ ] Algoritmi di consistent hashing per lo sharding

[x] Differenza pratica tra scale up e scale out

[x] Utilizzo di message broker per il livellamento del traffico

Jarvis Interviews
Jarvis