miércoles, 27 de agosto de 2014

Configurar la concurrencia en Apache y MySQL

Llega un momento en el que una aplicación Web tiene tanto éxito que el número de conexiones concurrentes satura las capacidades del servidor. Empiezan a aparecer errores de timeout o errores 500 Internal Server Error.

Para evitar ésto, se puede configurar Apache y MySQL para que admitan más concurrencia, es decir, más conexiones funcionando al mismo tiempo.

Concurrencia en Apache

Para configurar la concurrencia en Apache, hemos de configurar el archivo httpd.conf (el archivo será apache2.conf si está instalado en un Linux basado en Debian e instalado mediante sudo apt-get install apache2) o el archivo 000-default.conf.

Lo primero que debemos hacer es extraer la configuración actual de Apache. Para ello ejecutaremos el siguiente comando desde la terminal:

$ apache2 -V

El resultado será similar al siguiente:
Server version: Apache/2.2.22 (Debian)
Server built: Jul 24 2014 15:34:00
Server's Module Magic Number: 20051115:30
Server loaded: APR 1.4.6, APR-Util 1.4.1
Compiled using: APR 1.4.6, APR-Util 1.4.1
Architecture: 64-bit
Server MPM: Prefork
threaded: no
forked: yes (variable process count)
Server compiled with....
-D APACHE_MPM_DIR="server/mpm/prefork"
-D APR_HAS_SENDFILE
-D APR_HAS_MMAP
-D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
-D APR_USE_SYSVSEM_SERIALIZE
-D APR_USE_PTHREAD_SERIALIZE
-D APR_HAS_OTHER_CHILD
-D AP_HAVE_RELIABLE_PIPED_LOGS
-D DYNAMIC_MODULE_LIMIT=128
-D HTTPD_ROOT="/etc/apache2"
-D SUEXEC_BIN="/usr/lib/apache2/suexec"
-D DEFAULT_PIDLOG="/var/run/apache2.pid"
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
-D DEFAULT_LOCKFILE="/var/run/apache2/accept.lock"
-D DEFAULT_ERRORLOG="logs/error_log"
-D AP_TYPES_CONFIG_FILE="mime.types"
-D SERVER_CONFIG_FILE="apache2.conf"

Los primeros ajustes a realizar son:

  • KeepAlive On: Permite conexiones persistentes (más de una petición por conexión)
  • MaxKeepAliveRequests 100: Número máximo de peticiones permitidas durante una conexión persistente
  • KeepAliveTimout 5: Número de segundos de espera para la próxima petición en la misma conexión

A continuación, se ha de configurar el módulo de multiprocesamiento (MPM). En el ejemplo anterior lo conoceremos por la primera línea de la sección "Server compiled with...", en el parámetro APACHE_MPM_DIR. Como se puede observar, el módulo de multiprocesamiento es prefork. Por tanto, hemos de buscar en el archivo de configuración de Apache la sección correspondiente a este módulo, el cual contendrá los siguientes parámetros:

<IfModule mpm_prefork_module>
   StartServers 50
   MinSpareServers 20
   MaxSpareServers 70
   ThreadLimit 64
   ThreadsPerChild 25
   ServerLimit 500
   MaxClients 500
   MaxRequestsPerChild 0
</IfModule>

Los significado de estos parámetros es el siguiente:

  • StartServers: Número de servidores con los que arranca
  • MinSpareServers: Número mínimo de procesos de servidor que se mantienen de repuesto
  • MaxSpareServers: Número máximo de procesos de servidor que se mantienen de respuesto
  • ThreadLimit: Número máximo de hilos concurrentes
  • ThreadsPerChild: Número de hilos en funcionamiento en cada proceso del servidor
  • ServerLimit: Núḿeros máximo de servidores
  • MaxClients: Número máximo de procesos de servidor con los que arranca
  • MaxRequestsPerChild: Número máximo de peticiones que un proceso puede servir

NOTA: En el caso de nuestro Apache no tenga instalado un módulo de multiprocesamiento, podemos instalar uno mediante los siguientes comandos:

sudo apt-get update
sudo apt-get install apache2-mpm-prefork

Concurrencia en MySQL

Aunque configuremos Apache para que abastezca una gran cantidad de concurrencia, si nuestras webs acceden a bases de datos MySQL, encontrarán otro cuello de botella, pues MySQL también tiene una configuración predeterminada de concurrencia a la base de datos (unas 100 conexiones).

Para ajustar la concurrencia en MySQL, hemos de editar en el archivo my.cnf los siguientes parámetros:

  • max_connections: Número máximo de conexiones
  • thread_concurrency: Número de hilos concurrentes

A continuación, hay que rearrancar la base de datos para que MySQL asuma los cambios:

/etc/init.d/mysql restart

NOTA: Este comando es para Linux. En Windows, es similar, salvo la ruta.

Por último, verificamos que MySQL está funcionando con los valores actualizados. Para ello, arrancamos el cliente MySQL:

mysql -u root -p

Una vez nos logamos como administrador (hay que introducir la contraseña), en la línea de comandos del cliente MySQL introducimos la siguiente sentencia:

mysql> SHOW VARIABLES;

Buscamos las variables max_connections y thread_concurrency para verificar sus valores.