Problema

Los entornos de atención médica manejan datos sensibles y flujos de trabajo que no pueden interrumpirse. En muchos casos la infraestructura sigue siendo una combinación de servidores legacy (PHP + Apache + FastCGI) y hardware de escritorio que no está pensado para operar 24 horas al día, 7 días a la semana. Cuando la carga alcanza cientos de usuarios concurrentes y la tolerancia a fallos es cero, la falta de redundancia, de replicación de datos y de un plan de recuperación rápida se vuelve un riesgo inaceptable. El desafío es migrar a una arquitectura de alta disponibilidad (HA) que sea manejable por un equipo pequeño, que aproveche tecnologías de código abierto y que ofrezca recuperación casi en tiempo real para bases de datos críticas como MySQL.

Causa

  1. Hardware monolítico – Un solo PC i9 actúa como servidor de aplicación y base de datos. Si falla el hardware, todo el sistema se detiene.
  2. Ausencia de capa de orquestación – Sin un hypervisor o contenedores, la gestión de recursos, snapshots y migraciones en vivo es manual y propensa a errores.
  3. Almacenamiento sin replicación – Los discos locales no se sincronizan con un nodo de respaldo, por lo que cualquier pérdida de datos es irreversible.
  4. Failover de base de datos inexistente – MySQL corre en modo standalone; si el proceso muere, no hay réplica lista para asumir la carga.
  5. Red de enrutamiento estática – Un único punto de entrada (Apache) sin balanceador o proxy reverso genera cuellos de botella y dificulta la conmutación por error.

Estos factores se combinan para crear un punto único de falla (SPOF) que no es aceptable en un entorno clínico.

Solución

Una arquitectura basada en Proxmox VE con tres nodos (dos nodos de producción y un nodo “witness” ligero) permite distribuir máquinas virtuales (VM) y contenedores LXC. Cada nodo ejecuta un pool ZFS y utiliza ZFS send/receive para replicación continua. Las bases de datos MySQL se despliegan en contenedores LXC con replicación semisíncrona (GTID) y se exponen mediante NGINX como reverse proxy y balanceador de carga.

Paso a paso resumido

  1. Instalar Proxmox VE en los dos servidores de producción y en el mini‑PC witness. Configurar la red con al menos dos interfaces: una para tráfico de gestión y otra para tráfico de datos/cliente.
  2. Crear pools ZFS (tank) en cada nodo con discos dedicados (mirrored vdev recomendado).
  3. Configurar replicación ZFS entre los pools de los nodos de producción. La replicación debe ser asíncrona pero con intervalos de 5 s a 30 s para mantener la latencia mínima.
  4. Desplegar LXC containers para MySQL y para los servicios PHP. Cada contenedor recibe su propio dataset ZFS (tank/mysql, tank/web).
  5. Habilitar MySQL GTID replication con un nodo primario y un nodo secundario. Configurar semi-sync para que el primario espere al menos una confirmación del esclavo antes de confirmar la transacción.
  6. Instalar NGINX en una VM o contenedor dedicado y usar upstream con health checks para dirigir el tráfico a los nodos web activos.
  7. Activar HA en Proxmox: marcar las VMs/LXC como “HA managed” y asignar un “failover group” que incluya los dos nodos de producción.
  8. Probar failover: apagar un nodo, verificar que las VMs se migran automáticamente y que MySQL sigue sirviendo lecturas/escrituras desde la réplica.

Detalles críticos

  • ZFS replication: usar zfs send -R -i @lastsnap tank/dataset@snap | ssh root@peer zfs receive -F tank/dataset. Programar snapshots cada minuto con cron y habilitar zfs hold para evitar borrados prematuros.
  • MySQL semi‑sync: en my.cnf del primario, rpl_semi_sync_master_enabled=1. En el esclavo, rpl_semi_sync_slave_enabled=1. Reiniciar y crear el canal de replicación con CHANGE MASTER TO MASTER_HOST='ip‑esclavo', MASTER_USER='repl', MASTER_PASSWORD='***', MASTER_AUTO_POSITION=1; START SLAVE;.
  • NGINX health check: proxy_next_upstream error timeout http_502 http_503 http_504; y upstream web { server 10.0.1.10:80 max_fails=3 fail_timeout=30s; server 10.0.1.11:80 backup; }.

