Trucos para Mejorar el Rendimiento de Apache

Uno de los servidores WEB más populares del mundo, si no el que más, es Apache, aunque hay otros como, NGINX, que también son muy utilizados.

El caso, es que para que una página WEB vaya rápida, no basta sólo con optimizar la base de datos, el código fuente, que el servidor sea rápido, etc. El servidor WEB también tiene que estar optimizado para que la WEB cargue rápidamente y Google la posicione mejor.

Echa un vistazo a los consejos de SEO.

A continuación, te voy a explicar algunos trucos que te van a servir para optimizar el servidor WEB Apache.

Optimizando el consumo de memoria de Apache (MaxClients)

Recientemente, estaba notando un gran consumo de memoria en un servidor, a la vez que había aumentado considerablemente el número de procesos de Apache.

Tras analizarlo, me di cuenta de que las siguientes directivas estaban descompensadas (asumo que estamos trabajando en modo prefork):

  • StartServers: Es el número de procesos de apache con los que arranca nuestro servidor Web.
  • MaxClients: Es el número máximo de procesos hijo que se crearán para atender todas las peticiones WEB recibidas.
  • MaxSpareServers: Número máximo de procesos hijo esperando peticiones (idle). No debe ser demasiado alto para evitar problemas de consumo de recursos.
  • MinSpareServers: Número de procesos hijo iniciales van a estar esperando peticiones. No debe ser demasiado bajo para que Apache no tenga que estar creando nuevos procesos hijos continuamente.
  • ServerLimit: Su valor siempre será igual a MaxClients.
  • MaxRequestPerChild: Número máximo de peticiones que puede atender un proceso hijo. Una vez alcanzado el valor configurado, el proceso morirá y liberará sus recursos.

Si reviso cuánta memoria utiliza cada proceso de Apache, observo que está entre 70 y 90MB aproximadamente:

Así que si tomo 80MB de memoria como media y lo multiplico por 10 procesos de apache corriendo, significa que Apache estará consumiendo 800MB cuando tiene esos 10 procesos en marcha.

Por lo tanto, tendremos que mirar cuánta memoria libre tenemos en nuestro servidor cuando paramos Apache, para conocer el número máximo de procesos de Apache que tenemos que configurar como máximo. Es decir, el valor que pondremos en la directiva MaxClients.

Si hay más usuarios conectados que el número indicado en MaxClients, las nuevas peticiones se encolarán, por lo que MaxClients también significa el número máximo de conexiones simultáneas al servidor.

Yo procuro reservar un 20% de memoria libre para no agotar toda la que tenemos disponible en el servidor.

Ejemplo de configuración del módulo prefork:

<IfModule prefork.c>
StartServers 5
MinSpareServers 10
MaxSpareServers 15
ServerLimit 25
MaxClients 25
MaxRequestsPerChild 4000
</IfModule>

Reiniciamos Apache y comprobamos el número de procesos de Apache que han arrancado y la cantidad de memoria libre que tenemos:

Configura las directivas deflate

Las directivas deflate de Apache habilitan la compresión de los ficheros antes de ser descargados. De esta manera, si nos tenemos que descargar menos datos, más rápidamente se cargará una página WEB (no es lo mismo descargarse 100KB, que 50). Si esto se aplica a cada petición que recibimos en nuestro sitio, nos ahorramos mucho tráfico de descarga.

Obviamente, la compresión de ficheros utiliza CPU en el servidor WEB, pero si no vamos justos de consumo, no supondrá ningún problema. Más bien, se traducirá en una mejora de la velocidad de carga de nuestra WEB.

Para habilitar estas directivas, simplemente hay que tocar nuestro fichero de apache (httpd.conf) y añadir:

LoadModule deflate_module /usr/lib64/httpd/modules/mod_deflate.so
<IfModule mod_deflate.c>
 # Especificamos los tipos de archivos que queremos que se compriman
 AddOutputFilterByType DEFLATE text/plain
 AddOutputFilterByType DEFLATE text/html
 AddOutputFilterByType DEFLATE text/xml
 AddOutputFilterByType DEFLATE text/css
 AddOutputFilterByType DEFLATE text/javascript
 AddOutputFilterByType DEFLATE image/svg+xml
 AddOutputFilterByType DEFLATE application/xml
 AddOutputFilterByType DEFLATE application/xhtml+xml
 AddOutputFilterByType DEFLATE application/rss+xml
 AddOutputFilterByType DEFLATE application/atom_xml
 AddOutputFilterByType DEFLATE application/rdf+xml
 AddOutputFilterByType DEFLATE application/x-javascript
 AddOutputFilterByType DEFLATE application/x-httpd-php
 AddOutputFilterByType DEFLATE application/x-httpd-fastphp
 AddOutputFilterByType DEFLATE application/x-httpd-eruby
 AddOutputFilterByType DEFLATE application/json
 AddOutputFilterByType DEFLATE application/javascript
 AddOutputFilterByType DEFLATE application/x-font-ttf application/x-font-otf
 AddOutputFilterByType DEFLATE font/truetype font/opentype
 # Deshabilitamos la compresiM-sn deflate para cualquier tipo de contenido
 #SetOutputFilter DEFLATE. Esta se puede dejar habilitada, si los filtros anteriores fallan.
 #SetInputFilter DEFLATE
 #AddOutputFilterByType DEFLATE application/x-httpd-php
# Niveles de compresion
 DeflateCompressionLevel 7
 DeflateMemLevel 8
 DeflateWindowSize 10
</IfModule>

Luego, reiniciamos Apache.

Comprobar que la compresión con deflate está funcionando

A continuación, vamos a hacer una pequeña prueba para comprobar que Apache comprime los ficheros:

  • Miramos el tamaño del fichero jquery.js
[[email protected] Apache]# ls -la jquery.js
-rwx------ 1 puerto53 puerto53 97184 May 23 2016 jquery.js
[[email protected] Apache]#
  • Ahora accedemos a él con wget:
[[email protected] Apache]# wget --header="Accept-Encoding: gzip" https://puerto53.com/wp-includes/js/jquery/jquery.js
--2018-04-15 06:38:23-- https://puerto53.com/wp-includes/js/jquery/jquery.js
Resolving puerto53.com (puerto53.com)... 10.0.1.5
Connecting to puerto53.com (puerto53.com)|10.0.1.5|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/javascript]
Saving to: ‘jquery.js’

[ <=> ] 42,859 --.-K/s in 0s

2018-04-15 06:38:23 (209 MB/s) - ‘jquery.js’ saved [42859]
[[email protected] Apache]#

Como vemos, la compresión ha sido de la mitad del tamaño del fichero, aproximadamente.

Unificar las directivas deflate con políticas para minimizar html, mejorará el rendimiento de nuestra WEB, un factor clave para el SEO.

Habilita la caché del navegador desde el propio Apache

La primera vez que un usuario accede a nuestra página WEB, se descarga todo el contenido necesario para su carga. Sin embargo, con las directivas de Apache Expires y Cache-Control, habilitaremos ciertos ficheros para guardar en la propia caché del navegador del usuario para que no tenga que descargarse, una y otra vez los mismos ficheros cada vez que accede a nuestro sitio.

Yo lo tengo configurado así:

<ifModule mod_expires.c>
 ExpiresActive On
 ExpiresDefault "access plus 5 seconds"
 ExpiresByType image/x-icon "access plus 2592000 seconds"
 ExpiresByType image/jpeg "access plus 2592000 seconds"
 ExpiresByType image/png "access plus 2592000 seconds"
 ExpiresByType image/gif "access plus 2592000 seconds"
 ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
 ExpiresByType text/css "access plus 604800 seconds"
 ExpiresByType text/javascript "access plus 216000 seconds"
 ExpiresByType application/javascript "access plus 216000 seconds"
 ExpiresByType application/x-javascript "access plus 216000 seconds"
 ExpiresByType text/html "access plus 600 seconds"
 ExpiresByType application/xhtml+xml "access plus 600 seconds"
