Apache Tomcat si soffoca dopo 300 connessioni


16

Abbiamo un server web apache di fronte a Tomcat ospitato su EC2, il tipo di istanza è molto grande con una memoria di 34 GB.

La nostra applicazione si occupa di molti servizi Web esterni e abbiamo un servizio Web esterno molto scadente che impiega quasi 300 secondi per rispondere alle richieste nelle ore di punta.

Nelle ore di punta il server si blocca a circa 300 processi httpd. ps -ef | grep httpd | wc -l = 300

Ho cercato su Google e ho trovato numerosi suggerimenti, ma nulla sembra funzionare. Di seguito sono riportate alcune configurazioni che ho preso direttamente dalle risorse online.

Ho aumentato i limiti di connessione massima e numero massimo di client sia in Apache che in Tomcat. ecco i dettagli di configurazione:

// apache

   <IfModule prefork.c>
    StartServers 100
    MinSpareServers 10
    MaxSpareServers 10
    ServerLimit 50000
    MaxClients 50000
    MaxRequestsPerChild 2000
    </IfModule>

// Tomcat

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="600000"
           redirectPort="8443"
           enableLookups="false" maxThreads="1500"
           compressableMimeType="text/html,text/xml,text/plain,text/css,application/x-javascript,text/vnd.wap.wml,text/vnd.wap.wmlscript,application/xhtml+xml,application/xml-dtd,application/xslt+xml"
           compression="on"/>

//Sysctl.conf

 net.ipv4.tcp_tw_reuse=1
 net.ipv4.tcp_tw_recycle=1
 fs.file-max = 5049800
 vm.min_free_kbytes = 204800
 vm.page-cluster = 20
 vm.swappiness = 90
 net.ipv4.tcp_rfc1337=1
 net.ipv4.tcp_max_orphans = 65536
 net.ipv4.ip_local_port_range = 5000 65000
 net.core.somaxconn = 1024

Ho provato numerosi suggerimenti ma invano .. come risolvere questo problema? Sono sicuro che il server m2xlarge dovrebbe servire più richieste di 300, probabilmente potrei sbagliare con la mia configurazione.

Il server si blocca solo durante le ore di punta e quando ci sono 300 richieste simultanee in attesa che il servizio web [300 secondi in ritardo] risponda.

Stavo solo monitorando le connessioni tcp con netstat

ho trovato circa 1000 connessioni nello stato TIME_WAIT, non ho idea di cosa significherebbe in termini di prestazioni, sono sicuro che si deve aggiungere al problema.

Uscita di TOP

 8902  root      25   0 19.6g 3.0g  12m S  3.3  8.8  13:35.77 java
 24907 membase   25   0  753m 634m 2528 S  2.7  1.8 285:18.88 beam.smp
 24999 membase   15   0  266m 121m 3160 S  0.7  0.3  51:30.37 memcached
 27578 apache    15   0  230m 6300 1536 S  0.7  0.0   0:00.03 httpd
 28551 root      15   0 11124 1492  892 R  0.3  0.0   0:00.25 top


 Output of free -m
 total       used       free     shared    buffers    cached
 35007       8470       26536    0          1         61
 8407        26599
 15999       15         15984

 output of iostat
 avg-cpu:  %user   %nice %system %iowait  %steal   %idle
      26.21    0.00    0.48    0.13    0.02   73.15

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda1             14.36         4.77       329.37    9005402  622367592
sdb               0.00         0.00         0.00       1210         48

Anche nelle ore di punta ci sono circa 10-15k tcp di connessioni al server membase [locale]

ALCUNI ERRORI IN MODJK LOG, spero che questo faccia luce sulla questione.

[Wed Jul 11 14:39:10.853 2012] [8365:46912560456400] [error]         ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:18.627 2012] [8322:46912560456400] [error] ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:21.358 2012] [8351:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)
[Wed Jul 11 14:39:22.640 2012] [8348:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)

~

