http mantenersi in vita nell'era moderna


92

Quindi, secondo l'autore haproxy, chi sa una cosa o due su http:

Keep-Alive è stato inventato per ridurre l'utilizzo della CPU sui server quando le CPU erano 100 volte più lente. Ma ciò che non viene detto è che le connessioni persistenti consumano molta memoria pur non essendo utilizzabili da nessuno tranne il cliente che le ha aperte. Oggi, nel 2009, le CPU sono molto economiche e la memoria è ancora limitata a pochi gigabyte dall'architettura o dal prezzo. Se un sito ha bisogno di keep-alive, c'è un vero problema. I siti molto caricati spesso disabilitano keep-alive per supportare il numero massimo di client simultanei. Il vero svantaggio di non avere keep-alive è una latenza leggermente aumentata per recuperare gli oggetti. I browser raddoppiano il numero di connessioni simultanee su siti non keepalive per compensare ciò.

(da http://haproxy.1wt.eu/ )

È in linea con l'esperienza di altre persone? cioè senza keep-alive - il risultato è appena percettibile ora? (probabilmente vale la pena notare che con websocket ecc. - una connessione viene comunque mantenuta "aperta" indipendentemente dallo stato di keep-alive - per app molto reattive). L'effetto è maggiore per le persone che sono remote dal server o se ci sono molti artefatti da caricare dallo stesso host durante il caricamento di una pagina? (Penso che cose come CSS, immagini e JS provengano sempre più da CDN compatibili con la cache).

Pensieri?

(Non sono sicuro che sia una cosa su serverfault.com, ma non incrocio il post fino a quando qualcuno non mi dice di spostarlo lì).


1
Vale la pena notare che altrove nella documentazione di haproxy che keep-alive è menzionato in altri termini più favorevoli. Mi piacerebbe conoscere l'esperienza delle persone, specialmente per l'hosting di massa.
Michael Neale

"Ottenere un web / application-server meglio progettato"? :-) I progetti più recenti (come Jetty) con gestione della connessione continuativa (simile a) essenzialmente mitigano i problemi di memoria / thread. Inoltre, "pochi GB" suona come un termine del server 2008/2009 ;-)

3
A me sembra una sciocchezza. L'RTT aggiuntivo coinvolto nella creazione di una nuova presa è un limite fisico rigido che è spesso abbastanza lungo da essere rilevabile da un essere umano e non può essere ridotto entro le leggi della fisica conosciute. Al contrario, la RAM è economica, diventa sempre più economica e non c'è motivo per un socket inattivo di usarne più di pochi kB.
Will Dean

2
ma ciò che è interessante è che questa non è solo teoria: questo è l'autore di haproxy. Tutto il resto che sento sono teorie e supposizioni.
Michael Neale

Risposte:


141

Ehi, dato che sono l'autore di questa citazione, risponderò :-)

