Apache + Tomcat ha problemi di comunicazione. Messaggi di errore poco chiari. Realizzazione di siti Web ospitati su Tomcat


22

Installazione:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache inoltra le richieste usando AJP.

Problema:
dopo un certo periodo di tempo (nessuna costante, può essere compresa tra un'ora o due o uno o più giorni), Tomcat scenderà. O smette di rispondere o inserisce il generico "Servizio temporaneamente non disponibile".

Diagnosi:
esistono due server con la stessa configurazione. Uno ospita un sito Web a traffico più elevato (diverse richieste al secondo), l'altro uno a basso traffico (una manciata di richieste ogni pochi minuti). Entrambi i siti Web sono basi di codice completamente diverse, ma presentano problemi simili.

Sul primo server, quando si verifica il problema, tutti i thread iniziano lentamente a essere ripresi fino a raggiungere il limite (MaxThreads 200). A quel punto il server non risponde più (e viene visualizzata la pagina di servizio non disponibile dopo un lungo periodo di tempo).

Sul secondo server, quando si verifica il problema, le richieste impiegano molto tempo e quando vengono eseguite, viene visualizzata solo la pagina del servizio non disponibile.

Oltre alla menzione del problema MaxThreads, i registri Tomcat non indicano alcun problema specifico che potrebbe causare questo.

Tuttavia, nei registri di Apache vediamo messaggi casuali che si riferiscono ad AJP. Ecco un esempio di messaggio casuale che vediamo (in nessun ordine specifico):

[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)

L'altra cosa strana che abbiamo notato sul server a traffico più elevato è che proprio prima che si verifichi il problema, le query del database impiegano molto più tempo rispetto a prima (2000-5000 ms contro normalmente 5-50ms). Questo dura solo 2-4 secondi prima che appaia il messaggio MaxThreads. Suppongo che questo sia il risultato del server che improvvisamente ha a che fare con troppi dati / traffico / thread.

Informazioni di base:
Questi due server erano in esecuzione senza problemi da un po 'di tempo. I sistemi sono stati effettivamente installati ciascuno utilizzando due schede di rete durante quel periodo. Hanno separato il traffico interno ed esterno. Dopo un aggiornamento della rete, abbiamo spostato questi server in singole NIC (questo ci è stato consigliato per motivi di sicurezza / semplicità). Dopo tale modifica, i server hanno iniziato ad avere questi problemi.

Risoluzione:
la soluzione ovvia sarebbe quella di tornare a una configurazione di due schede di rete. Il problema è che ciò comporterebbe alcune complicazioni con la configurazione della rete e sembra ignorare il problema. Preferiremmo provare a farlo funzionare su una singola configurazione della scheda di rete.

Cercare su Google i vari messaggi di errore non ha fornito nulla di utile (soluzioni vecchie o non correlate al nostro problema).

Abbiamo provato a regolare i vari timeout, ma ciò ha reso il server leggermente più lungo prima di morire.

Non siamo sicuri di dove cercare per diagnosticare ulteriormente il problema. Stiamo ancora cercando di capire quale potrebbe essere il problema:

1) L'impostazione con AJP e Tomcat non è corretta o è obsoleta (ad esempio, bug noti?)
2) L'impostazione della rete (due NIC contro una NIC) sta causando problemi di confusione o velocità effettiva.
3) I siti Web stessi (non esiste un codice comune, nessuna piattaforma utilizzata, solo codice Java di base con servlet e JSP)

Aggiornamento 1:
seguendo i consigli utili di David Pashley, ho fatto un dump dello stack / thread dello stack durante il problema. Quello che ho scoperto è che tutti i 200 thread erano in uno dei seguenti stati:

"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at  oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

Curiosamente, solo un thread su tutti i 200 thread era in questo stato:

"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]

È possibile che il driver Oracle in questo thread stia forzando tutti gli altri thread ad attendere il completamento. Per qualche motivo deve essere bloccato in questo stato di lettura (il server non ripristina mai da solo, richiede un riavvio).

Ciò suggerisce che deve essere correlato alla rete tra il server e il database o al database stesso. Stiamo continuando gli sforzi di diagnosi, ma qualsiasi suggerimento sarebbe utile.


Prima di tutto, questa è una domanda meravigliosamente scritta. Fantastico lavoro sui dettagli! Secondo, stai usando proxy_ajp o mod_jk per connettere i server Apache e Tomcat?
Ophidian,

Sto usando proxy_ajp per collegare i due.
Jordy Boom,

Fai degli stress test usando assedio, joedog.org/siege-home .
paalfe,

Risposte:


9

Si scopre che questa versione (classi 12 - piuttosto vecchia) del driver Oracle presentava vari bug che causavano un deadlock (come visto nello stato TP-Processor2 citato sopra). Non è diventato attivo fino a quando non siamo passati al nuovo ambiente. L'aggiornamento alla versione più recente (ojdbc14) ha risolto il problema sul server primario.


Questo mi ha portato alla mia soluzione corretta: avevo un blocco in una riga DB ... e non ho mai avuto eccezioni nell'App-Server
cljk,

6

