Opzioni Ruby on Rails Server

L’intera questione di creare un server di sviluppo per l’applicazione Ruby on Rails mi confonde. Ci sono WEBrick, Mongrel, Passenger, Apache, Nginx e molti altri ne sono sicuro, e non capisco davvero i diversi ruoli che interpretano.

Ho iniziato a utilizzare WEBrick e ora utilizzo Mongrel per lo sviluppo. Questi server sono autonomi o si trovano di fronte ad Apache?

Ho letto di Passenger e non capisco veramente di cosa si tratti, il sito dice “rende semplice l’implementazione delle applicazioni web di Ruby”, sostituisce Mongrel? È come Capistrano, che implementa anche le applicazioni web?

Tenendo presente che vorrei testare SSL, e credo che non sia supportato da mongrel, qual è la migliore configurazione del server di sviluppo?

Grazie

La parola “distribuzione” può avere due significati a seconda del contesto. Stai confondendo anche 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 dell’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 di app.

Apache vs Nginx

Sono entrambi i server web. Possono servire file statici ma, con i moduli giusti, possono anche servire applicazioni web dinamiche, ad esempio quelle scritte in PHP. Apache è più popolare e ha più funzioni, Nginx è più piccolo e più veloce e ha meno funzioni.

Né Apache né Nginx sono in grado di offrire app web Ruby immediatamente, per fare ciò è necessario utilizzare Apache / Nginx in combinazione con qualche tipo di componente aggiuntivo, descritto in seguito.

Apache e Nginx possono anche agire come proxy inversi, il che significa che possono ricevere una richiesta HTTP in entrata 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 più tardi perché questo è rilevante.

Mongrel e altri server di app di produzione contro WEBrick

Mongrel è un “application server” di Ruby: in termini concreti ciò significa che Mongrel è un’applicazione che:

  1. Carica la tua app Ruby all’interno del proprio spazio di processo.
  2. Imposta un socket TCP, permettendogli 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 di Ruby.
  3. L’app web di Ruby restituisce quindi un object, che descrive come dovrebbe apparire la risposta HTTP, e Mongrel si occupa di convertirlo in una risposta HTTP effettiva (i byte effettivi) e di inviarlo al socket.

Comunque Mongrel è abbastanza datato, al giorno d’oggi non è più mantenuto. I server applicativi alternativi più recenti sono:

  • Phusion Passenger
  • Unicorno
  • Magro
  • Puma
  • Trinidad (solo JRuby)
  • TorqueBox (solo JRuby)

Li coprirò più tardi e descriverò come differiscono tra loro 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 è scritto interamente in Ruby. Mongrel (e la maggior parte degli altri server di app di Ruby) è in 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.
  • WEBrick viene solitamente utilizzato come server predefinito solo durante lo sviluppo perché WEBrick è incluso in Ruby per impostazione predefinita. Mongrel e altri server delle app devono essere installati separatamente. Non è consigliabile utilizzare WEBrick negli ambienti di produzione, sebbene per qualche motivo Heroku abbia scelto WEBrick come server predefinito. Stavano usando Thin prima, quindi non ho idea del motivo per cui sono passati a WEBrick.

Il server delle app e il mondo

Tutti gli attuali server di app di Ruby parlano HTTP, tuttavia alcuni server di app potrebbero essere esposti direttamente a Internet sulla porta 80, mentre altri potrebbero non farlo.

  • App server che possono essere esposti direttamente a Internet: Phusion Passenger, Rainbows
  • App server che potrebbero non essere esposti direttamente a Internet: Mongrel, Unicorn, Thin, Puma. Questi server di app devono essere posizionati dietro un server web proxy inverso come Apache e Nginx.
  • Non ne so abbastanza su Trinidad e TorqueBox, quindi li ho omessi.

Perché alcuni server di app devono essere messi dietro un proxy inverso?

  • Alcuni server applicazioni possono gestire solo una richiesta contemporaneamente, per processo. Se si desidera gestire contemporaneamente 2 richieste, è 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 un cluster di server delle applicazioni (da cui il nome Mongrel Cluster, Thin Cluster, ecc.). È quindi necessario configurare Apache o Nginx per invertire il proxy su questo cluster. Apache / Nginx si occuperà di distribuire le richieste tra le istanze nel cluster (Ulteriori informazioni nella sezione “Modelli di concorrenza I / O”).
  • Il server Web può bufferizzare le richieste e le risposte, proteggendo il server delle app da “client lenti” – client HTTP che non inviano o accettano i dati molto rapidamente. Non vuoi che il tuo server delle applicazioni non faccia nulla mentre aspetti che il client invii la richiesta completa o che riceva la risposta completa, perché durante quel periodo il server dell’app potrebbe non essere in grado di fare altro. Apache e Nginx sono molto bravi a fare molte cose allo stesso tempo perché sono multithreaded o evented.
  • La maggior parte dei server di app può servire file statici, ma non sono particolarmente adatti. Apache e Nginx possono farlo più velocemente.
  • Normalmente le persone impostano Apache / Nginx per servire direttamente file statici, ma inoltrano richieste che non corrispondono ai file statici sul server dell’app, è una buona pratica di sicurezza. Apache e Nginx sono molto maturi e possono proteggere il server delle app da (forse malevolmente) richieste corrotte.