Ci sono due grandi problemi su siti di grandi dimensioni: connessioni simultanee e latenza. Le connessioni simultanee sono causate da client lenti che impiegano anni per scaricare i contenuti e da stati di connessione inattiva. Questi stati di connessione inattiva sono causati dal riutilizzo della connessione per recuperare più oggetti, noto come keep-alive, che è ulteriormente aumentato dalla latenza. Quando il client è molto vicino al server, può fare un uso intensivo della connessione e assicurarsi che non sia quasi mai inattivo. Tuttavia, quando la sequenza finisce, nessuno si preoccupa di chiudere rapidamente il canale e la connessione rimane aperta e inutilizzata per molto tempo. Questo è il motivo per cui molte persone suggeriscono di utilizzare un timeout keep-alive molto basso. Su alcuni server come Apache, il timeout più basso che puoi impostare è di un secondo, ed è spesso troppo per sostenere carichi elevati: se hai 20000 client davanti a te e questi recuperano in media un oggetto ogni secondo, avrai quelle 20000 connessioni stabilite in modo permanente. 20000 connessioni simultanee su un server generico come Apache sono enormi, richiederanno tra 32 e 64 GB di RAM a seconda di quali moduli vengono caricati e probabilmente non si può sperare di andare molto più in alto anche aggiungendo RAM. In pratica, per 20000 client potresti persino vedere da 40000 a 60000 connessioni simultanee sul server perché i browser proveranno a impostare da 2 a 3 connessioni se hanno molti oggetti da recuperare. e probabilmente non puoi sperare di andare molto più in alto anche aggiungendo RAM. In pratica, per 20000 client potresti persino vedere da 40000 a 60000 connessioni simultanee sul server perché i browser proveranno a impostare da 2 a 3 connessioni se hanno molti oggetti da recuperare. e probabilmente non puoi sperare di andare molto più in alto anche aggiungendo RAM. In pratica, per 20000 client potresti persino vedere da 40000 a 60000 connessioni simultanee sul server perché i browser proveranno a impostare da 2 a 3 connessioni se hanno molti oggetti da recuperare.

Se chiudi la connessione dopo ogni oggetto, il numero di connessioni simultanee diminuirà drasticamente. Infatti, scenderà di un fattore corrispondente al tempo medio per scaricare un oggetto dal tempo tra gli oggetti. Se hai bisogno di 50 ms per scaricare un oggetto (una foto in miniatura, un pulsante, ecc ...) e scarichi in media 1 oggetto al secondo come sopra, avrai solo 0,05 connessioni per client, che è solo 1000 connessioni simultanee per 20000 client.

Ora il tempo per stabilire nuove connessioni sta per contare. I client remoti sperimenteranno una spiacevole latenza. In passato, i browser utilizzavano grandi quantità di connessioni simultanee quando Keep-Alive era disabilitato. Ricordo le cifre di 4 su MSIE e 8 su Netscape. Questo avrebbe davvero diviso la latenza media per oggetto di molto. Ora che keep-alive è presente ovunque, non vediamo più numeri così alti, perché così facendo aumenta ulteriormente il carico sui server remoti e i browser si occupano di proteggere l'infrastruttura di Internet.

Ciò significa che con i browser odierni, è più difficile rendere i servizi non keep-alive altrettanto reattivi di quelli keep-alive. Inoltre, alcuni browser (ad esempio: Opera) utilizzano l'euristica per provare a utilizzare il pipelinining. Il pipelining è un modo efficiente di utilizzare keep-alive, perché elimina quasi la latenza inviando più richieste senza attendere una risposta. L'ho provato su una pagina con 100 foto piccole e il primo accesso è circa due volte più veloce che senza keep-alive, ma il prossimo accesso è circa 8 volte più veloce, perché le risposte sono così piccole che conta solo la latenza (solo Risposte "304").

Direi che idealmente dovremmo avere alcuni parametri sintonizzabili nei browser per mantenere attive le connessioni tra gli oggetti recuperati e rilasciarlo immediatamente quando la pagina è completa. Ma sfortunatamente non lo stiamo vedendo.

Per questo motivo, alcuni siti che necessitano di installare server generici come Apache sul lato anteriore e che devono supportare grandi quantità di client generalmente devono disabilitare keep-alive. E per forzare i browser ad aumentare il numero di connessioni, utilizzano più nomi di dominio in modo che i download possano essere parallelizzati. È particolarmente problematico sui siti che fanno un uso intensivo di SSL perché la configurazione della connessione è ancora più elevata in quanto vi è un round trip aggiuntivo.

Ciò che è più comunemente osservato al giorno d'oggi è che tali siti preferiscono installare frontend leggeri come haproxy o nginx, che non hanno problemi a gestire da decine a centinaia di migliaia di connessioni simultanee, abilitano keep-alive lato client e disabilitano sul lato Lato Apache. Da questo lato, il costo per stabilire una connessione è pressoché nullo in termini di CPU, e per nulla percepibile in termini di tempo. In questo modo ciò fornisce il meglio di entrambi i mondi: bassa latenza dovuta al keep-alive con timeout molto bassi sul lato client e basso numero di connessioni sul lato server. Sono tutti felici :-)

