Ajuste del rendimiento de un servidor Apache de alta carga

12

Estoy buscando entender algunos problemas de rendimiento del servidor que estoy viendo con un servidor web (para nosotros) muy cargado. El entorno es el siguiente:

  • Debian Lenny (todos los paquetes estables + parcheados para actualizaciones de seguridad)
  • Apache 2.2.9
  • PHP 5.2.6
  • Gran instancia de Amazon EC2

El comportamiento que estamos viendo es que la web generalmente se siente receptiva, pero con un ligero retraso para comenzar a manejar una solicitud, a veces una fracción de segundo, a veces 2-3 segundos en nuestros tiempos de uso pico. La carga real en el servidor se informa como muy alta, a menudo 10.xx o 20.xx según lo informado por top. Además, ejecutar otras cosas en el servidor durante estos tiempos (incluso vi) es muy lento, por lo que la carga definitivamente está allí. Curiosamente, Apache sigue siendo muy receptivo, aparte de ese retraso inicial.

Tenemos Apache configurado de la siguiente manera, usando prefork:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

Y KeepAlive como:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Al mirar la página de estado del servidor, incluso en estos momentos de gran carga, rara vez estamos llegando al límite del cliente, por lo general atendiendo entre 80-100 solicitudes y muchas de las personas en estado de mantenimiento. Eso me dice que descarte la lentitud de la solicitud inicial como "esperar un controlador", pero puedo estar equivocado.

El monitoreo de Amazon CloudWatch me dice que incluso cuando nuestro sistema operativo informa una carga de> 15, nuestra utilización de CPU de instancia es entre 75-80%.

Ejemplo de salida de top:

top - 15:47:06 up 31 days,  1:38,  8 users,  load average: 11.46, 7.10, 6.56
Tasks: 221 total,  28 running, 193 sleeping,   0 stopped,   0 zombie
Cpu(s): 66.9%us, 22.1%sy,  0.0%ni,  2.6%id,  3.1%wa,  0.0%hi,  0.7%si,  4.5%st
Mem:   7871900k total,  7850624k used,    21276k free,    68728k buffers
Swap:        0k total,        0k used,        0k free,  3750664k cached

La mayoría de los procesos se ven así:

24720 www-data  15   0  202m  26m 4412 S    9  0.3   0:02.97 apache2                                                                       
24530 www-data  15   0  212m  35m 4544 S    7  0.5   0:03.05 apache2                                                                       
24846 www-data  15   0  209m  33m 4420 S    7  0.4   0:01.03 apache2                                                                       
24083 www-data  15   0  211m  35m 4484 S    7  0.5   0:07.14 apache2                                                                       
24615 www-data  15   0  212m  35m 4404 S    7  0.5   0:02.89 apache2            

Ejemplo de salida vmstatal mismo tiempo que el anterior:

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 8  0      0 215084  68908 3774864    0    0   154   228    5    7 32 12 42  9
 6 21      0 198948  68936 3775740    0    0   676  2363 4022 1047 56 16  9 15
23  0      0 169460  68936 3776356    0    0   432  1372 3762  835 76 21  0  0
23  1      0 140412  68936 3776648    0    0   280     0 3157  827 70 25  0  0
20  1      0 115892  68936 3776792    0    0   188     8 2802  532 68 24  0  0
 6  1      0 133368  68936 3777780    0    0   752    71 3501  878 67 29  0  1
 0  1      0 146656  68944 3778064    0    0   308  2052 3312  850 38 17 19 24
 2  0      0 202104  68952 3778140    0    0    28    90 2617  700 44 13 33  5
 9  0      0 188960  68956 3778200    0    0     8     0 2226  475 59 17  6  2
 3  0      0 166364  68956 3778252    0    0     0    21 2288  386 65 19  1  0

Y finalmente, salida de Apache server-status:

Server uptime: 31 days 2 hours 18 minutes 31 seconds
Total accesses: 60102946 - Total Traffic: 974.5 GB
CPU Usage: u209.62 s75.19 cu0 cs0 - .0106% CPU load
22.4 requests/sec - 380.3 kB/second - 17.0 kB/request
107 requests currently being processed, 6 idle workers

C.KKKW..KWWKKWKW.KKKCKK..KKK.KKKK.KK._WK.K.K.KKKKK.K.R.KK..C.C.K
K.C.K..WK_K..KKW_CK.WK..W.KKKWKCKCKW.W_KKKKK.KKWKKKW._KKK.CKK...
KK_KWKKKWKCKCWKK.KKKCK..........................................
................................................................

