Questa risposta è complementare alle altre e spiega perché Unicorn ha bisogno di nginx di fronte .
TL; DR Il motivo per cui Unicorn viene solitamente distribuito insieme a un proxy inverso come nginx è perché i suoi creatori lo hanno deliberatamente progettato, facendo un compromesso per semplicità.
Prima di tutto, non c'è nulla che ti impedisca di distribuire Unicorn senza un proxy inverso. Tuttavia, non sarebbe una buona idea; vediamo perché.
Unicorn segue la filosofia Unix che consiste nel fare una cosa e farlo bene , e cioè nel servire clienti veloci a bassa latenza (vedremo cosa significa in seguito). Il fatto che Unicorn sia progettato per client veloci e a bassa latenza implica anche che non è molto buono con i client lenti e ad alta latenza , il che è vero. Questo è uno dei punti deboli di Unicorn ed è qui che entra in gioco un proxy inverso: si trova di fronte a Unicorn e si prende cura di quei client lenti (vedremo come seguito).
Fortunatamente, esiste già un proxy inverso che si chiama nginx .
La decisione di gestire solo client veloci, semplifica notevolmente la progettazione di Unicorn e consente una base di codice molto più semplice e più piccola, a scapito di una maggiore complessità nel reparto di distribuzione (ovvero, è necessario distribuire anche nginx oltre a Unicorn).
Una decisione alternativa potrebbe essere la progettazione di Unicorn in modo tale da non richiedere un proxy inverso. Tuttavia, ciò significa che dovrebbe implementare funzionalità extra per fare tutto ciò che ora nginx fa, risultando in una base di codice più complessa e maggiori sforzi di ingegneria.
Invece i suoi creatori hanno preso la decisione di sfruttare il software esistente che è stato testato in battaglia e ben progettato e di evitare di perdere tempo ed energia per problemi già risolti da altri software.
Ma diventiamo tecnici e rispondiamo alla tua domanda:
Perché Unicorn deve essere distribuito insieme a nginx?
Ecco alcuni dei motivi principali:
Unicorn utilizza I / O di blocco per i client
Affidarsi a un proxy inverso significa che Unicorn non ha bisogno di usare I / O non bloccanti. Può invece utilizzare l'I / O di blocco che è intrinsecamente più semplice e più facile da seguire per il programmatore.
Inoltre, come afferma il documento DESIGN :
[Utilizzo di I / O di blocco] consente di seguire un percorso del codice più semplice nell'interprete Ruby e meno syscall.
Tuttavia, ciò ha anche alcune conseguenze:
Punto chiave n. 1: Unicorn non è efficiente con client lenti
(Per semplicità, ipotizziamo una configurazione con 1 lavoratore Unicorn)
Poiché viene utilizzato l'I / O di blocco, un lavoratore Unicorn può servire solo un client alla volta , quindi un client lento (cioè uno con una connessione lenta) manterrebbe effettivamente il lavoratore occupato per un tempo più lungo (rispetto a un client veloce ). Nel frattempo, gli altri clienti avrebbero semplicemente aspettato che il lavoratore fosse di nuovo libero (cioè le richieste si accumulassero in coda).
Per ovviare a questo problema, viene distribuito un proxy inverso di fronte a Unicorn, che bufferizza completamente le richieste in arrivo e le risposte dell'applicazione e quindi invia ciascuna di esse contemporaneamente (ovvero le nutre con il cucchiaio) a Unicorn e ai client, rispettivamente. A tale proposito, si potrebbe dire che il proxy inverso "protegge" Unicorn dai client di rete lenti.
Fortunatamente Nginx è un ottimo candidato per questo ruolo, poiché è progettato per gestire in modo efficiente migliaia di centinaia di clienti simultanei.
È di fondamentale importanza che il proxy inverso si trovi all'interno della stessa rete locale di Unicorn (in genere nella stessa macchina fisica che comunica con Unicorn tramite un socket di dominio Unix), in modo che la latenza di rete sia ridotta al minimo.
Quindi un tale proxy svolge effettivamente il ruolo di un client veloce che Unicorn è progettato per servire in primo luogo, poiché inoltra rapidamente richieste a Unicorn e mantiene occupati i lavoratori per il minor tempo possibile (rispetto a quanto tempo un client con una connessione lenta farebbe).
Punto chiave n. 2: Unicorn non supporta keep-alive HTTP / 1.1
Poiché Unicorn utilizza l'I / O di blocco, significa anche che non può supportare la funzionalità keep-alive HTTP / 1.1, poiché le connessioni persistenti di client lenti occuperebbero rapidamente tutti i lavoratori Unicorn disponibili.
Pertanto, per sfruttare HTTP keep-alive, indovina un po ': viene utilizzato un proxy inverso.
nginx, d'altra parte, può gestire migliaia di connessioni simultanee usando solo pochi thread. Pertanto, non ha i limiti di concorrenza di un server come Unicorn (che essenzialmente si limita alla quantità di processi di lavoro), il che significa che può gestire bene connessioni persistenti. Maggiori informazioni su come funziona effettivamente possono essere trovate qui .
Ecco perché nginx accetta connessioni keep-alive dai client e li inoltra a Unicorn su connessioni semplici tramite un socket Unix.
Punto n. 3: Unicorn non è molto bravo a servire file statici
Ancora una volta, servire file statici è una cosa che Unicorn può fare ma non è progettato per funzionare in modo efficiente.
D'altra parte, i proxy inversi come nginx sono comunque molto più efficaci (ad es. sendfile(2)
E memorizzazione nella cache).
Di Più
Ci sono altri punti che sono delineati nel documento FILOSOFIA (vedi "Prestazioni migliorate attraverso il proxy inverso" ).
Vedi anche alcune delle funzionalità di base di nginx .
Vediamo che sfruttando il software esistente (es. Nginx) e seguendo la filosofia Unix di "fare una cosa e farlo bene", Unicorn è in grado di seguire una progettazione e un'implementazione più semplici mantenendo al contempo l'efficienza nel servire le app Rack (ad es. la tua app Rails).
Per ulteriori informazioni, consultare la filosofia e i documenti di progettazione di Unicorn che spiegano più in dettaglio le scelte alla base della progettazione di Unicorn e perché nginx è considerato un buon proxy inverso per Unicorn.