L’origine del problema C10K
Alla fine degli anni Novanta, con la crescita del traffico web, emerge un problema architetturale noto come C10K: come gestire diecimila connessioni concorrenti su un singolo server. I web server tradizionali come Apache HTTP Server utilizzano un modello process-per-connection o thread-per-connection: ogni connessione client richiede un processo o thread dedicato. Quando le connessioni crescono, il consumo di memoria e il context switching diventano il collo di bottiglia.
Nginx (pronunciato “engine-x”) nasce nel 2004 dal lavoro di Igor Sysoev, un amministratore di sistema russo che gestisce Rambler, uno dei siti più trafficati della Russia. La motivazione è pratica: servire un volume di traffico che il modello prefork di Apache non riesce a gestire in modo efficiente.
Architettura event-driven
Nginx adotta un’architettura radicalmente diversa. Un processo master gestisce la configurazione e coordina un piccolo numero di processi worker — tipicamente uno per core della CPU. Ogni worker utilizza un event loop asincrono basato su chiamate di sistema come epoll (Linux) o kqueue (FreeBSD) per gestire migliaia di connessioni in un singolo thread.
Il modello è non-bloccante: quando un worker avvia un’operazione di I/O — leggere un file, inviare dati a un client, attendere una risposta da un backend — non si ferma ad aspettare. Registra l’evento e passa a servire un’altra connessione. Al completamento dell’I/O, il sistema operativo notifica il worker tramite l’event loop.
Il risultato è un consumo di memoria prevedibile e contenuto: un processo worker Nginx occupa pochi megabyte di RAM indipendentemente dal numero di connessioni attive. Dove Apache con prefork potrebbe richiedere centinaia di megabyte per gestire migliaia di connessioni, Nginx ne utilizza una frazione.
Reverse proxy e load balancing
Oltre a servire contenuti statici con efficienza eccezionale, Nginx è progettato per funzionare come reverse proxy: riceve le richieste dai client e le inoltra a server backend — applicazioni FastCGI, server HTTP upstream, processi memcached. Questa architettura permette di separare il serving dei contenuti statici dalla logica applicativa.
Le funzionalità di load balancing distribuiscono le richieste su più server backend secondo algoritmi configurabili: round-robin, least connections, IP hash per la persistenza di sessione. Nginx gestisce anche il buffering delle risposte dai backend, liberando i processi applicativi non appena la risposta è generata.
Un’alternativa architetturale
Nginx non cerca di sostituire Apache in tutti i casi d’uso. Non supporta .htaccess per la configurazione distribuita e non ha un equivalente del sistema modulare di Apache. La sua forza è in uno scenario preciso: siti ad alto traffico dove la gestione efficiente delle connessioni concorrenti è il serving veloce di contenuti statici sono priorità. In questo scenario, l’architettura event-driven offre vantaggi misurabili in prestazioni, consumo di risorse e scalabilità.
Link: nginx.org
