[apache] benchmark de diversas configuraciones de Apache+PHP

He estado configurando un load-balance de servidores Apache2; claro, usando nginx como proxy reverso, una de las dudas que me saltó durante las pruebas fue:
¿cómo lograr el máximo rendimiento en cada nodo?, y es que, cada nodo de apache2 se ejecuta en una máquina virtual con una ínfima cantidad de RAM, así que, manos a la obra, decidí tomar el control del asunto.

Apache y MPM

Los “módulos de multi-procesamiento” (“Multi-Processing Modules” ó MPM) es como llama apache a sus módulos que procesan las solicitudes.

mpm_prefork: el más antiguo y utilizado por usuarios de PHP, prefork genera procesos de apache con el interprete PHP imbuido (mod_php), es el más sencilo de configurar (apt-get install apache2-mpm-prefork libapache2-mod-php5); sin embargo, prefork tiene el inconveniente de tener que integrar un compilador de PHP en cada proceso, por consiguiente el consumo de recursos ante sitios con alta demanda, es excesivo.

mpm_worker: en worker no sólo se generan procesos, sino que cada proceso puede generar múltiples hilos, al procesar múltiples hilos de manera asincrónica a la vez, podemos consumir menos recursos que levantar un proceso de apache por cada solicitud

mpm_event: es una versión más reciente de worker, los procesos padre generan hilos “principales”, dichos hilos principales pueden “pasar” procesos a hilos hijos (creados por demanda) para asumir nuevas solicitudes, event tiene una característica de trabajo muy parecida al modo asíncrono multi-hilado de Nginx.

Las pruebas:

Hemos instalado el siguiente servidor (una máquina virtual) muy sencilla:

Servidor: Debian Wheezy 7.0
RAM: 512MB
Document Size: 70Kb
CPUs: 1

Usando apache benchmark, con una configuración muy simple:
ab -n 100 -c 50 http://web1.example.net/test.php

Donde test.php contiene un “loop” sencillo y un phpinfo().

He decidido probar las diferentes combinaciones tomando el mejor de 10 resultados.

Resultados (raw)

* apache mpm_prefork + mod_php:

la clásica combinación MPM_PREFORK+MOD_PHP.

Server API: Apache 2.0 Handler

Concurrency Level: 50
Time taken for tests: 37.756 seconds
Complete requests: 100
Failed requests: 14
 (Connect: 0, Receive: 0, Length: 14, Exceptions: 0)