Worker.properties
workers.tomcat_home=/usr/local/tomcat/
worker.list=loadbalancer
worker.tom1.port=8009
worker.tom1.host=localhost
worker.tom1.type=ajp13
worker.tom1.socket_keepalive=True
worker.tom1.connection_pool_timeout=600
worker.tom2.port=8109
worker.tom2.host=localhost
worker.tom2.type=ajp13
worker.tom2.socket_keepalive=True
worker.tom2.connection_pool_timeout=600
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tom1,tom2
worker.loadbalancer.sticky_session=True
worker.tom1.lbfactor=1
worker.tom1.socket_timeout=600
worker.tom2.lbfactor=1
worker.tom2.socket_timeout=600

// Risolto

grazie a tutti per i vostri preziosi suggerimenti .. Ho perso le impostazioni di maxThreads per il connettore AJP 1.3 .. Ora tutto sembra sotto controllo.

Vorrei anche iniziare a guardare anche i server basati come nginx.


Come sono le tue impostazioni di Keepalive?
Tom O'Connor,

Che tipo di errore restituiscono i client quando tentano di caricare una pagina?
Shane Madden

1
Hai aumentato il numero massimo consentito di descrizioni di file aperti per l'utente apache / httpd?
Golja,

@Tom My Keep Alive Le impostazioni sono KeepAliveTimeout 10 in httpd.conf
john titus

3
Che topaspetto ha l'output di questi tempi? Che ne dici free -m? E infine iostat?
Zypher,

Risposte:


13

Hai aumentato maxThreads nel connettore AJP 1.3 sulla porta 8009?


1500 è quello che ho per istanza di Tomcat
John Titus,

@john, stai dicendo che per ogni connettore hai specificato maxThreads = "1500"? Puoi pubblicare la tua stanza per il connettore AJP 1.3 (porta 8009)?
HTTP500,

grazie per averlo sottolineato .. non esiste alcuna impostazione di maxThreads per AJP1.3 .. questo potrebbe essere il motivo?
john titus,

1
Sì, aggiungi maxThreads alla stanza per quel connettore. L'impostazione predefinita è 200.
HTTP500,

6

Prendi in considerazione la possibilità di configurare un server web proxy asincrono come nginxo lighttpddavanti ad Apache. Apache serve il contenuto in modo sincrono, quindi i lavoratori vengono bloccati fino a quando i client non scaricano completamente il contenuto generato (maggiori dettagli qui ). L'impostazione di un proxy asincrono (non bloccante) di solito migliora notevolmente la situazione (ero solito ridurre il numero di lavoratori Apache in esecuzione simultaneamente da 30 a 3-5 utilizzando nginxcome proxy frontend).


5

Ho il sospetto che il tuo problema sia in Tomcat, non in Apache, dai registri che hai mostrato comunque. Quando viene visualizzato "errore 110" durante il tentativo di riconnettersi a Tomcat, significa che è presente una coda di connessioni in attesa di essere servite che non può più rientrare nella configurazione del backlog di ascolto per il socket di ascolto in Tomcat.

From the listen manpage:
   The  backlog  parameter defines the maximum length the queue of pending 
   connections may grow to.  If a connection request arrives with
   the queue full the client may receive an error with an indication
   of ECONNREFUSED or, if the underlying protocol supports  
   retransmission, the request may be ignored so that retries succeed.

Se dovessi indovinare, sospetterei che la stragrande maggioranza delle richieste HTTP quando il server "sta soffocando" è bloccata in attesa che qualcosa ritorni da Tomcat. Scommetto che se tentassi di recuperare alcuni contenuti statici direttamente forniti da Apache (piuttosto che essere delegati a Tomcat) che funzionerebbe anche quando normalmente è "soffocato".

Purtroppo non ho familiarità con Tomcat, ma esiste un modo per manipolare le impostazioni di concorrenza di questo?

Oh, e potrebbe essere necessario prendere in considerazione anche la possibilità che i suoi servizi di rete esterni questo è limitare il numero di connessioni che si sta facendo a voi fino a 300, quindi non fa differenza quanta manipolazione di concorrenza si sta facendo sul lato anteriore se praticamente ogni connessione effettuata dipende da una risposta di servizi Web esterni.

In uno dei tuoi commenti hai menzionato che i dati diventano obsoleti dopo 2 minuti. Suggerirei di memorizzare nella cache la risposta che ricevi da questo servizio per due minuti per ridurre la quantità di connessioni simultanee che stai conducendo al servizio web esterno.


2