Dalla descrizione, suggerirei che il problema potrebbe essere dovuto alle query del database che impiegano troppo tempo. Se le query impiegano più tempo, la richiesta richiederà più tempo e quindi ne avrai molte in esecuzione contemporaneamente. Come vedi, stai esaurendo i thread Tomcat. Quando risolvi il problema con il database dovresti essere a posto.

  • Ottieni una traccia dello stack, usando jstack o usando kill -3 $ process_id. Guarda cosa stanno facendo i tuoi fili quando muore. Se stanno tutti aspettando sul database, questo è un buon indicatore della mia teoria. Potrebbero essere tutti in attesa di qualche blocco.
  • Installa LambdaProbe. È prezioso per scoprire cosa sta facendo il tuo gatto selvatico.
  • Aggiorna il tuo tomcat. 5.5.8 è incredibilmente vecchio. Penso che siano ora in 5.5.27.

David, ho aggiornato la domanda (vedi Aggiornamento 1) con nuovi risultati basati sul suggerimento di traccia del dump / stack del thread.
Jordy Boom,

Suggerirei che il pool di connessioni al database sia troppo piccolo rispetto al valore di connessione massima di Tomcat. Sembra che la maggior parte dei thread siano in attesa di ottenere una connessione al database.
David Pashley,

L'unico motivo per cui ci sono molti thread è perché i thread normalmente utilizzati vengono lasciati in attesa che quel thread tenti di leggere dal socket. Il numero di connessioni DB utilizzate in qualsiasi momento va da 1 a 3. Non c'è mai bisogno di più di così tante.
Jordy Boom,

5

Aggiungi connectionTimeout e keepAliveTimeout al tuo connettore AJP che si trova in /etc/tomcat7/server.xml.

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

Informazioni sul connettore AJP su https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Il numero di millisecondi che questo connettore attenderà, dopo aver accettato una connessione, per la presentazione della riga URI della richiesta. Il valore predefinito per i connettori del protocollo AJP è -1 (ovvero infinito).

  • keepAliveTimeout = Il numero di millisecondi che questo connettore attenderà per un'altra richiesta AJP prima di chiudere la connessione. Il valore predefinito è utilizzare il valore che è stato impostato per l'attributo connectionTimeout.

Se i valori connectionTimeout e keepAliveTimeout non sono definiti, le connessioni AJP saranno mantenute in vita per infinito. Causando molti thread, il numero massimo di thread predefinito è 200.

Consiglio di installare psi-probe, un gestore e monitor avanzato per Apache Tomcat, creato da Lambda Probe. https://code.google.com/p/psi-probe/


4

A causa del modo in cui funziona AJP, le connessioni persistenti tra apache (usando mod_proxy_ajp o mod_jk) possono essere chiuse in modo sicuro dal client . In questo caso, il client è l'apache worker che si apre e quindi mantiene una connessione a Tomcat per la durata del processo di lavoro .

A causa di questo comportamento non puoi avere più apache worker dei thread tomcat worker. In questo modo, i lavoratori http aggiuntivi non potranno connettersi a Tomcat (poiché la coda di accettazione è piena) e contrassegnare il back-end come DOWN!


1
Ci scusiamo per il commento dopo tutti questi anni, ma non è possibile garantirlo impostando il max-flag all'interno della configurazione ProxyPass sul numero di MaxThreads del contenitore servlet?
Horst Gutmann,

2

Ho ottenuto risultati migliori con mod_proxy anziché mod_ajp in termini di stabilità, quindi prova questa soluzione. Non è invasivo: nella migliore delle ipotesi risolverà il problema e nella peggiore delle ipotesi escluderà mod_ajp.

A parte questo, sembra che i tuoi Tomcats smettano di rispondere e che tutti i thread delle richieste siano collegati. Chiedi al tuo team di sviluppo di esaminare cosa sta succedendo: prendere una discarica di thread e consegnarla a loro sarà utile.


Ho avuto l'impressione che mod_proxy abbia alcuni problemi di scalabilità nonostante sia più facile da collegare. Sembra che la fondazione Apache raccomanda mod_jk ( wiki.apache.org/tomcat/FAQ/Connectors#Q2 )
Ophidian

Non fornisce sesssion appiccicoso, vero. Ma a parte questo non ho mai avuto problemi con esso.
Robert Munteanu,

1

La prima cosa che mi viene in mente quando sento che un server funziona per un po ', improvvisamente rallenta e poi inizia ad avere errori di servizio è che sta esaurendo la RAM e il thrashing swap. Non sono chiaro se gli errori AJP che stai vedendo potrebbero essere conseguenti a timeout, ma non sembra del tutto irragionevole; non vedo alcun modo ovvio per collegarsi alla scheda di rete, tuttavia. In ogni caso, ti consiglio di avere una foto di ciò che sta accadendo con l'utilizzo della memoria quando si verificano questi eventi.

Se si sta esaurendo la RAM, potrebbe essere necessario abbassare Apache MaxClientse aumentarlo ListenBacklog.

A proposito, grazie per aver reso la tua domanda così ben organizzata e completa.


Quando osservo "top" mentre ciò accade, l'utilizzo della memoria rimane abbastanza coerente. Almeno non ci sono punte. C'è solo un breve momento di elevato utilizzo della CPU.
Jordy Boom,

1

Ho avuto errori di registro simili nell'ambiente Redhat con proxy_ajp e Tomcat. Risolto aggiornando il pacchetto httpd:

yum update httpd

a partire dal:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

a:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

Quindi riavviato Apache, seguito dal riavvio di Tomcat.

Questo mi ha risolto!

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.