
Configuración:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache reenvía solicitudes mediante AJP.
Problema:
Después de un cierto período de tiempo (sin ninguna constante, puede ser entre una hora o dos, o uno o más días), Tomcat dejará de funcionar. O deja de responder o muestra el mensaje genérico "Servicio no disponible temporalmente".
Diagnóstico:
Hay dos servidores con la misma configuración. Uno alberga un sitio web con mayor tráfico (varias solicitudes por segundo), el otro uno con poco tráfico (un puñado de solicitudes cada pocos minutos). Ambos sitios web tienen bases de código completamente diferentes, pero presentan problemas similares.
En el primer servidor, cuando ocurre el problema, todos los subprocesos comienzan a ocuparse lentamente hasta que alcanza el límite (MaxThreads 200). En ese momento, el servidor ya no responde (y aparece la página de servicio no disponible después de un largo período de tiempo).
En el segundo servidor, cuando ocurre el problema, las solicitudes tardan mucho tiempo y cuando finalizan, todo lo que ves es la página de servicio no disponible.
Aparte de la mención del problema MaxThreads, los registros de Tomcat no indican ningún problema específico que pueda estar causando esto.
Sin embargo, en los registros de Apache vemos mensajes aleatorios que hacen referencia a AJP. A continuación se muestra un ejemplo de mensaje aleatorio que vemos (sin ningún orden específico):
[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)
La otra cosa extraña que hemos notado en el servidor de mayor tráfico es que justo antes de que comience a ocurrir el problema, las consultas a la base de datos están tardando mucho más que antes (2000-5000 ms versus normalmente 5-50 ms). Esto solo dura de 2 a 4 segundos antes de que aparezca el mensaje de MaxThreads. Supongo que esto es el resultado de que el servidor de repente trata con demasiados datos/tráfico/hilos.
Información de contexto:
Estos dos servidores llevaban bastante tiempo funcionando sin problemas. En realidad, los sistemas se configuraron cada uno utilizando dos NIC durante ese tiempo. Separaron el tráfico interno y externo. Después de una actualización de la red, trasladamos estos servidores a NIC únicas (nos lo recomendaron por razones de seguridad/simplicidad). Después de ese cambio, los servidores empezaron a tener estos problemas.
Resolución:
La solución obvia sería volver a una configuración de dos NIC. El problema con esto es que causaría algunas complicaciones con la configuración de la red y parece ignorar el problema. Preferiríamos intentar ejecutarlo en una única configuración de NIC.
Buscar en Google los diversos mensajes de error no proporcionó nada útil (ya sea soluciones antiguas o no relacionadas con nuestro problema).
Intentamos ajustar los distintos tiempos de espera, pero eso hizo que el servidor funcionara un poco más antes de morir.
No estamos seguros de dónde buscar para diagnosticar más el problema. Todavía estamos aferrándonos a un clavo ardiendo sobre cuál podría ser el problema:
1) La configuración con AJP y Tomcat es incorrecta o está desactualizada (es decir, ¿errores conocidos?).
2) La configuración de la red (dos NIC versus una NIC) está causando confusión o problemas de rendimiento.
3) Los sitios web en sí (no hay ningún código común, no se utilizan plataformas, solo código Java básico con servlets y JSP)
Actualización 1:
Siguiendo el útil consejo de David Pashley, realicé un seguimiento de pila/volcado de subprocesos durante el problema. Lo que encontré fue que los 200 subprocesos estaban en uno de los siguientes estados:
"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, sólo uno de los 200 hilos estaba en este estado:
"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]
Es posible que el controlador de Oracle en este subproceso esté obligando a todos los demás subprocesos a esperar a que se complete. Por alguna razón, debe estar atascado en este estado de lectura (el servidor nunca se recupera por sí solo, requiere un reinicio).
Esto sugiere que debe estar relacionado con la red entre el servidor y la base de datos o con la base de datos misma. Continuamos con los esfuerzos de diagnóstico, pero cualquier consejo sería útil.
Respuesta1
Resulta que esta versión (clases 12, bastante antigua) del controlador de Oracle tenía varios errores que causaron un punto muerto (como se ve en el estado TP-Processor2 citado anteriormente). No se activó hasta que cambiamos al nuevo entorno. La actualización a la última versión (ojdbc14) resolvió el problema en el servidor principal.
Respuesta2
Según la descripción, sugeriría que el problema puede deberse a que las consultas a la base de datos tardan demasiado. Si las consultas tardan más, la solicitud tardará más y, por lo tanto, tendrá más ejecutándose a la vez. Como puedes ver, te estás quedando sin hilos de Tomcat. Cuando resuelvas el problema con la base de datos deberías estar bien.
- Obtenga un seguimiento de la pila, ya sea usando jstack o usando kill -3 $process_id. Vea lo que hacen sus hilos cuando muere. Si todos están esperando en la base de datos, ese es un buen indicador de mi teoría. Es posible que todos estén esperando alguna cerradura.
- Instale LambdaProbe. Es invaluable para descubrir qué está haciendo su gato.
- Actualiza tu gato. 5.5.8 es increíblemente antiguo. Creo que ahora están en 5.5.27.
Respuesta3
Agregue ConnectionTimeout y keepAliveTimeout a su conector AJP que se encuentra en /etc/tomcat7/server.xml.
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"
connectionTimeout="10000" keepAliveTimeout="10000" />
Información sobre el conector AJP enhttps://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html
ConnectionTimeout = El número de milisegundos que este conector esperará, después de aceptar una conexión, para que se presente la línea URI de solicitud. El valor predeterminado para los conectores del protocolo AJP es -1 (es decir, infinito).
keepAliveTimeout = El número de milisegundos que este conector esperará por otra solicitud AJP antes de cerrar la conexión. El valor predeterminado es utilizar el valor que se ha establecido para el atributo ConnectionTimeout.
Si los valores de ConnectionTimeout y keepAliveTimeout no están definidos, las conexiones AJP se mantendrán vivas durante un tiempo infinito. Debido a que hay muchos subprocesos, el número máximo de subprocesos predeterminado es 200.
Recomiendo instalar psi-probe, un administrador y monitor avanzado para Apache Tomcat, bifurcado de Lambda Probe.https://code.google.com/p/psi-probe/
Respuesta4
Obtuve mejores resultados con mod_proxy en lugar de mod_ajp en términos de estabilidad, así que prueba esa solución. No es invasivo: en el mejor de los casos, resolverá el problema y, en el peor, descartará mod_ajp.
Aparte de eso, parece que sus Tomcats dejan de responder y todos los hilos de solicitud están bloqueados. Haga que su equipo de desarrollo investigue lo que está pasando.haciendo un volcado de hiloy entregárselo será útil.