Alcuni prodotti commerciali migliorano ulteriormente questo aspetto riutilizzando le connessioni tra il servizio di bilanciamento del carico anteriore e il server e eseguendo il multiplexing di tutte le connessioni client su di esse. Quando i server sono vicini all'LB, il guadagno non è molto maggiore rispetto alla soluzione precedente, ma spesso richiederà adattamenti sull'applicazione per garantire che non vi sia alcun rischio di incrocio di sessioni tra utenti a causa della condivisione inaspettata di una connessione tra più utenti . In teoria questo non dovrebbe mai accadere. La realtà è molto diversa :-)


1
Grazie per la risposta completa e esauriente! Ero un po 'confuso dai vari commenti sulla pagina sul keep-alive, ma tutto questo ha senso.
Michael Neale

È interessante notare che - ho osservato Chrome su Linux riutilizzare una connessione mantenuta attiva per pochi secondi - cioè il tempo impiegato per aprire un'altra scheda - quest'altra scheda era su un nome host diverso, ma risolta tramite carattere jolly DNS sullo stesso server (massa hosting virtuale) - e quindi riutilizzato la stessa connessione! (questo mi ha causato qualche sorpresa, non il buon tipo - ovviamente se keep alive è solo lato client va bene).
Michael Neale

Tutto quello che ho sentito è stato "usa qualcosa di diverso da apache e non è un grosso problema". Quello che ho estrapolato è stato "disabilita mod_php e passeggero e quindi anche apache potrebbe avere una possibilità di combattere".
coolaj86

@ CoolAJ86: il punto è assolutamente non colpire Apache, e io personalmente lo uso. Il punto è che più generico è il server, minori saranno le opzioni da scalare. Alcuni moduli richiedono il modello pre-fork, quindi non è possibile scalare a un numero enorme di connessioni. Ma come spiegato non è un grosso problema in quanto puoi combinarlo con un altro componente gratuito come haproxy. Perché qualcuno dovrebbe sostituire tutto in questo caso? Meglio installare haproxy che affrontare il fastidio di reimplementare l'applicazione utilizzando un altro server!
Willy Tarreau

22

Negli anni trascorsi da quando questo è stato scritto (e pubblicato qui su stackoverflow) ora abbiamo server come nginx che stanno crescendo in popolarità.

nginx, ad esempio, può mantenere aperte 10.000 connessioni keep-alive in un singolo processo con solo 2,5 MB (megabyte) di RAM. In effetti è facile tenere aperte migliaia di connessioni con pochissima RAM, e gli unici limiti che incontrerai saranno altri limiti come il numero di handle di file aperti o le connessioni TCP.

Keep-alive era un problema non a causa di un problema con la specifica keep-alive in sé, ma a causa del modello di ridimensionamento basato sul processo di Apache e dei keep-alive hackerati in un server la cui architettura non era progettata per adattarlo.

Particolarmente problematico è Apache Prefork + mod_php + keep-alive. Questo è un modello in cui ogni singola connessione continuerà ad occupare tutta la RAM occupata da un processo PHP, anche se è completamente inattivo e rimane aperto solo come keep-alive. Questo non è scalabile. Ma i server non devono essere progettati in questo modo: non c'è motivo particolare per cui un server debba mantenere ogni connessione keep-alive in un processo separato (specialmente non quando ogni processo di questo tipo ha un interprete PHP completo). PHP-FPM e un modello di elaborazione del server basato su eventi come quello di nginx risolvono il problema in modo elegante.

Aggiornamento 2015:

