Planificación de una arquitectura multiservidor para una infraestructura dedicada

Guía de planificación de una arquitectura multiservidor para una infraestructura dedicada

Un solo servidor dedicado suele bastar para gestionar la mayoría de las aplicaciones web en producción. Pero llega un momento en que ya no es suficiente: ya sea porque el tráfico ha crecido más allá de lo que un solo servidor puede soportar, porque necesitas redundancia para que un fallo de hardware no deje la aplicación fuera de servicio, o porque tu base de datos se ha vuelto tan grande que debería ejecutarse en hardware dedicado…

Cuando un único servidor deja de ser la solución adecuada

Los motivos para pasar a una arquitectura multiservidor son muy concretos. El simple argumento de «estamos creciendo» no basta: los costes y la complejidad de una infraestructura multiservidor son reales, y la optimización de un solo servidor suele alargar el margen de maniobra más de lo que los equipos esperan.

Pasa a una arquitectura multiservidor cuando:

  • El promedio de carga supera constantemente el número de núcleos durante las horas de tráfico normal, no solo en los picos. Un servidor de 16 núcleos con un promedio de carga sostenido superior a 20 está acumulando trabajo en cola.
  • Tu base de datos y tu aplicación compiten por la misma memoria RAM. El almacenamiento en caché de Redis, el búfer de MySQL InnoDB, los procesos de PHP-FPM y la memoria de la aplicación comparten la misma memoria RAM física en un único servidor. Llega un momento en el que el rendimiento de la base de datos y el de la capa web se ven directamente afectados el uno por el otro.
  • Un fallo de hardware se consideraría un incidente operativo. Si el tiempo de inactividad del servidor durante su sustitución (normalmente entre 2 y 4 horas) te supondría un coste significativo, necesitas redundancia.
  • La implementación requiere tiempo de inactividad. Las configuraciones con varios servidores permiten realizar implementaciones progresivas; en cambio, las implementaciones en un solo servidor suelen requerir desconectar la aplicación durante las actualizaciones.

Nivel 1: Separación entre la web y la base de datos

La primera configuración multiserver significativa separa el nivel de la aplicación web del nivel de la base de datos. Esto resuelve el problema de la contienda por la memoria RAM y permite que cada servidor se optimice para su función.

Servidor web: Nginx, PHP-FPM, código de la aplicación, caché Redis. Configuración optimizada para la CPU. Los planes Essential o Elite de InMotion son los más adecuados para la mayoría de las aplicaciones en esta fase.

Servidor de bases de datos:PostgreSQL, gran pool de búfer InnoDB (70-80 % de la RAM), configuración optimizada de E/S de disco. Configuración optimizada para memoria. Los 192 GB de RAM DDR5 del servidor Extreme lo convierten en un excelente servidor de bases de datos dedicado: un pool de búfer InnoDB de 130-150 GB mantiene la mayoría de las bases de datos de producción íntegramente en memoria.

La conectividad de red entre los dos servidores es importante. Ambos servidores deben estar alojados en el mismo centro de datos de InMotion para garantizar una comunicación de red privada de baja latencia. La configuración de la aplicación debe dirigir las conexiones a la base de datos a la IP privada del servidor de la base de datos, en lugar de a localhost:

// WordPress wp-config.php

define('DB_HOST', '10.0.0.2'); // Database server private IP

define('DB_NAME', 'production_db');

define('DB_USER', 'app_user');

define('DB_PASSWORD', 'secure_password');

MySQL on the database server should bind to the private interface and accept connections only from the web server IP:

# /etc/mysql/mysql.conf.d/mysqld.cnf

bind-address = 10.0.0.2

# Grant access only from web server

# GRANT ALL ON production_db.* TO 'app_user'@'10.0.0.1' IDENTIFIED BY 'password';

Nivel 2: Nivel web con equilibrio de carga

Cuando un solo servidor web ya no es suficiente, añadir un segundo servidor web detrás de un equilibrador de carga distribuye el tráfico y garantiza la continuidad del servicio en caso de que falle uno de los servidores web.

HAProxy es el equilibrador de carga de código abierto estándar para esta configuración. Se ejecuta en un servidor pequeño (o en el servidor de la base de datos si los recursos lo permiten) y distribuye las solicitudes por toda la capa web:

global

    maxconn 50000

    log /dev/log local0

defaults

    mode http

    timeout connect 5s

    timeout client 30s

    timeout server 30s

    option httplog

frontend web_frontend

    bind *:80

    bind *:443 ssl crt /etc/ssl/certs/production.pem

    default_backend web_servers

backend web_servers

    balance roundrobin

    option httpchk GET /health

    server web1 10.0.0.1:80 check inter 2s

    server web2 10.0.0.2:80 check inter 2s

La directiva «httpchk» envía solicitudes de comprobación de estado a la ruta «/health» de cada servidor web cada 2 segundos. Los servidores que no superan las comprobaciones de estado se eliminan automáticamente de la rotación. La guía de configuración de HAProxy explica cómo configurar las comprobaciones de estado al detalle, incluyendo la comparación de códigos de respuesta y los umbrales de fallo.

El estado de la sesión debe almacenarse fuera de los servidores web. Cuando el equilibrio de carga distribuye las solicitudes entre varios servidores web, cada solicitud puede llegar a un servidor diferente. Los datos de sesión almacenados en el gestor de sesiones predeterminado de PHP, basado en archivos, no estarán disponibles en el otro servidor. Almacena las sesiones en Redis en el servidor de la base de datos:

# /etc/php/8.x/fpm/php.ini

session.save_handler = redis

session.save_path = "tcp://10.0.0.3:6379"