</ifModule>

<ifModule mod_headers.c>
 <filesMatch "\.(ico|jpe?g|png|gif|swf)$">
 Header set Cache-Control "public"
 </filesMatch>
 <filesMatch "\.(css)$">
 Header set Cache-Control "public"
 </filesMatch>
 <filesMatch "\.(js)$">
 Header set Cache-Control "private"
 </filesMatch>
 <filesMatch "\.(x?html?|php)$">
 Header set Cache-Control "private, must-revalidate"
 </filesMatch>
</ifModule>

Si la WEB está escrita con PHP, utiliza PHP-FM

PHP-FPM (Fast CGI Process Manager) es un producto  que permite integrarse con Apache 2 para atender diferentes peticiones PHP de manera simultánea para mejorar el rendimiento y la carga de la página WEB, lo que se traduce en menores tiempos de carga y muchas más peticiones concurrentes en el mismo servidor WEB.

Una de las características de PHP-FPM que mejora la velocidad de carga es la reutilización del código PHP almacenado en memoria caché. Es decir, en vez de interpretar el código PHP cada vez, lo interpreta la primera vez y el resto de las veces lo reutiliza, evitando nuevos cálculos de CPU.

Lo he probado en puerto53.com y he notado una mejora notable en la carga de este blog.

La instalación es muy sencilla.

En Linux CentOs 7, instalamos PHP-FPM así:

yum install -y php72w-fpm
systemctl enable php-fpm

Seguidamente, editamos fichero /etc/php-fpm.d/www.conf y modificamos las siguientes directivas:

;dominio de la URL
[puerto53.com]

;usuario de sistema operativo que arranca Apache
user = puerto53

;grupo al que pertenece el usuario
group = puerto53
;La IP y el puerto por donde va a escuchar el servicio de PHP-FPM
listen = 127.0.0.1:9000
;El usuario del sistema operativo propietario del servicio
listen.owner = puerto53

Ejemplo de configuración de este fichero:

[[email protected] ~]# cat /etc/php-fpm.d/www.conf |grep -v ^$ |grep -v ";"
[puerto53.com]
user = puerto53
group = puerto53
listen = 127.0.0.1:9000
listen.owner = puerto53
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 12
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 10
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
[[email protected] ~]#

Arrancamos el servicio de PHP-FPM con el comando systemctl start php-fpm y comprobamos que el puerto 9000 ya está escuchando al estar el servicio arrancado:

[[email protected] ~]# lsof -i:9000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
php-fpm 3162 root 6u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 3163 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 3164 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 3165 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 3166 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 3167 puerto53 3u IPv4 435157 0t0 TCP localhost:cslistener->localhost:52054 (ESTABLISHED)
php-fpm 3167 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
httpd 7494 puerto53 15u IPv4 436554 0t0 TCP localhost:52054->localhost:cslistener (ESTABLISHED)
php-fpm 7514 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 7528 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 7550 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 7634 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 7638 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 21240 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 21246 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 21270 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
php-fpm 21275 puerto53 8u IPv4 361759 0t0 TCP localhost:cslistener (LISTEN)
[[email protected] ~]#

Por último, configuramos Apache. Simplemente hay que añadir las siguientes directiva:

# php-fpm
SetEnv proxy-nokeepalive 1
<IfModule proxy_module>
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/app/puerto53/html/$1 timeout=600
ProxyTimeout 600
</IfModule>
# php-fpm Fin

El módulo de Apache proxy_module, debe estar habilitado.

Reiniciamos Apache y ya tenemos PHP-FPM funcionando.

Cálculo correcto del parámetro pm.max_children de PHP-FPM para un rendimiento óptimo

Lo primero que tenemos que saber es cuánta memoria consume nuestra aplicación. Lo averiguaremos con el comando:

ps -ylC php-fpm --sort:rss

En este caso vemos en la columna RSS que cada proceso de aplicación ocupa unos 90MB, aproximadamente.

A continuación, revisamos cuánta memoria libre tenemos en nuestra maquina si paramos PHP-FPM. Lo veremos con el comando:

 free -m

En este caso tenemos 1GB totalmente libre y unos 550MB de buffer caché que se pueden considerar como libres.

Pero no queremos agotar toda la memoria del servidor, así que decidimos que, como máximo, el servicio PHP-FPM utilice 1100MB de memoria. Por lo tanto:

pm.max_children: 1100 / 92 = 11,9

El parámetro pm.max_children lo configuraremos con un valor de 12.

No olvides realizar pruebas de estrés con el comando ab (Apache Bench)

Antes de publicar una página WEB al gran público, es conveniente hacer pruebas de estrés de los servidores WEB, revisar el rendimiento del Garbage Collector de Java (si la aplicación está hecha en Java) y de la base de datos, para saber si los usuarios van a experimentar problemas de lentitud o no cuando pongamos el servicio en producción.

Si es una WEB pública en Internet, hay que recordar que Google penaliza el posicionamiento cuando la página carga con lentitud. Hay estadísticas que dicen que si una página tarda más de tres segundos en cargar, se pierde el 40% de los usuarios.

Pruebas de carga con ab simulando 100 peticiones y 10 usuarios concurrentes

En el caso que nos ocupa, ab o Apache Bench nos sirve para realizar pruebas de estrés sobre una URL. Por ejemplo, lanzar 100 peticiones simulando 10 usuarios concurrentes.

Ejemplo:

[[email protected] ~]# ab -n 100 -c 10 www.google.com/index.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.google.com (be patient).....done

Server Software: gws
Server Hostname: www.google.com
Server Port: 80

Document Path: /index.html
Document Length: 10848 bytes

Concurrency Level: 10
Time taken for tests: 3.826 seconds
Complete requests: 100
Failed requests: 98
 (Connect: 0, Receive: 0, Length: 98, Exceptions: 0)
Write errors: 0
Total transferred: 1152610 bytes
HTML transferred: 1086110 bytes
Requests per second: 26.14 [#/sec] (mean)
Time per request: 382.625 [ms] (mean)
Time per request: 38.262 [ms] (mean, across all concurrent requests)
Transfer rate: 294.18 [Kbytes/sec] received

Connection Times (ms)
 min mean[+/-sd] median max
Connect: 138 139 1.0 139 142
Processing: 203 209 4.6 208 242
Waiting: 165 171 4.5 170 204
Total: 340 348 5.0 347 383 --> Petición más lenta 383ms y más rápida 340ms

Percentage of the requests served within a certain time (ms)
 50% 347
 66% 349
 75% 349
 80% 350
 90% 354
 95% 355
 98% 357
 99% 383
 100% 383 (longest request)
[[email protected] ~]#

Te puede interesar

¿Te ha gustado? ¡Compártelo!

Share on facebook
Share on twitter
Share on linkedin
Share on whatsapp
Share on telegram
Share on email

SUSCRÍBETE A PUERTO53

Recibe un email periódico con los artículos más interesantes de Puerto53.com

Antes de suscribirte lee los términos y condiciones. Gracias.

Contenido Relacionado

Este es un blog de informática. ¿Qué necesita un informático?

Portátiles

Rebajas
Lenovo S145-15IIL - Ordenador portátil 15.6" FullHD (Intel Core i5-1035G1, 8GB RAM, 512GB...
  • Pantalla de 15.6" FullHD 1920x1080 pixeles 220nits Anti-glare
  • Procesador Intel Core I5-1035G1, QuadCore, 1.0-3.6GHz
  • Memoria RAM de 4GB Soldered + 4GB DIMM DDR4-2666
Lenovo S145-15AST - Ordenador portátil 15.6" FullHD (AMD A9-9425, 8GB de RAM, 512GB SSD,...
  • Pantalla de 15,6"fullhd 1920x1080 pixeles
  • Procesador amd a9-9425, dualcore 3.1ghz hasta 3.7ghz, 1m
  • Memoria ram de 8gddr4, 2133mhz
Rebajas
HP 15s-eq0004ns - Ordenador portátil de 15.6" HD (AMD Ryzen 3 3200U, 8 GB RAM, 256 GB,...
  • Procesador AMD Ryzen 3 3200U (2 núcleos, 5 MB de Caché, 2.6 GHz hasta 3.5 GHz)
  • Memoria RAM de 8 GB DDR4, 2400 MT/s
  • Disco SSD de 256 GB PCIe NVMe M.2
Rebajas
Lenovo S145-15AST- Ordenador portátil 15.6" FullHD (AMD A9-9425, 8GB RAM, 256GB SSD, AMD...
  • Pantalla de 15.6" FullHD 1920x1080 pixeles 220nits Anti-glare
  • Procesador AMD A9-9425, DualCore, 3.1GHz-3.7GHz
  • Memoria RAM de 8GB DIMM DDR4, 2133Mhz

Monitores PC

HP 22w - Monitor 21.5" (Full HD, 1920 x 1080 pixeles, tiempo de respuesta de 5 ms, 1 x...
  • Regálale a tu escritorio un toque de elegancia
  • Esta pantalla IPS de 53.61 cm (21,5 pulgadas) en diagonal dispone de 178 ángulos de visualización para ofrecer una experiencia de entretenimiento...
  • Con los puertos VGA y HDMI, esta pantalla hace que conectar tu ordenador portátil o pc de sobremesa sea una tarea sencilla y fluida
Rebajas
Samsung LC24F390FHU - Monitor para PC Desktop de 24'' (1920 x 1080 pixeles, Full HD, HD...
  • Pantalla de 24 pulgadas con una resolución de 1920 x 1080 píxeles
  • Brillo de pantalla: 250 cd / m²
  • Interfaz de montaje VESA 75 x 75 mm
Rebajas
BenQ GW2470HL - Monitor para PC Desktop de 23.8" Full HD (1920x1080, VA, 16:9, 2x HDMI,...
  • Los niveles ajustables de baja luz azul eliminan la luz azul peligrosa y mantienen la luz beneficiosa para una comodidad de visualización prolongada
  • Disfruta de gráficos nítidos con una resolución de 1920 x 1080
  • Minimiza las distracciones y crea una configuración de varios paneles con monitores de bisel estrecho

NAS

Rebajas
Western Digital My Cloud Home - Almacenamiento En Red NAS de 3 TB, 1 Bahía, Blanco y...
  • Configuración sencilla y rápida desde el teléfono
  • Acceso desde cualquier lugar con la aplicación para móviles o para ordenadores de My Cloud Home, o bien desde MyCloud.com
  • Copia de seguridad automática de las fotos y los vídeos del teléfono
Synology Diskstation DS218+ - Memoría externa DS218+ NAS 2bay
  • Procesador de doble núcleo con aceleración de cifrado AES-NI
  • No lleva disco
  • Admite la transcodificación 4K en tiempo real
Synology DS218J Diskstation
  • A versatile entry-level 2-bay NAS for home and personal cloud storage
  • Over 113 MB/s reading, 112 MB/s writing
  • Dual-core CPU with hardware encryption engine
Synology diskstation ds120j.
  • Almacenamiento de 1 bahía fácil de usar en una nube personal para usuarios de nas inexpertos
  • Rendimiento secuencial más de 112 mb/s de lectura, 106 mb/s de escritura
  • Plataforma para compartir archivos y sincronización entre dispositivos

Deja un comentario

About Author