La parola "spiegamento" può avere due significati a seconda del contesto. Stai anche confondendo i ruoli di Apache / Nginx con i ruoli di altri componenti.
Nota storica: questo articolo è stato originariamente scritto il 6 novembre 2010, quando l'ecosistema del server delle app Ruby era limitato. Ho aggiornato questo articolo il 15 marzo 2013 con tutti gli ultimi aggiornamenti nell'ecosistema.
Disclaimer : sono uno degli autori di Phusion Passenger, uno dei server delle app.
Apache vs Nginx
Sono entrambi server web. Possono servire file statici ma - con i moduli giusti - possono anche servire app web dinamiche, ad esempio quelle scritte in PHP. Apache è più popolare e ha più funzionalità, Nginx è più piccolo e più veloce e ha meno funzionalità.
Né Apache né Nginx sono in grado di offrire app Web Ruby pronte all'uso, per fare ciò è necessario utilizzare Apache / Nginx in combinazione con un qualche tipo di componente aggiuntivo, descritto più avanti.
Apache e Nginx possono anche fungere da proxy inversi, il che significa che possono prendere una richiesta HTTP in arrivo e inoltrarla a un altro server, che parla anche HTTP. Quando quel server risponde con una risposta HTTP, Apache / Nginx inoltrerà la risposta al client; Imparerai in seguito perché questo è rilevante.
Mongrel e altri server di app di produzione vs WEBrick
Mongrel è un "application server" di Ruby: in termini concreti ciò significa che Mongrel è un'applicazione che:
- Carica la tua app Ruby nel suo spazio di processo.
- Imposta un socket TCP, consentendogli di comunicare con il mondo esterno (ad es. Internet). Mongrel ascolta le richieste HTTP su questo socket e passa i dati della richiesta all'app Web Ruby.
- L'app Web Ruby restituisce quindi un oggetto, che descrive come dovrebbe essere la risposta HTTP e Mongrel si occupa di convertirlo in una risposta HTTP effettiva (i byte effettivi) e lo restituisce sul socket.
Tuttavia Mongrel è piuttosto datato, al giorno d'oggi non è più mantenuto. I server di applicazioni alternative più recenti sono:
- Passeggero Phusion
- Unicorno
- Magro
- Puma
- Trinidad (solo JRuby)
- TorqueBox (solo JRuby)
Li tratterò più avanti e descriverò come differiscono l'uno dall'altro e da Mongrel.
WEBrick fa la stessa cosa di Mongrel, ma le differenze sono:
- WEBrick non è adatto alla produzione, a differenza di tutto ciò che ho menzionato prima. WEBrick è interamente scritto in Ruby. Mongrel (e la maggior parte degli altri server di app Ruby) è parte Ruby e parte C (Mostly Ruby), ma il suo parser HTTP è scritto in C per le prestazioni.
- WEBrick è più lento e meno robusto. Ha alcune perdite di memoria note e alcuni problemi di analisi HTTP noti.
- Di solito WEBrick viene utilizzato solo come server predefinito durante lo sviluppo poiché WEBrick è incluso in Ruby per impostazione predefinita. Mongrel e altri server app devono essere installati separatamente. Non è consigliabile utilizzare WEBrick negli ambienti di produzione, sebbene per qualche ragione Heroku abbia scelto WEBrick come server predefinito. Stavano usando Thin prima, quindi non ho idea del perché siano passati a WEBrick.
L'app server e il mondo
Tutti gli attuali server di app Ruby parlano HTTP, tuttavia alcuni server di app potrebbero essere direttamente esposti a Internet sulla porta 80, mentre altri potrebbero non esserlo.
- Server di app che possono essere direttamente esposti a Internet: Phusion Passenger, Rainbows
- Server di app che potrebbero non essere direttamente esposti a Internet: Mongrel, Unicorn, Thin, Puma. Questi server di app devono essere inseriti in un server Web proxy inverso come Apache e Nginx.
- Non so abbastanza su Trinidad e TorqueBox, quindi li ho omessi.
Perché alcuni server di app devono essere messi dietro un proxy inverso?
- Alcuni server di app possono gestire solo 1 richiesta contemporaneamente, per processo. Se si desidera gestire 2 richieste contemporaneamente, è necessario eseguire più istanze del server delle app, ognuna delle quali serve la stessa app Ruby. Questo insieme di processi del server delle app è chiamato cluster del server delle app (da cui il nome Mongrel Cluster, Thin Cluster, ecc.). È quindi necessario configurare Apache o Nginx per invertire il proxy in questo cluster. Apache / Nginx si occuperà della distribuzione delle richieste tra le istanze nel cluster (Maggiori informazioni al riguardo nella sezione "Modelli di concorrenza I / O").
- Il web server può bufferizzare richieste e risposte, proteggendo l'app server da "client lenti" - client HTTP che non inviano o accettano dati molto rapidamente. Non si desidera che l'app server non faccia nulla durante l'attesa che il client invii la richiesta completa o riceva la risposta completa, poiché durante tale periodo il server dell'app potrebbe non essere in grado di fare altro. Apache e Nginx sono molto bravi a fare molte cose contemporaneamente perché sono multithread o eventi.
- La maggior parte dei server delle app possono servire file statici, ma non sono particolarmente bravi. Apache e Nginx possono farlo più velocemente.
- Le persone in genere impostano Apache / Nginx per servire direttamente i file statici, ma inoltrare richieste che non corrispondono ai file statici al server delle app, è una buona pratica di sicurezza. Apache e Nginx sono molto maturi e possono proteggere il server delle applicazioni da richieste corrotte (forse maliziosamente).
Perché alcuni server di app possono essere esposti direttamente a Internet?
- Phusion Passenger è una bestia molto diversa da tutti gli altri server di app. Una delle sue caratteristiche uniche è che si integra nel web server.
- L'autore di Rainbows ha dichiarato pubblicamente che è sicuro esporlo direttamente a Internet. L'autore è abbastanza sicuro che non ci siano vulnerabilità nel parser HTTP (e simili). Tuttavia, l'autore non fornisce alcuna garanzia e afferma che l'utilizzo è a proprio rischio.
Server delle applicazioni a confronto
In questa sezione comparerò la maggior parte dei server delle applicazioni che ho citato, ma non Phusion Passenger. Phusion Passenger è una bestia così diversa dalle altre che gli ho dato una sezione dedicata. Ho anche omesso Trinidad e TorqueBox perché non li conosco abbastanza bene, ma sono comunque rilevanti solo se usi JRuby.
- Mongrel era piuttosto ossuto. Come accennato in precedenza, Mongrel è un multi-processo puramente a thread singolo, quindi è utile solo in un cluster. Non esiste un monitoraggio dei processi: se un processo nel cluster si arresta in modo anomalo (ad esempio a causa di un bug nell'app), è necessario riavviarlo manualmente. Le persone tendono a utilizzare strumenti di monitoraggio dei processi esterni come Monit e God.
- Unicorn è una forchetta di Mongrel. Supporta un monitoraggio limitato del processo: se un processo si arresta in modo anomalo viene automaticamente riavviato dal processo principale. Può far ascoltare tutti i processi su un singolo socket condiviso, anziché su un socket separato per ogni processo. Questo semplifica la configurazione del proxy inverso. Come Mongrel, è un multi-processo a thread singolo.
- Thin utilizza il modello I / O con eventi utilizzando la libreria EventMachine. Oltre a utilizzare il parser Mongrel HTTP, non si basa in alcun modo su Mongrel. La modalità cluster non prevede il monitoraggio dei processi, pertanto è necessario monitorare gli arresti anomali, ecc. Non esiste un socket condiviso simile all'unicorno, quindi ogni processo è in ascolto sul proprio socket. In teoria, il modello I / O di Thin consente un'elevata concorrenza, ma nella maggior parte delle situazioni pratiche in cui viene utilizzato Thin, un processo Thin può gestire solo 1 richiesta simultanea, quindi è ancora necessario un cluster. Maggiori informazioni su questa proprietà peculiare nella sezione "Modelli di concorrenza I / O".
- Anche Puma è stato biforcuto da Mongrel, ma a differenza dell'unicorno, Puma è progettato per essere multi-thread. Pertanto, attualmente non esiste alcun supporto cluster incorporato. È necessario prestare particolare attenzione per assicurarsi di poter utilizzare più core (Ulteriori informazioni al riguardo nella sezione "Modelli di concorrenza I / O").
- Rainbows supporta più modelli di concorrenza attraverso l'uso di diverse librerie.
Passeggero Phusion
Phusion Passenger funziona in modo molto diverso da tutti gli altri. Phusion Passenger si integra direttamente in Apache o Nginx e quindi può essere paragonato a mod_php per Apache. Proprio come mod_php consente ad Apache di servire app PHP, quasi magicamente, Phusion Passenger consente ad Apache (e anche a Nginx!) Di servire app Ruby, quasi magicamente. L'obiettivo di Phusion Passenger è quello di fare tutto Just Work (tm) con il minor fastidio possibile.
Invece di avviare un processo o un cluster per la tua app e configurare Apache / Nginx per servire file statici e / o invertire richieste di proxy al processo / cluster con Phusion Passenger devi solo:
- Modifichi il file di configurazione del web server e specifichi la posizione della directory 'pubblica' della tua app Ruby.
- Non c'è passaggio 2.
Tutta la configurazione viene eseguita all'interno del file di configurazione del server Web. Phusion Passenger automatizza praticamente tutto. Non è necessario avviare un cluster e gestire i processi. Avvio / arresto dei processi, riavvio in caso di arresto anomalo, ecc., Tutto automatizzato. Rispetto ad altri server di app, Phusion Passenger ha molte meno parti mobili. Questa facilità d'uso è uno dei motivi principali per cui le persone usano Phusion Passenger.
A differenza di altri server di app, Phusion Passenger è principalmente scritto in C ++, rendendolo molto veloce.
Esiste anche una variante Enterprise di Phusion Passenger con ancora più funzionalità, come riavvii automatici, supporto multithreading, resistenza agli errori di distribuzione, ecc.
Per i motivi di cui sopra, Phusion Passenger è attualmente il server di app Ruby più popolare, che alimenta oltre 150.000 siti Web, inclusi quelli di grandi dimensioni come New York Times, Pixar, Airbnb, ecc.
Phusion Passenger contro altri server di app
Phusion Passenger offre molte più funzioni e offre molti vantaggi rispetto ad altri server di app, come:
- Regolazione dinamica del numero di processi in base al traffico. Eseguiamo un sacco di app Rails sul nostro server con risorse limitate che non sono rivolte al pubblico e che le persone della nostra organizzazione usano al massimo poche volte al giorno. Cose come Gitlab, Redmine, ecc. Phusion Passenger può abbattere quei processi quando non vengono utilizzati e avviarli quando vengono utilizzati, consentendo a più risorse di essere disponibili per le app più importanti. Con altri server di app, tutti i processi sono sempre attivi.
- Alcuni server di app non sono adatti a determinati carichi di lavoro, in base alla progettazione. Ad esempio, Unicorn è progettato solo per richieste a esecuzione rapida: vedere la sezione del sito Web Unicorn "Solo peggio in alcuni casi".
I carichi di lavoro in cui Unicorn non è bravo sono:
- Carichi di lavoro in streaming (ad es. Streaming live di Rails 4 o streaming modello di Rails 4).
- Carichi di lavoro in cui l'app esegue chiamate API HTTP.
Il modello I / O ibrido in Phusion Passenger Enterprise 4 o versione successiva lo rende una scelta eccellente per questi tipi di carichi di lavoro.
- Altri server di app richiedono che l'utente esegua almeno un'istanza per applicazione. Al contrario, Phusion Passenger supporta più applicazioni in un'unica istanza. Ciò riduce notevolmente i costi amministrativi.
- Commutazione automatica dell'utente, una comoda funzione di sicurezza.
- Phusion Passenger supporta molte risonanze magnetiche Ruby, JRuby e Rubinius. Mongrel, Unicorn e Thin supportano solo la risonanza magnetica. Puma supporta anche tutti e 3.
- Phusion Passenger in realtà supporta più di un semplice Ruby! Supporta anche Python WSGI, quindi può ad esempio eseguire anche app Django e Flask. In realtà Phusion Passenger si sta muovendo nella direzione di diventare un server poliglotta. Supporto Node.js nell'elenco delle cose da fare.
- Garbage Collection fuori banda. Phusion Passenger può eseguire il Garbage Collector Ruby al di fuori del normale ciclo di richiesta / risposta, riducendo potenzialmente i tempi di richiesta di centinaia di millisecondi. Unicorn ha anche una funzione simile, ma la versione di Phusion Passenger è più flessibile perché 1) non è limitata a GC e può essere utilizzata per lavori arbitrari. 2) La versione di Phusion Passenger funziona bene con le app multithread, mentre quella di Unicorn no.
- Riavvio automatico a rotazione. Il riavvio a rotazione su Unicorn e altri server richiede un lavoro di scripting. Phusion Passenger Enterprise si automatizza completamente in questo modo per te.
Ci sono più funzionalità e vantaggi, ma l'elenco è davvero lungo. Per informazioni, consultare il manuale completo di Phusion Passenger ( versione Apache , versione Nginx ) o il sito Web di Phusion Passenger .
Modelli di concorrenza I / O
- Multiprocesso a thread singolo. Questo è tradizionalmente il modello I / O più popolare per i server di app Ruby, in parte perché il supporto del multithreading nell'ecosistema Ruby era pessimo. Ogni processo può gestire esattamente 1 richiesta alla volta. Il carico del server Web si bilancia tra i processi. Questo modello è molto robusto e ci sono poche possibilità per il programmatore di introdurre bug di concorrenza. Tuttavia, la sua concorrenza I / O è estremamente limitata (limitata dal numero di processi). Questo modello è molto adatto per carichi di lavoro veloci e di breve durata. Non è molto adatto per carichi di lavoro I / O di blocco lenti e di lunga durata, ad esempio carichi di lavoro che coinvolgono la chiamata di API HTTP.
- Puramente multi-thread. Oggi l'ecosistema Ruby ha un eccellente supporto multithreading, quindi questo modello I / O è diventato molto praticabile. Il multithreading consente una concorrenza I / O elevata, rendendola adatta per carichi di lavoro I / O di blocco sia di breve che di lunga durata. È più probabile che il programmatore introduca bug di concorrenza, ma per fortuna la maggior parte dei framework web sono progettati in modo tale che è ancora molto improbabile. Una cosa da notare tuttavia è che l'interprete Ruby MRI non può sfruttare più core della CPU anche quando ci sono più thread, a causa dell'uso del Global Interpreter Lock (GIL). È possibile aggirare il problema utilizzando più processi multi-thread, poiché ogni processo può sfruttare un core della CPU. JRuby e Rubinius non hanno GIL, quindi possono sfruttare appieno più core in un unico processo.
- Multi-processo ibrido multi-thread. Implementato principalmente da Phusion Passenger Enterprise 4 e versioni successive. È possibile passare facilmente da un processo multiprocesso a thread singolo, a un processo multithread o forse anche a processi multipli, ciascuno con più thread. Questo modello offre il meglio di entrambi i mondi.
- Evented. Questo modello è completamente diverso dal modello precedentemente citato. Consente una concorrenza I / O molto elevata ed è quindi eccellente per i carichi di lavoro I / O di blocco a lungo termine. Per utilizzarlo, è richiesto il supporto esplicito dall'applicazione e dal framework. Tuttavia, tutti i principali framework come Rails e Sinatra non supportano il codice evented. Questo è il motivo per cui in pratica un processo Thin non è ancora in grado di gestire più di 1 richiesta alla volta, rendendolo efficacemente uguale al modello multi-processo a thread singolo. Esistono framework specializzati che possono trarre vantaggio dall'eventuale I / O, come Cramp.
Di recente è stato pubblicato un articolo sul blog di Phusion sull'ottimizzazione ottimale del numero di processi e thread in base al carico di lavoro. Vedi Ottimizzazione delle impostazioni di concorrenza di Phusion Passenger .
Capistrano
Capistrano è qualcosa di completamente diverso. In tutte le sezioni precedenti, "distribuzione" si riferisce all'atto di avviare l'app Ruby in un server delle applicazioni, in modo che diventi accessibile ai visitatori, ma prima che ciò possa accadere in genere è necessario eseguire alcuni lavori di preparazione, come:
- Caricamento del codice e dei file dell'app Ruby sul computer server.
- Installazione di librerie da cui dipende la tua app.
- Impostazione o migrazione del database.
- Avvio e arresto di tutti i demoni su cui l'app potrebbe fare affidamento, come i lavoratori Sidekiq / Resque o altro.
- Qualsiasi altra cosa che deve essere eseguita durante la configurazione dell'applicazione.
Nel contesto di Capistrano, "spiegamento" si riferisce a fare tutto questo lavoro di preparazione. Capistrano non è un server applicazioni. Invece, è uno strumento per automatizzare tutto quel lavoro di preparazione. Indichi a Capistrano dove si trova il tuo server e quali comandi devono essere eseguiti ogni volta che distribuisci una nuova versione della tua app e Capistrano si occuperà di caricare l'app Rails sul server e di eseguire i comandi che hai specificato.
Capistrano viene sempre utilizzato in combinazione con un server applicazioni. Non sostituisce i server delle applicazioni. Viceversa, i server delle applicazioni non sostituiscono Capistrano, ma possono essere utilizzati in combinazione con Capistrano.
Naturalmente non si deve usare Capistrano. Se preferisci caricare la tua app Ruby con FTP ed eseguire manualmente gli stessi passaggi di comandi ogni volta, puoi farlo. Altre persone si sono stancate, quindi automatizzano quei passaggi a Capistrano.