De mi experiencia limitada extraigo las siguientes conclusiones / preguntas:

  • Es posible que estemos permitiendo demasiadas KeepAlivesolicitudes

  • Veo algo de tiempo esperando a IO en vmstat, aunque no de manera constante y no mucho (¿creo?), Así que no estoy seguro de si esto es una gran preocupación o no, tengo menos experiencia con vmstat

  • También en vmstat, veo en algunas iteraciones una serie de procesos en espera de ser atendidos, que es a lo que atribuyo el retraso de carga de página inicial en nuestro servidor web, posiblemente erróneamente

  • Servimos una mezcla de contenido estático (75% o más) y contenido de secuencia de comandos, y el contenido de la secuencia de comandos suele ser bastante intensivo en el procesador, por lo que es importante encontrar el equilibrio adecuado entre los dos; a largo plazo, queremos mover las estadísticas a otro lugar para optimizar ambos servidores, pero nuestro software no está listo para eso hoy

Me complace proporcionar información adicional si alguien tiene alguna idea, la otra nota es que se trata de una instalación de producción de alta disponibilidad, por lo que desconfío de hacer ajustes tras ajustes, y es por eso que no he jugado con cosas como el KeepAlivevalor. todavía.

futuro
fuente
+1 Gran pregunta sangrienta, bien redactada y pensada. ¡Espero que hayas recibido la respuesta que se merece!
Dave Rix

Respuestas:

7

Comenzaré admitiendo que no me gusta mucho ejecutar cosas en las nubes, pero según mi experiencia en otros lugares, diría que esta configuración del servidor web refleja un volumen de tráfico bastante bajo. Que la cola de ejecución sea tan grande sugiere que simplemente no hay suficiente CPU disponible para manejarla. ¿Qué más hay en la pista?

Es posible que estemos permitiendo demasiadas solicitudes KeepAlive

No, keeplive aún mejora el rendimiento, los navegadores modernos son muy inteligentes al saber cuándo canalizar y cuándo ejecutar solicitudes en paralelo, aunque un tiempo de espera de 5 segundos es bastante alto y tienes MUCHOS servidores esperando, a menos que ' Tengo ENORMES problemas de latencia, recomendaría reducir esto a 2-3. Esto debería acortar un poco la cola de ejecución.

Si aún no ha instalado mod_deflate en el servidor web, le recomiendo que lo haga y agregue ob_gzhandler () a sus scripts PHP. Puedes hacer esto como un auto-antecedente:

if(!ob_start("ob_gzhandler")) ob_start();

(sí, la copresión usa más CPU, pero debería ahorrar CPU en general sacando los servidores de la cola de ejecución más rápido / manejando menos paquetes TCP, y como beneficio adicional, su sitio también es más rápido).

Recomiendo establecer un límite superior en MaxRequestsPerChild, digamos algo así como 500. Esto solo permite cierta rotación en los procesos en caso de que tenga una pérdida de memoria en alguna parte. Sus procesos httpd parecen ser ENORMES: asegúrese de haber eliminado los módulos de apache que no necesita y asegúrese de que está sirviendo contenido estático con buena información de almacenamiento en caché.

Si todavía ve problemas, entonces el problema probablemente esté dentro del código PHP (si cambia a usar fastCGI, esto debería ser evidente sin ninguna penalización de rendimiento importante).

actualizar

Si el contenido estático no varía mucho entre las páginas, entonces también podría valer la pena experimentar con:

if (count($_COOKIE)) {
    header('Connection: close');
}

en los scripts PHP también.

symcbean
fuente
Entre una variedad de buenas respuestas, estoy marcando esto como el aceptado porque usted declaró claramente que se trataba de un problema relacionado con la CPU (en gran parte debido a la mala aplicación que estamos ejecutando) y ese ciertamente fue el caso. Replegué todo en instancias 2xlarge EC2 (en lugar de grandes) y la mayoría de los problemas desaparecieron, aunque muchas de las otras características de rendimiento todavía están ahí. Solo tenemos la aplicación única ejecutándose en estos servidores, y es simplemente fea.
futuro
4

Debería considerar instalar un proxy inverso asíncrono, porque varios procesos en estado W también son bastante altos. Sus procesos de Apache parecen pasar mucho tiempo enviando contenido a clientes lentos a través de la red bloqueados en eso. Nginx o lighttpd como interfaz para su servidor Apache pueden reducir drásticamente varios procesos en estado W. Y sí, debe limitar una cantidad de solicitudes de keepalive. Probablemente valga la pena intentar apagar el keepalive.

