2012-07-11 22 views
21

La mia app Web Java con Tomcat (7.0.28) periodicamente non risponde. Sto sperando in qualche suggerimento su possibili colpevoli (sincronizzazione?), Così come forse alcuni strumenti consigliati per raccogliere maggiori informazioni su ciò che sta accadendo durante un incidente. Alcuni fatti che ho accumulato:L'app Web Java in tomcat si blocca periodicamente

  • Quando il web app si blocca, Tomcat continua ad alimentare le discussioni richiesta in app, ma l'applicazione non li rilascia. Il pool di thread si riempie fino al massimo (attualmente 250), quindi le richieste successive vengono immediatamente interrotte. Durante il normale funzionamento, non ci sono mai più di 2 o 3 thread attivi.

  • Non ci sono errori o eccezioni di alcun tipo registrati a nessuno dei nostri registri delle applicazioni Web o Tomcat quando si verifica il problema.

  • Fare un "Stop" e quindi un "Start" sulla nostra applicazione tramite l'app web di gestione di Tomcat risolve immediatamente questo problema (fino ad oggi).

  • Ultimamente la frequenza è stata due o tre volte al giorno, anche se oggi era molto peggio, probabilmente 20 volte, e talvolta non tornava alla vita immediatamente.

  • Il problema si verifica solo durante l'orario lavorativo

  • Il problema non si verifica sul nostro sistema di stadiazione

  • Quando si verifica il problema, utilizzo del processore e della memoria sul server rimane piatta (e piuttosto bassa) . Tomcat segnala un sacco di memoria libera.

  • Tomcat continua a rispondere quando si verifica il problema. L'app Web di gestione funziona perfettamente e Tomcat continua a inviare richieste nella nostra app fino a quando non vengono riempite tutte le discussioni nel pool.

  • Il nostro server di database rimane reattivo quando si verifica il problema. Usiamo il framework Spring per l'accesso ai dati e l'iniezione.

  • Il problema si verifica generalmente quando l'utilizzo è elevato, ma non c'è mai un picco insolitamente elevato nell'utilizzo.

  • Cronologia problemi: qualcosa di simile si è verificato circa un anno e mezzo fa. Dopo molte modifiche alla configurazione e al codice del server, il problema è scomparso fino a circa un mese fa. Nelle ultime settimane si è verificato molto più frequentemente, una media di 2 o 3 volte al giorno, a volte più volte di seguito.

  • Ho identificato alcuni codici server oggi che potrebbero non essere stati protetti da thread e ho inserito una correzione per questo, ma il problema si verifica ancora (anche se meno frequentemente). È questo il tipo di problema che può causare un codice non protetto da un codice?

UPDATE: Con diversi messaggi che suggeriscono connessione al database piscina esaurimento, ho fatto qualche ricerca in questa direzione e ha trovato questo altro Stackoverflow question che spiega quasi tutti i problemi che sto vivendo.

Apparentemente, i valori predefiniti per le connessioni maxActive e maxIdle nell'implementazione di BasicDataSource di Apache sono ciascuno 8. Inoltre, maxWait è impostato su -1, quindi quando il pool è esaurito e una nuova richiesta di connessione arriva, attende per sempre senza registrare alcun tipo di eccezione.Sto ancora aspettando che questo problema si ripresenti ed eseguo un jstack dump sulla JVM in modo da poter analizzare tali informazioni, ma sembra che questo sia il problema. L'unica cosa che non spiega è perché a volte l'app non si risolve da questo problema. Suppongo che le richieste si accumulino a volte e una volta che le cose non sono riuscite a raggiungerlo.

UPDATE II: mi passò una jstack durante un incidente e ha trovato circa 250 (fili max) delle seguenti operazioni:

"http-nio-443-exec-294" daemon prio=10 tid=0x00002aaabd4ed800 nid=0x5a5d in Object.wait() [0x00000000579e2000] 
    java.lang.Thread.State: WAITING (on object monitor) 
     at java.lang.Object.wait(Native Method) 
     at java.lang.Object.wait(Object.java:485) 
     at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118) 
     - locked <0x0000000743116b30> (a org.apache.commons.pool.impl.GenericObjectPool$Latch) 
     at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106) 
     at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
     at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) 
     at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) 
     at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674) 
     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718) 

Al mio occhio non addestrato, questo sembra abbastanza conclusiva. Sembra che il pool di connessione del database abbia raggiunto il suo limite. Ho configurato un maxWait di tre secondi senza modificare maxActive e maxIdle solo per garantire che iniziamo a vedere le eccezioni registrate quando il pool si riempie. Quindi imposterò quei valori su qualcosa di appropriato e monitor.

UPDATE III: Dopo aver configurato maxWait, ho cominciato a vedere questi nei miei ceppi, come ci si aspettava:

org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object 
     at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114) 
     at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
     at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) 
     at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) 

ho impostato maxActive a -1 (infinito) e maxIdle a 10. Lo farò monitorare per un po ', ma la mia ipotesi è che questa è la fine del problema.

+7

'kill -3 ' è tuo amico. Esegui questo e guarda il dump del thread. Potrebbe essere utile dare un'occhiata al Thread Dump Analyzer per il raggruppamento delle informazioni (http://java.net/projects/tda/). – mindas

+0

Wild-guess senza altre informazioni (sono necessari dump di thread!): Esaurimento del pool di connessioni DB. –

+1

Questo è esattamente quello che mi stava succedendo, l'applicazione web è diventata troppo grande, le connessioni massime erano troppo basse e il tempo di attesa era indeterminato, i thread continuavano ad accumularsi e quindi il server si bloccava. Aumentati i minimi e impostare un tempo specifico in attesa massima e ora sto solo monitorando, ma il server funziona bene. Grazie per questo mini tutorial. – Lauro182

risposta

12

Per esperienza, si consiglia di verificare l'implementazione del pool di connessione del database . Potrebbe essere che il tuo database abbia molta capacità, ma il pool di connessioni nell'applicazione è limitato a un numero limitato di connessioni. Non riesco a ricordare i dettagli, ma mi sembra di ricordare di avere un problema simile, che è stato uno dei motivi per cui sono passato a utilizzare BoneCP, che ho trovato essere molto veloce e affidabile sotto test di carico.

Dopo aver provato il debug suggerito di seguito, provare ad aumentare il numero di connessione disponibile nel pool e vedere se questo ha un impatto.

ho identificato un certo codice del server oggi che non può essere stato threadsafe, e ho messo una correzione in per questo, ma il problema è ancora accadendo (anche se meno di frequente). È questo il tipo di problema che può causare il codice non protetto da ?

Dipende da cosa intendi per thread-safe. Mi sembra che l'applicazione stia causando thread a deadlock. Potresti voler eseguire il tuo ambiente di produzione con la JVM configurata per consentire a un debugger di connettersi e quindi utilizzare JVisualVM, JConsole o un altro strumento di profilazione (YourKit è eccellente IMO) per dare un'occhiata a quali thread hai e cosa sono stai aspettando.

+0

Sì BoneCP oscilla. commons-dbcp fa schifo. Tomcat 7 viene fornito con un dbcp https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html ma per utilizzarlo il driver deve essere accessibile dallo stesso classloader di tomcat-jdbc.jar. Non voglio preoccuparmi di mettere il jar del driver nella cartella lib di tomcat ogni volta che installo un nuovo tomcat. – redochka

+0

Redsonic: Non è vero. Se il tuo 'DataSource' è definito all'interno di un contesto, e non come una risorsa JNDI condivisa tra i contesti, può essere nel classpath del contesto (cioè nel file .war). Questo è il modo in cui l'ho usato nei sistemi di produzione. –

+0

ah ok. Non mi sono messo alla prova. Ho riportato cosa c'era nel tomcat 7 doc. Ok allora, anche in questo caso è un'opzione :) – redochka