Todos los servidores web apuntan a la misma instancia de Redis. Cualquier servidor web puede atender cualquier solicitud, independientemente de qué servidor haya gestionado las solicitudes anteriores del mismo usuario.

Nivel 3: Alta disponibilidad de la base de datos

La redundancia en el nivel web sin redundancia en la base de datos deja un único punto de fallo en la capa de la base de datos. La replicación o la agrupación en clústeres de MySQL proporcionan redundancia a nivel de la base de datos.

La replicación de MySQL entre un servidor principal y réplicas es la configuración de alta disponibilidad más sencilla. El servidor principal se encarga de todas las escrituras; las réplicas reciben los cambios a través de la replicación del registro binario y pueden gestionar las consultas de lectura.

# Primary server my.cnf

[mysqld]

server-id = 1

log_bin = /var/log/mysql/mysql-bin.log

binlog_format = ROW

sync_binlog = 1

innodb_flush_log_at_trx_commit = 1

# Replica server my.cnf

[mysqld]

server-id = 2

relay-log = /var/log/mysql/relay-bin.log

read_only = 1

Para la conmutación automática por error (promover una réplica a primaria si falla la primaria), Orchestrator es la herramienta estándar para la gestión de la topología de MySQL. Orchestrator supervisa la topología de replicación y puede ejecutar la promoción automática, con integraciones para Consul o ZooKeeper para la coordinación de la conmutación por error basada en DNS.

MySQL InnoDB Cluster ofrece replicación síncrona con conmutación automática por fallo, a cambio de una mayor latencia en las escrituras (las escrituras deben ser confirmadas por un quórum de nodos antes de que se validen). Para aplicaciones en las que la pérdida de datos durante la conmutación por fallo es inaceptable, el modelo síncrono de InnoDB Cluster ofrece mayores garantías que la replicación asíncrona. La documentación de Group Replication de MySQL explica la configuración y las consideraciones operativas.

Diagrama de arquitectura: configuración de producción con tres servidores

[Load Balancer / HAProxy]

                         10.0.0.0:80,443

                        /               \

              [Web Server 1]         [Web Server 2]

               10.0.0.1               10.0.0.2

               Nginx + PHP            Nginx + PHP

                        \               /

                    [Database Server]

                         10.0.0.3

                    MySQL Primary + Redis

                         |

                    [DB Replica]

                         10.0.0.4

                    MySQL Replica

Esta configuración se encarga de:

  • Fallo en el nivel web: HAProxy retira el servidor web que ha fallado; el servidor restante se encarga de todo el tráfico
  • Fallo en la réplica de la base de datos: la aplicación sigue escribiendo en la base de datos principal; la réplica se vuelve a conectar y se pone al día
  • Fallo del servidor principal de la base de datos: Orchestrator eleva la réplica a servidor principal; las actualizaciones del DNS redirigen la aplicación al nuevo servidor principal

Lo que no cubre: el fallo del equilibrador de carga. Añadir redundancia con HAProxy y Keepalived (para la conmutación por error de la dirección VIP entre dos instancias de HAProxy) soluciona ese último punto único de fallo.

Almacenamiento compartido de archivos entre servidores web

Las aplicaciones web que permiten subir archivos (imágenes, documentos, contenido generado por los usuarios) necesitan que esos archivos sean accesibles desde todos los servidores web. Los archivos subidos a web1 deben poder leerse desde web2.

Tres enfoques, ordenados por complejidad:

Montaje NFS: un servidor exporta un directorio a través de NFS; los demás lo montan. Es sencillo, pero el servidor NFS se convierte en un punto único de fallo y en un cuello de botella de E/S cuando se escala.

GlusterFS: un sistema de archivos distribuido que replica los datos en varios servidores. Es más complicado de configurar, pero elimina el punto único de fallo.

Almacenamiento de objetos con interfaz CDN: sube archivos directamente a un almacenamiento de objetos compatible con S3 (o al almacenamiento de copias de seguridad de InMotion como área de preparación) y sírvelos a través de CDN. La arquitectura más sencilla para aplicaciones nuevas: sin necesidad de gestionar un sistema de archivos compartido.

En el caso de las aplicaciones ya existentes, NFS suele ser la forma más rápida de acceder a archivos en varios servidores. Para las aplicaciones diseñadas desde el principio para funcionar en varios servidores, el almacenamiento de objetos con distribución mediante CDN evita por completo un tipo de complejidad operativa.

Planificar la progresión

No hace falta implementar la arquitectura multiservidor de una sola vez. El proceso suele ser el siguiente:

  1. Empieza con un servidor único bien configurado (InMotion Essential o Extreme, dependiendo de la carga de trabajo)
  2. Separa la base de datos en su propio servidor cuando la saturación de la RAM o de E/S sea apreciable
  3. Añade un segundo servidor web y un equilibrador de carga cuando la saturación de la CPU sea constante
  4. Incorpora la replicación de bases de datos cuando los requisitos empresariales exijan reducir el riesgo de tiempo de inactividad
  5. Añade redundancia con HAProxy cuando el propio equilibrador de carga se convierte en el último punto único de fallo

Cada paso aumenta los costes y la complejidad operativa. Pasa al siguiente nivel cuando las limitaciones actuales sean cuantificables, no anticipándote a limitaciones con las que aún no te has topado.

Lecturas relacionadas: Infraestructura híbrida: combinación de recursos dedicados y en la nube | Supervisión de recursos de servidor y optimización del rendimiento

Comparte este artículo

Deja una respuesta

Tu dirección de correo electrónico no se publicará. Los campos obligatorios están marcados con *.