Por cierto, 107 procesos de Apache son demasiado altos para 22 rps, pude servir 100-120 rps usando solo 5 procesos de Apache. Probablemente, el siguiente paso es perfilar su aplicación.

Alex
fuente
Sí, definitivamente estuvo de acuerdo en que la aplicación es una gran parte del problema. Fue subcontratado y desde entonces ha estado sujeto a muchos parches y otras cosas que lo han empeorado, y un esfuerzo de rediseño está en curso. Esta noche intenté desactivar KeepAlive sin ningún efecto real, y mi próximo paso es probar ese proxy inverso, probablemente con nginx basado en todo lo que he leído desde entonces.
futuro
Para seguir, he comenzado a experimentar con el proxy inverso y probablemente lo implemente en producción en el futuro cercano. Gracias (y a los demás que lo sugirieron) por la idea, no es algo con lo que haya jugado antes, pero creo que tendrá un impacto hasta que podamos hacer un rediseño completo.
futuro
1

Tiene dos filas en su vmstat que muestran que el tiempo de espera de su CPU es bastante alto, y alrededor de eso, hace un buen número de escrituras (io-bo) y cambio de contexto. Vería lo que está escribiendo bloques y cómo eliminar esa espera. Creo que la mayor mejora podría encontrarse en mejorar su disco IO. Compruebe syslog: configúrelo para escribir de forma asíncrona. Asegúrese de que la memoria caché de escritura de su controlador esté funcionando (compruébelo, es posible que tenga una batería defectuosa).

Keepalive no está causando su problema de rendimiento, le ahorra tiempo en la configuración de la conexión si no está ejecutando un caché en frente. Puede golpear un poco a MaxSpareServers para que en una crisis no esté esperando todos los tenedores.

frijoles
fuente
No estoy lo suficientemente familiarizado con syslog para saber cómo configurarlo para escrituras asincrónicas en Apache, aunque ciertamente buscaré y buscaré eso. Realicé algunos cambios esta noche relacionados con KeepAlive y MaxSpareServers sin ningún efecto real, estoy de acuerdo en dejar más repuestos, me lo perdí. Una (mala) calidad de nuestra aplicación es que escribe mucho en los archivos de sesión del usuario (sí, archivos), que es donde estoy empezando a pensar que estamos sufriendo. Tengo la opción de mover la administración de sesión a la base de datos, que es probable que intente a continuación.
futuro
Sí, estaría de acuerdo en que las escrituras de su sesión son la fuente del problema. Puede perder las escrituras del disco de la sesión si está utilizando sesiones php: instale memcache y configure session.save_handler de PHP en memcache y session.save_path en tcp : //127.0.0.1: 11211 (o donde sea que configure memcache). El registro de Apache es asíncrono de manera predeterminada, pero a veces las aplicaciones web pueden usar syslog, o syslog puede ser hablador y está haciendo una sincronización para cada línea. No parece que sea el problema en su caso, después de todo. Puede anteponer líneas de entrada de archivo con '-' en syslog.conf para omitir la sincronización.
frijoles
0

deberías considerar desactivar el keepalive como primer intento ...

con 107 solicitudes procesadas, mantendría MaxSpareServers más alto de lo que configuró ...

En mi humilde opinión a largo plazo, nginx como proxy inverso del contenido estático debe tenerse en cuenta

evcz
fuente
0

Primera sugerencia: deshabilitar keepalives. Solo lo he necesitado cuando pude identificar una situación específica en la que el rendimiento aumentó, pero en general las solicitudes / seg disminuyeron con Keepalive habilitado.

Segunda sugerencia: establezca un MaxRequestsPerChild. Hago eco de Symcbean aquí, ayudará con la transferencia del proceso en el caso de una pérdida de memoria. 500 es un buen punto de partida.

Tercera sugerencia: aumentar MaxClients. Un cálculo aproximado para esto es (memoria física - memoria utilizada por procesos que no son httpd) / tamaño de cada proceso httpd. Dependiendo de cómo se compiló httpd, este número alcanza un máximo de 255. Uso 250 para mis servidores públicos para tratar con google / yahoo / MS que rastrea los sistemas.

Cuarta sugerencia: Aumente MaxSpareServers: algo así como 4-5x MinSpareServers.

Al descartar esas sugerencias que fallan, miraría el equilibrio de carga con proxy inverso o memcache para DB.

Paul S
fuente