Write errors: 0
Total transferred: 6701286 bytes
HTML transferred: 6674386 bytes
Requests per second: 2.65 [#/sec] (mean)
Time per request: 18877.780 [ms] (mean)
Time per request: 377.556 [ms] (mean, across all concurrent requests)
Transfer rate: 173.33 [Kbytes/sec] received

* apache mpm_worker + php5-fpm + fastcgi:

hemos combinado PHP5-FPM (vía socket, es unos 15% más rápido así que vía TCP, ya que te quitas unas cuantas capas del transporte TCP/IP) + fastcgi (el modo por defecto de configurar FPM, ya que fcgid no permite enviar solicitudes a procesos remotos).

Server API FPM/FastCGI

Concurrency Level: 50
Time taken for tests: 33.945 seconds
Complete requests: 100
Failed requests: 5
 (Connect: 0, Receive: 0, Length: 5, Exceptions: 0)
Write errors: 0
Total transferred: 7714795 bytes
HTML transferred: 7680695 bytes
Requests per second: 2.95 [#/sec] (mean)
Time per request: 16972.487 [ms] (mean)
Time per request: 339.450 [ms] (mean, across all concurrent requests)
Transfer rate: 221.95 [Kbytes/sec] received

Nota: el uso de RAM es muy eficiente usando php5-fpm, nunca consumiendo más de 140MB de RAM.

* apache mpm_worker + php5-cgi + mod_ fcgid:

combinamos mpm_worker con PHP5 en modo fastCGI pero usando fcgid

Server API CGI/FastCGI

Concurrency Level: 50
Time taken for tests: 32.200 seconds
Complete requests: 100
Failed requests: 8
 (Connect: 0, Receive: 0, Length: 8, Exceptions: 0)
Write errors: 0
Total transferred: 7641087 bytes
HTML transferred: 7606987 bytes
Requests per second: 3.11 [#/sec] (mean)
Time per request: 16099.806 [ms] (mean)
Time per request: 321.996 [ms] (mean, across all concurrent requests)
Transfer rate: 231.74 [Kbytes/sec] received

* apache mpm_event + php5-cgi + mod_fcgid:

realizamos la misma combinación, pero sustituyendo mpm_worker por mpm_event.

Server API CGI/FastCGI

Concurrency Level: 50
Time taken for tests: 46.755 seconds
Complete requests: 100
Failed requests: 8
 (Connect: 0, Receive: 0, Length: 8, Exceptions: 0)
Write errors: 0
Total transferred: 7641191 bytes
HTML transferred: 7607091 bytes
Requests per second: 2.14 [#/sec] (mean)
Time per request: 23377.675 [ms] (mean)
Time per request: 467.553 [ms] (mean, across all concurrent requests)
Transfer rate: 159.60 [Kbytes/sec] received

* apache mpm_event + fastcgi + php5-fpm:

La misma combinación de fastcgi + php5-fpm, pero usando mpm_event

Server API FPM/FastCGI

Concurrency Level: 50
Time taken for tests: 35.976 seconds
Complete requests: 100
Failed requests: 10
 (Connect: 0, Receive: 0, Length: 10, Exceptions: 0)
Write errors: 0
Total transferred: 7714787 bytes
HTML transferred: 7680687 bytes
Requests per second: 2.78 [#/sec] (mean)
Time per request: 17987.970 [ms] (mean)
Time per request: 359.759 [ms] (mean, across all concurrent requests)
Transfer rate: 209.42 [Kbytes/sec] received

Nota: se incrementó hasta 400 conexiones con 100 niveles de concurrencia, los valores de conexión y procesamiento se mantuvieron invariables.

 

Las gráficas

… y es que la gente le encanta un gráfico

conexion

El primero representa el tiempo que tarda Apache en recibir una conexión y procesarla, como vemos, aun con pocas solicitudes, prefork se va **adelante** (pues el servidor con solo 512MB de RAM estaba a punto de irse a la SWAP), mientras, mpm_event fue más diligente en conectarse y procesar rápidamente las solicitudes, sin tomar en cuenta cuanto más tardó en transmitirlas.

Ganador: Empate entre MPM-Event+PHP5-FPM y MPM-Event+PHP5-CGI+FCGID

tiempo-total

El tiempo total de la prueba, es lo que tardó Apache desde que se inició el apache-benchmark hasta que se completaron las 100 solicitudes, como vemos (y muy interesante el resultado) event-fcgid fue el peor en el resultado, tardando incluso más que mpm_prefork en conectar-procesar y transmitir resultados, de manera paradójica, la misma configuración pero usando mpm_worker fue la mejor de todas.

Ganador: MPM-Worker+PHP5-CGI+mod_fcgidsolicitud

En general, los resultados fueron parejos, sin embargo, worker-fcgid aparece nuevamente victorioso acá, además, en promedio terminó más solicitudes por segundo (unas 3.11 solicitudes/seg versus 2.9 de worker-fpm).

Ganador: MPM-Worker+PHP5-CGI+mod_fcgid
transfer-rate

 

La velocidad de respuesta, o rata de transferencia de los datos desde el servidor hacia el cliente, es también muy importante, como vemos, Worker-fcgid aparece con una velocidad más alta que el resto.

Ganador: MPM-Worker+PHP5-CGI+mod_fcgid

… ¿Y por qué no Nginx?

Con un conjunto de VPS, uso de .htaccess, facilidad de implementación de instalaciones adaptadas a apache2, en uso de apache2 es *casi* que una obligación en el proyecto que estoy realizando, sin embargo, es más que notable la diferencia de Nginx+PHP5-FPM versus el resto de configuraciones.

Pero para este caso en particular, necesitaba apache2.

Las conclusiones

Es precipitado adelantarse a dar ganadores sin explicar para qué se podría utilizar cada combinación, por ejemplo, mpm_prefork se muy sencillo de configurar y para sitios web con muy pocas visitas y si el recurso no es problema, con APC (o xcache) más mod_deflate+mod_expires puede superar a cualquiera de las configuraciones actuales.

Para sitios web con muchísimo tráfico y tiempos de respuesta cortos, es obvio que MPM-Worker+PHP5-CGI+mod_fcgid podría rendir mejor que cualquier otra combinación (MPM-Event+PHP5-FPM+FastCGI podría ser una segunda opción); sin embargo, hay que recordar que mod_fcgid no permite llamar procesos externos (como PHP5-FPM).

PHP5-FPM aparece como una buena opción (en conjunto con MPM-Worker, aunque mejores números, MPM-Event suele consumir más recursos como RAM y CPU que Worker) para pequeños servidores con bajos recursos, PHP5-FPM es bastante óptimo (durante las pruebas Apache+PHP-FPM+todo el sistema operativo no consumían más de 150MB de RAM), además la posibilidad de “compartir” el proceso PHP5-FPM con otras instancias (de apache o de nginx) tanto en el servidor como en otros servidores, nos brindan un ahorro notable de recursos.

La gran sorpresa de la noche fue mpm_event, tal vez me faltó algún detalle de configuración, sin embargo, ver que MPM_EVENT consume más recursos que mpm_worker y además, no rinde mejor que este … me hace dudar de implementarlo con PHP.

Acerca de phenobarbital

http://about.me/phenobarbital

Publicado el 16 julio 2013 en Blogeando!, La nota del día, Linux, PlanetaLinux, Software Libre, trucos de la abuela y etiquetado en , , , , , , . Guarda el enlace permanente. 3 comentarios.

  1. Excelente articulo y muy útil éste tipo de comparativas; me hubiese gustado compararas también los distintos mpm con mod_suphp. Saludos.

  2. Gracias por la aclaratoria, siempre me confundo con los términos y abreviaturas. Saludos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: