Apache Tomcat se ahoga después de 300 conexiones

16

Tenemos un servidor web apache frente a Tomcat alojado en EC2, el tipo de instancia es extra grande con 34 GB de memoria.

Nuestra aplicación se ocupa de muchos servicios web externos y tenemos un servicio web externo muy pésimo que tarda casi 300 segundos en responder a las solicitudes durante las horas pico.

Durante las horas pico, el servidor se ahoga con aproximadamente 300 procesos httpd. ps -ef | grep httpd | wc -l = 300

Busqué en Google y encontré numerosas sugerencias, pero parece que nada funciona. A continuación se detallan algunas configuraciones que hice directamente de los recursos en línea.

He aumentado los límites de conexión máxima y clientes máximos tanto en apache como en tomcat. Aquí están los detalles de configuración:

//apache

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

//gato

    <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

He estado probando numerosas sugerencias pero en vano ... ¿cómo solucionar esto? Estoy seguro de que el servidor m2xlarge debería atender más solicitudes que 300, probablemente podría estar fallando con mi configuración.

El servidor se bloquea solo durante las horas pico y cuando hay 300 solicitudes simultáneas esperando que responda el servicio web [300 segundos retrasados].

Solo estaba monitoreando las conexiones tcp con netstat

Encontré alrededor de 1000 conexiones en el estado TIME_WAIT, no tengo idea de lo que eso significaría en términos de rendimiento, estoy seguro de que debe estar aumentando el problema.

Salida de 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

También en la hora pico hay aproximadamente 10-15k conexiones tcp al servidor membase [local]

ALGUNOS ERRORES EN MODJK LOG, espero que esto arroje algo de luz sobre el tema.

[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

// resuelto

gracias a todos por sus valiosas sugerencias. Me perdí la configuración de maxThreads para el conector AJP 1.3. Ahora todo parece estar bajo control.

También comenzaría a mirar incluso servidores basados ​​en nginx.

John Titus
fuente
¿Cómo son sus configuraciones de Keepalive?
Tom O'Connor
¿Qué tipo de error recuperan los clientes cuando intentan cargar una página?
Shane Madden
1
¿Aumentó las descripciones máximas permitidas de archivos abiertos para el usuario apache / httpd?
golja
@Tom My Keep Alive La configuración es KeepAliveTimeout 10 en httpd.conf
john titus
3
¿Cómo se ve la salida de topestos tiempos? ¿Qué tal free -m? Y por ultimo iostat?
Zypher

Respuestas:

13

¿Ha aumentado maxThreads en el conector AJP 1.3 en el puerto 8009?

HTTP500
fuente
1500 es lo que tengo por instancia de tomcat
john titus
@john, ¿estás diciendo que para cada conector has especificado maxThreads = "1500"? ¿Puedes publicar tu estrofa para el conector AJP 1.3 (puerto 8009)?
HTTP500
gracias por señalar esto ... no hay una configuración maxThreads para AJP1.3 en absoluto ... ¿podría ser esta la razón?
juan titus
1
Sí, agregue maxThreads a la stanza para ese conector. El valor predeterminado es 200.
HTTP500
6

Considere configurar un servidor web proxy asíncrono como nginxo lighttpdfrente a Apache. Apache sirve contenido sincrónicamente para que los trabajadores se bloqueen hasta que los clientes descarguen el contenido generado en su totalidad (más detalles aquí ). La configuración de un proxy asincrónico (sin bloqueo) generalmente mejora la situación dramáticamente (solía reducir el número de trabajadores de Apache que se ejecutan simultáneamente de 30 a 3-5 usando nginxcomo proxy frontend).

Alex
fuente
5

Sospecho que su problema está en tomcat no apache, de los registros que ha mostrado de todos modos. Cuando recibe el 'error 110' al intentar volver a conectarse a Tomcat, indica que tiene una cola de conexiones esperando a ser atendidas que ya no pueden caber en la configuración de backlog de escucha para el socket de escucha en 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.

Si tuviera que adivinar, sospecharía que la gran mayoría de las solicitudes HTTP cuando el servidor se está "ahogando" está bloqueado esperando que algo vuelva de Tomcat. Apuesto a que si intentas obtener algún contenido estático que es directamente servido por apache (en lugar de ser enviado a Tomcat), esto funcionaría incluso cuando normalmente se está `` ahogando ''.

Desafortunadamente, no estoy familiarizado con tomcat, pero ¿hay alguna forma de manipular la configuración de concurrencia de esto?

Ah, y puede que tenga que considerar también la posibilidad de que sus servicios de red externos eso es limitar el número de conexiones que se está haciendo a usted hasta 300, por lo que no hace ninguna diferencia cuánto manipulación de concurrencia que está haciendo en su lado frontal si prácticamente todas las conexiones que realiza se basan en una respuesta de servicios web externos.

En uno de sus comentarios, mencionó que los datos se vuelven obsoletos después de 2 minutos. Sugeriría almacenar en caché la respuesta que obtiene de este servicio durante dos minutos para reducir la cantidad de conexiones simultáneas que conduce al servicio web externo.

Matthew Ife
fuente
2

El primer paso para solucionar este problema es habilitar el mod_status de Apache y estudiar su informe; hasta que haya hecho esto, en realidad estará caminando a ciegas. Eso no es justo. ;-)