Cuándo aplicar esta solución

  • Entornos críticos 24/7 donde la pérdida de disponibilidad implica riesgo de salud o multas regulatorias.
  • Cargas moderadas a altas (decenas a cientos de usuarios concurrentes) que pueden ser manejadas por hardware de clase servidor (ProLiant, Dell PowerEdge, etc.).
  • Equipos con conocimientos básicos de Linux y virtualización; la curva de aprendizaje de Proxmox y ZFS es razonable para un sysadmin junior con apoyo de documentación.

No es adecuada cuando:

  • La infraestructura está distribuida geográficamente y requiere replicación WAN con latencias superiores a 100 ms.
  • Se necesita un nivel de consistencia estricta (transacciones ACID en tiempo real) que sólo una solución de base de datos clusterizada (Galera, Percona XtraDB) pueda ofrecer.

Código

# 1. Crear snapshot cada minuto (cron: * * * * *)
/usr/sbin/zfs snapshot -r tank/web@$(date +\%Y\%m\%d\%H\%M)

# 2. Replicar incremental al nodo secundario
lastsnap=$(zfs list -t snapshot -H -o name -s creation -r tank/web | tail -2 | head -1)
zfs send -R -i $lastsnap tank/web@$(date +\%Y\%m\%d\%H\%M) | \
ssh root@10.0.1.11 "zfs receive -F tank/web"

# 3. Configuración mínima de MySQL semi‑sync (en primario)
cat >> /etc/mysql/mysql.conf.d/mysqld.cnf <<EOF
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
EOF
systemctl restart mysql

# 4. Crear usuario de replicación
mysql -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'StrongPass!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;"

# 5. Configurar esclavo
mysql -h 10.0.1.10 -u repl -pStrongPass! -e "
CHANGE MASTER TO MASTER_HOST='10.0.1.10',
MASTER_USER='repl',
MASTER_PASSWORD='StrongPass!',
MASTER_AUTO_POSITION=1;
START SLAVE;
"

Verificación

  1. Snapshot y replicación: ejecutar zfs list -t snapshot -r tank/web en ambos nodos y confirmar que los nombres coinciden.
  2. Estado de MySQL: mysql -e "SHOW SLAVE STATUS\G" debe mostrar Seconds_Behind_Master = 0 y Rpl_semi_sync_slave_status = ON.
  3. HA de Proxmox: desde la GUI, detener una VM marcada como HA y observar que el daemon pve-ha-crm la migra automáticamente al nodo activo.
  4. NGINX: usar curl -I http://ip‑vip/ antes y después de apagar un nodo web; la respuesta debe seguir viniendo sin error 502/504.

Notas adicionales

  • Latencia de ZFS: la replicación incremental es muy rápida en LAN Gigabit, pero si la red cae a 100 Mbps la ventana de consistencia puede ampliarse. Monitorea el tiempo entre snapshots y ajusta la frecuencia.
  • Backup offline: aunque la replicación cubre la disponibilidad, sigue necesitando backups periódicos (por ejemplo, zfs send -R tank/web@snap | gzip > /mnt/backup/web_$(date +%F).gz).
  • Mantenimiento de hardware: el nodo witness no necesita discos de alta capacidad, pero sí una conexión de red estable; su función es romper empates de quorum.
  • Actualizaciones de Proxmox: realiza pruebas en un nodo de prueba antes de aplicar parches al cluster productivo; la actualización de kernel puede requerir reinicio de los nodos y, por tanto, una ventana de failover controlada.
  • Seguridad: restringe el acceso SSH entre nodos a claves específicas y habilita firewalld o iptables para limitar puertos a los necesarios (22, 8006, 3306, 80/443).

Con esta arquitectura se consigue una solución reutilizable que cubre la mayoría de los requerimientos de disponibilidad en clínicas, hospitales o cualquier organización que no pueda permitirse interrupciones. La combinación de Proxmox, ZFS y MySQL semi‑sync ofrece un equilibrio entre complejidad operativa y robustez, permitiendo a equipos pequeños mantener un entorno fiable sin depender de soluciones propietarias costosas.