Perché alcuni server delle app possono essere esposti direttamente a Internet?

  • Phusion Passenger è una bestia molto diversa da tutti gli altri server delle app. Una delle sue caratteristiche uniche è che si integra nel server web.
  • L’autore di Rainbows ha dichiarato pubblicamente che è sicuro esporlo direttamente a Internet. L’autore è abbastanza sicuro che non ci sono vulnerabilità nel parser HTTP (e simili). Tuttavia, l’autore non fornisce alcuna garanzia e afferma che l’utilizzo è a proprio rischio.

Server delle applicazioni confrontati

In questa sezione confronterò la maggior parte dei server di applicazioni che ho menzionato, ma non Phusion Passenger. Phusion Passenger è una bestia così diversa dal resto che gli ho dato una sezione dedicata. Ho anche omesso Trinidad e TorqueBox perché non li conosco abbastanza bene, ma sono rilevanti solo se usi JRuby.

  • Mongrel era piuttosto nudo. Come accennato in precedenza, Mongrel è puramente multi-processo a thread singolo, quindi è utile solo in un cluster. Non c’è monitoraggio del processo: se un processo nel cluster si arresta in modo anomalo (ad esempio a causa di un bug nell’app), deve essere riavviato manualmente. Le persone tendono a utilizzare strumenti di monitoraggio dei processi esterni come Monit e God.
  • L’unicorno è una forchetta di Mongrel. Supporta il monitoraggio limitato del processo: se un processo si blocca, viene automaticamente riavviato dal processo master. Può far ascoltare tutti i processi su un singolo socket condiviso, invece che su un socket separato per ogni processo. Questo semplifica la configurazione del proxy inverso. Come Mongrel, è puramente multi-processo a thread singolo.
  • Thin utilizza il modello di I / O event utilizzando la libreria EventMachine. Oltre a utilizzare il parser HTTP Mongrel, non è basato su Mongrel in alcun modo. La modalità cluster non prevede il monitoraggio dei processi, quindi è necessario monitorare i crash, ecc. Non esiste un socket condiviso simile a Unicorn, 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 utilizzate da Thin, un processo Thin può gestire solo una richiesta simultanea, quindi è necessario un cluster. Ulteriori informazioni su questa proprietà particolare nella sezione “Modelli di concorrenza I / O”.
  • Puma era anche biforcuta da Mongrel, ma a differenza di Unicorn, Puma è progettato per essere puramente multi-threaded. Di conseguenza non esiste attualmente un supporto cluster integrato. È necessario prestare particolare attenzione per assicurarsi di poter utilizzare più core (Ulteriori informazioni in questo capitolo “Modelli di concorrenza I / O”).
  • Rainbows supporta diversi modelli di concorrenza attraverso l’uso di diverse librerie.

Phusion Passenger

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 le app di Ruby, quasi magicamente. L’objective di Phusion Passenger è di rendere tutto Just Work ™ il più semplice ansible.

Anziché avviare un processo o un cluster per la tua app e configurare Apache / Nginx per servire i file statici e / o le richieste di reverse proxy al processo / cluster con Phusion Passenger hai solo bisogno di:

  1. Si modifica il file di configurazione del server Web e si specifica la posizione della directory “pubblica” dell’app Ruby.
  2. 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 applicazioni, Phusion Passenger ha molte meno parti mobili. Questa facilità d’uso è uno dei motivi principali per cui le persone utilizzano Phusion Passenger.

Inoltre, a differenza di altri server di applicazioni, Phusion Passenger è scritto principalmente in C ++, il che lo rende molto veloce.

Esiste anche una variante Enterprise di Phusion Passenger con ancora più funzioni, come riavvio automatico del rotolo, supporto multithreading, resistenza agli errori di implementazione, ecc.

Per le ragioni sopra esposte, Phusion Passenger è attualmente il più popolare app server di Ruby, che alimenta oltre 150.000 siti Web, inclusi quelli di grandi dimensioni come New York Times, Pixar, Airbnb, ecc.

Phusion Passenger vs altri server delle app

Phusion Passenger offre molte più funzionalità e offre molti vantaggi rispetto ad altri server di app, come ad esempio:

  • Regolazione dynamic del numero di processi in base al traffico. Gestiamo una tonnellata di app Rails sul nostro server con risorse limitate che non sono rivolte al pubblico e che le persone della nostra organizzazione usano solo al massimo un paio di volte al giorno. Cose come Gitlab, Redmine, ecc. Phusion Passenger può far cadere quei processi quando non vengono utilizzati, e ruotarli quando vengono utilizzati, consentendo di avere a disposizione più risorse per le app più importanti. Con altri server di app, tutti i tuoi 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: consulta la sezione del sito Web di Unicorn “Peggioramenti in alcuni casi”.

I carichi di lavoro a cui Unicorn non è bravo sono:

  • Streaming dei carichi di lavoro (es. Streaming in streaming di Rails 4 o streaming di modelli di Rails 4).
  • Carichi di lavoro in cui l’app esegue chiamate API HTTP.