La segunda cosa a mencionar (no me gusta que me den respuestas a preguntas que no estaba haciendo, pero ...) es usar servidores front-end más eficientes y especiales como nginx.

Además, ¿exactamente restartApache, o simplemente gracefulLy recargado ella? :)

poige
fuente
Apache reiniciado ... no es una recarga elegante
john titus
@johntitus, bueno, mod_statuses tu amigo, de todos modos. :)
poige
1

Para cualquier tipo de despliegue empresarial, el MPM prefork es la peor opción que puede hacer: engloba recursos como el negocio de nadie, y reiniciar los hilos lleva SIEMPRE en comparación con otros MPM.

Al menos cambie al MPM de trabajo (apache 2.2 y superior) o, mejor aún, actualice a la versión estable actual 2.4.2 con su evento predeterminado MPM.

Ambos manejarán fácilmente miles de conexiones concurrentes con muy poca sobrecarga.

Adaptador
fuente
gracias ... probé eso también ... sin suerte. Las conexiones TIME_WAIT siguen aumentando. El servidor deja de responder a 350 conexiones
john titus
1
No estoy de acuerdo con que sea la peor opción: es una mala elección para este contexto y es probable que los problemas se alivien utilizando el servidor roscado, pero una mejor solución sería utilizar un servidor basado en eventos (nginx o lighttpd). El evento basado en Apache no es lo suficientemente maduro como para ser considerado desde una implementación de la empresa en mi humilde opinión.
symcbean
1

Sé que es una historia vieja, pero tengo 2 comentarios.

Existe un límite codificado para la Directiva ServerLimit . http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit verá que tiene un máximo de 20000 / 200K.

Existe un límite estricto de ServerLimit 20000 compilado en el servidor (para el prefork MPM 200000). Esto está destinado a evitar los efectos desagradables causados ​​por errores tipográficos.

2º Aparentemente, nodybo mencionó que establecer esos 2 en uno es una muy mala idea :

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

significa que reutilizas el tiempo de espera temprano, ¿adivina qué? el servidor puede hablar con el cliente equivocado bajo carga pesada.

Encontré un muy buen artículo que explica eso, pero es francés ;-) http://vincent.bernat.im/fr/blog/2014-tcp-time-wait-state-linux.html

Nadir
fuente
0

extra grande con memoria de 34GB.

El hierro grande no es la forma de escalar la red, solo estás moviendo los cuellos de botella. Pero incluso con tanta memoria, sospecho que 50000 conexiones están impulsando lo que el sistema es capaz de hacer particularmente si:

Durante las horas pico, el servidor se ahoga con aproximadamente 300 procesos httpd

Sería útil si explicara lo que quiere decir con "el servidor se ahoga".

También es muy extraño tener un límite tan alto para las conexiones pero un límite muy bajo para la histéresis (servidores de reserva mínimos / máximos).

Aunque el extracto de errores que ha proporcionado no muestra el indicador "demasiados archivos abiertos", comenzaría mirando la cantidad de descriptores de archivos abiertos y la configuración de ulimit.

symcbean
fuente
El servidor se bloquea, ya que no responde incluso a los archivos html normales ...
john titus
Cambié maxClients a 3000 ahora ... sigue siendo el mismo problema
john titus
0

¿Quizás el usuario de Apache se está quedando sin identificadores de archivos permitidos? No los mencionaste en absoluto en tu publicación. ¿Cuántos identificadores de archivos tiene actualmente Apache?

Janne Pikkarainen
fuente
128192 manejadores de archivos
john titus
0

Esto es más como un comentario, pero no puedo porque tengo menos reputación. Encontré un problema exactamente similar al de @john titus.

Hicimos el conector AJP MaxThreadscerca de nuestro límite de Apache Thread para resolver el problema.

Para monitorear esto, buscamos SYN_SENT ayuda del estado del puerto netstat con el comando netstat en nuestro puerto AJP.

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

Esto se redujo a 0, que siempre fue un gran número antes del límite MaxThread establecido en el conector AJP.

Vineeth
fuente