Il primo passo per risolvere questo problema è abilitare il mod_status di Apache e studiarne il rapporto - fino a quando non lo hai fatto, in realtà stai camminando alla cieca. Non è giusto. ;-)

La seconda cosa da menzionare (non mi piacciono le risposte a domande che non mi ponevo, ma ...) sta usando server front-end più efficienti e speciali come nginx.

Inoltre, ha fatto esattamente restartapache, o semplicemente gracefulmente ricaricato esso? :)


Apache ha riavviato .. non un grazioso ricaricare
john titus il

@johntitus, beh, mod_statusè tuo amico, comunque. :)
poige,

1

Per qualsiasi tipo di implementazione enterprise-y, la prefork MPM è praticamente la scelta peggiore che puoi fare: divora risorse come le attività di nessuno, e riavviare i thread prende SEMPRE rispetto ad altri MPM.

Almeno passa al lavoratore MPM (apache 2.2 e versioni successive) o - meglio ancora - passa alla versione stabile attuale 2.4.2 con il suo evento predefinito MPM.

Entrambi gestiranno facilmente migliaia di connessioni simultanee con un sovraccarico minimo.


grazie .. ci ho provato anche io .. niente fortuna. Le connessioni TIME_WAIT continuano ad aumentare. Il server smette di rispondere a 350 connessioni
john titus,

1
Non sono d'accordo sul fatto che sia la scelta peggiore - è una scelta sbagliata per questo contesto ed è probabile che i problemi vengano risolti utilizzando il server threaded, ma una soluzione migliore sarebbe quella di utilizzare un server basato su eventi (nginx o lighttpd). Apache basato sugli eventi non è abbastanza maturo per essere considerato da un IMHO di distribuzione aziendale.
symcbean,

1

So che è una vecchia storia, ma ho 2 osservazioni.

Esiste un limite codificato per la Direttiva ServerLimit . http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit vedrai che è max 20000 / 200K.

Esiste un limite rigido di ServerLimit 20000 compilato nel server (per prefork MPM 200000). Questo ha lo scopo di evitare i cattivi effetti causati dai refusi.

2 ° Apparentemente nodybo ha menzionato che impostare quei 2 su uno è una pessima idea :

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

vuol dire che riutilizzi presto il tempo atteso, indovina un po '? il server può parlare al client sbagliato sotto carico pesante.

Ho trovato un ottimo articolo che lo spiega ma - è francese ;-) http://vincent.bernat.im/fr/blog/2014-tcp-time-wait-state-linux.html


0

extra large con memoria da 34 GB.

Il ferro grande non è il modo di ridimensionare il servizio web, ma stai solo spostando i colli di bottiglia. Ma anche con così tanta memoria, sospetto che 50000 connessioni stiano spingendo ciò di cui il sistema è particolarmente capace se:

Nelle ore di punta il server si blocca a circa 300 processi httpd

Sarebbe utile se spiegassi cosa intendi con "il server soffoca".

È anche molto strano avere un limite così alto per le connessioni ma un limite molto basso per l'isteresi (server di riserva min / max).

Sebbene l'estrazione degli errori che hai fornito non mostri il "troppi file aperti", vorrei iniziare esaminando il numero di descrittori di file aperti e le impostazioni di ulimit.


Il server si blocca perché non risponde nemmeno ai normali file html ..
john titus,

Ho cambiato i maxClients a 3000 ora ... sempre lo stesso problema
john titus l'

0

Forse l'utente Apache sta esaurendo gli handle di file consentiti? Non li hai menzionati affatto nel tuo post. Quanti file gestisce attualmente Apache è autorizzato ad avere?


128192 handle di file
john titus,

0

È più simile a un commento, ma non posso perché ho meno reputazione. Si è imbattuto in un problema esattamente simile a quello di @john titus.

Abbiamo MaxThreadsrisolto il problema con il connettore AJP vicino al limite del thread Apache.

Per il monitoraggio, abbiamo cercato SYN_SENT aiuto sullo stato della porta netstat con il comando netstat sulla nostra porta AJP.

netstat -an | grep :8102 | grep SYN_SENT | wc -l

Questo è sceso a 0, che era sempre un numero elevato prima del limite MaxThread impostato su AJP Connector.

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.