Il modello I / O ibrido di Phusion Passenger Enterprise 4 o versioni successive lo rende una scelta eccellente per questo tipo di carichi di lavoro.

  • Altri server di app richiedono all’utente di eseguire almeno un’istanza per applicazione. Al contrario, Phusion Passenger supporta più applicazioni in un’unica istanza. Ciò riduce notevolmente i costi di amministrazione.
  • Cambio automatico dell’utente, una comoda funzione di sicurezza.
  • Phusion Passenger supporta molti MRI Ruby, JRuby e Rubinius. Mongrel, Unicorn e Thin supportano solo la risonanza magnetica. Puma supporta anche tutti e 3.
  • Phusion Passenger supporta in realtà più di un semplice Ruby! Supporta anche Python WSGI, quindi può ad esempio eseguire anche le app Django e Flask. Infatti, Phusion Passenger sta andando nella direzione di diventare un server poliglotta. Supporto Node.js nella lista 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. Anche Unicorn ha una caratteristica 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 applicazioni multithread, mentre quella di Unicorn no.
  • Il riavvolgimento automatico si riavvia. Il riavvio del sistema su Unicorn e su altri server richiede alcuni lavori di scripting. Phusion Passenger Enterprise automatizza completamente questo modo per te.

Ci sono più funzionalità e vantaggi, ma la lista è davvero lunga. 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

  • Multi-processo a thread singolo. Questo è tradizionalmente il modello I / O più popolare per i server dell’app Ruby, in parte perché il supporto del multithreading nell’ecosistema Ruby era molto negativo. Ogni processo può gestire esattamente 1 richiesta alla volta. Il server web bilancia i carichi 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. È molto inadatto per carichi di lavoro I / O di blocco lenti e di lunga durata, ad esempio carichi di lavoro che implicano la chiamata di API HTTP.
  • Puramente multi-threaded. Oggigiorno l’ecosistema Ruby ha un eccellente supporto per il multithreading, quindi questo modello di I / O è diventato molto praticabile. Il multithreading consente un’elevata concorrenza I / O, rendendolo adatto sia per carichi di lavoro I / O di blocco di breve durata che di lunga durata. È più probabile che il programmatore introduca bug di concorrenza, ma fortunatamente la maggior parte dei framework web è progettata in modo tale che è ancora molto improbabile. Una cosa da notare tuttavia è che l’interprete Ruby MRI non può sfruttare più core CPU anche quando ci sono più thread, a causa dell’uso del Global Interpreter Lock (GIL). È ansible aggirare questo 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 singolo processo.
  • Multi processo multi-threaded ibrido. Implementato principalmente da Phusion Passenger Enterprise 4 e versioni successive. È ansible passare facilmente tra processi multi-thread a thread singolo, puramente multithread o forse anche a più processi ciascuno con più thread. Questo modello offre il meglio di entrambi i mondi.
  • Evented. Questo modello è completamente diverso dal modello menzionato in precedenza. Permette una concorrenza I / O molto elevata ed è quindi eccellente per i carichi di lavoro I / O di blocco di lunga durata. Per utilizzarlo, è richiesto il supporto esplicito dell’applicazione e del 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 può gestire più di una richiesta alla volta, in modo che si comporti in modo efficace come il modello multi-processo a thread singolo. Esistono framework specializzati che possono sfruttare l’I / O event, come Cramp.

Un articolo è stato recentemente pubblicato sul blog di Phusion sull’ottimizzazione ottimale del numero di processi e thread forniti dal carico di lavoro. Consulta l’impostazione delle impostazioni di concorrenza di Phusion Passenger .

Capistrano

Capistrano è qualcosa di completamente diverso. In tutte le sezioni precedenti, “deployment” si riferisce all’atto di avviare la tua app Ruby in un server delle applicazioni, in modo che diventi accessibile ai visitatori, ma prima che ciò avvenga, in genere è necessario eseguire alcuni lavori di preparazione, come ad esempio:

  • 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 eventuali daemon su cui la tua app potrebbe fare affidamento, come i lavoratori di Sidekiq / Resque o qualsiasi altra cosa.
  • Qualsiasi altra cosa che deve essere fatta quando si imposta la propria applicazione.

Nel contesto di Capistrano, “spiegamento” si riferisce a fare tutto questo lavoro di preparazione. Capistrano non è un server di applicazioni. Invece, è uno strumento per automatizzare tutto quel lavoro di preparazione. Dì 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 per te e di eseguire i comandi specificati.

Capistrano viene sempre utilizzato in combinazione con un server delle applicazioni. Non sostituisce i server delle applicazioni. Viceversa, i server applicazioni non sostituiscono Capistrano, possono essere utilizzati in combinazione con Capistrano.

Ovviamente non devi usare Capistrano. Se si preferisce caricare l’app Ruby con FTP e ogni volta eseguire manualmente gli stessi passaggi dei comandi, è ansible farlo. Altre persone si sono stancate di farlo, quindi automatizzano quei passi a Capistrano.