SPDY e HTTP / 2 sostituiscono la funzionalità keep-alive di HTTP con qualcosa di ancora migliore: la capacità non solo di mantenere attiva una connessione e di effettuare più richieste e risposte su di essa, ma anche di essere multiplexate, in modo che le risposte possano essere inviate in qualsiasi ordine e parallelamente, anziché solo nell'ordine in cui sono stati richiesti. Ciò impedisce che risposte lente blocchino quelle più veloci e rimuove la tentazione per i browser di mantenere aperte più connessioni parallele a un singolo server. Queste tecnologie evidenziano ulteriormente le inadeguatezze dell'approccio mod_php ei vantaggi di qualcosa come un server web basato su eventi (o per lo meno multi-threaded) accoppiato separatamente con qualcosa come PHP-FPM.


2

la mia comprensione era che aveva poco a che fare con la CPU, ma la latenza nell'apertura di socket ripetuti dall'altra parte del mondo. anche se disponi di una larghezza di banda infinita, la latenza della connessione rallenterà l'intero processo. amplificato se la tua pagina ha dozzine di oggetti. anche una connessione persistente ha una latenza di richiesta / risposta ma è ridotta quando si hanno 2 socket poiché in media uno dovrebbe trasmettere i dati mentre l'altro potrebbe bloccarsi. Inoltre, un router non presumerà mai che un socket si connetta prima di consentirti di scrivere su di esso. Ha bisogno della stretta di mano completa di andata e ritorno. di nuovo, non pretendo di essere un esperto, ma è così che l'ho sempre visto. ciò che sarebbe davvero interessante è un protocollo completamente ASYNC (no, non un protocollo completamente malato).


sì, questa sarebbe la mia ipotesi. forse è un compromesso - c'è un punto in cui la latenza (dovuta alla distanza) significa che è un vero problema
Michael Neale

ok, quindi la tipografia moderna ti farebbe connettere a un proxy vicino (forse). ma poi estendi la domanda se i proxy dovrebbero utilizzare connessioni persistenti?
catchpolenet

@Michael Neale inoltre, a causa di cose come l'avvio lento del TCP, la penalità di latenza effettiva è molto peggiore di quanto ci si aspetterebbe.
MartinodF

forse il compromesso è un periodo di timeout molto più breve. se hai richieste di backup, perché chiudere il socket e ricominciare? anche 1 secondo consentirebbe a una pagina di caricarsi con piena persistenza e quindi chiudere i socket immediatamente dopo.
catchpolenet

2

Keep-live molto lunghi può essere utile se stai usando una CDN "origin pull" come CloudFront o CloudFlare. In effetti, questo può rivelarsi più veloce di nessun CDN, anche se stai servendo contenuti completamente dinamici.

Se ti mantieni vivo a lungo in modo tale che ogni PoP abbia fondamentalmente una connessione permanente al tuo server, la prima volta che gli utenti visitano il tuo sito, possono eseguire una stretta di mano TCP veloce con il loro PoP locale invece di una stretta di mano lenta con te. (La luce stessa impiega circa 100 ms per fare il giro del mondo in fibra ottica e per stabilire una connessione TCP sono necessari tre pacchetti da trasmettere avanti e indietro. SSL richiede tre round trip .)


1
Ero tentato di fare +1, ma il tuo secondo paragrafo ha questa osservazione errata della luce che impiega solo 10 ms per viaggiare a metà strada intorno al mondo. 10 ms di velocità della luce nel vuoto sono 3000 km e 10 ms di velocità della luce in una fibra non sono molto più di 2000 km; mezzo giro del mondo (lungo la superficie) è di 20.000 km. Quindi sarebbero 100 ms --- se solo la tua fibra andasse direttamente da Londra a Sydney piuttosto che probabilmente circumnavigare l'Africa via mare o prendere la lunga rotta per le Hawaii ...
piramidi

@pyramids Hai ragione, o l'ho digitato, o ho semplicemente scherzato. Si aggiornerà.
mjs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.