Alta disponibilidad de MySQL en producción: clúster InnoDB, replicación de grupo y operadores Kubernetes
Una guía para ingenieros de producción sobre InnoDB Cluster, Group Replication, MySQL Operador para Kubernetes, Percona XtraDB Cluster, estrategias de múltiples nubes e implementaciones bare metal de k3s/Rancher con almacenamiento Longhorn
Ejecutar MySQL en producción es un territorio familiar para la mayoría de los equipos de ingeniería. Ejecutarlo con alta disponibilidad genuina, donde una falla de nodo, una partición de red o una zona de disponibilidad completa que se apaga no resulta en tiempo de inactividad o pérdida de datos, requiere una arquitectura deliberada. Esta guía recorre cada capa de esa arquitectura: desde las primitivas de replicación dentro del propio MySQL, pasando por los operadores Kubernetes que automatizan la administración del ciclo de vida, pasando por las opciones administradas y autoadministradas en todos los principales proveedores de la nube, hasta los clústeres k3s sin sistema operativo administrados por Rancher.
Al final de este artículo, tendrá un modelo mental completo para elegir y operar MySQL HA en producción, junto con ejemplos de configuración concretos que puede adaptar a su propio entorno.
MySQL Arquitectura de clúster InnoDB
InnoDB Cluster es la solución integrada de alta disponibilidad de Oracle para MySQL. Combina tres componentes: MySQL Group Replication para sincronización de datos, MySQL Shell para administración de clústeres y MySQL Router para enrutamiento de conexiones transparente y conmutación por error automática. Juntos forman un clúster de autorreparación que puede tolerar fallos de nodos sin intervención manual.
La arquitectura es elegante en su simplicidad. Las aplicaciones se conectan al enrutador MySQL, que mantiene el conocimiento de la topología del clúster consultando el esquema de metadatos del clúster InnoDB. Cuando el primario falla, Group Replication elige un nuevo primario entre los secundarios restantes y el enrutador MySQL redirige automáticamente el tráfico de escritura al nuevo primario, generalmente en cuestión de segundos. El tráfico de lectura se puede distribuir entre todos los secundarios para lograr un escalado de lectura horizontal.
Fundamentos de replicación de grupoMySQL Group Replication es la base de InnoDB Cluster. Utiliza un protocolo de consenso basado en Paxos para garantizar que cada transacción confirmada en el principal se replique en la mayoría de los nodos antes de ser reconocida. Esto proporciona replicación síncrona virtual: una garantía de que existen datos confirmados en al menos la mayoría de los miembros del clúster en el momento de la confirmación.
La replicación de grupofunciona en dos modos:
- Modo primario único: un nodo acepta escrituras (el primario); todos los demás son secundarios de sólo lectura. Este es el modo recomendado y predeterminado. Evita por completo los conflictos de escritura porque solo un nodo puede generar transacciones.
- Modo multiprimario: todos los nodos aceptan escrituras simultáneamente. Esto ofrece un mayor rendimiento de escritura para cargas de trabajo que se dividen limpiamente en diferentes tablas o espacios de claves, pero introduce la posibilidad de conflictos de certificación cuando transacciones simultáneas modifican las mismas filas. Las transacciones en conflicto se revierten en un nodo. Utilice multiprimario solo cuando su aplicación esté diseñada para manejar fallas de certificación y lógica de reintento.
Configuración del clúster InnoDB con MySQL Shell
MySQL Shell proporciona AdminAPI, un conjunto de funciones que automatizan todo el ciclo de vida del clúster. Aquí está la secuencia de configuración completa para un clúster de 3 nodos.
# Step 1: Prepare each MySQL instance (run on all 3 nodes)
# Ensure my.cnf has required settings
[mysqld]
server-id=1 # unique per node: 1, 2, 3
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
binlog_transaction_dependency_tracking=WRITESET
transaction_write_set_extraction=XXHASH64
loose-group_replication_start_on_boot=OFF
plugin_load_add='group_replication.so'
plugin_load_add='mysql_clone.so'
report_host='mysql-node-1' # unique per node
# Step 2: Use MySQL Shell to configure and create the cluster
mysqlsh -- dba configure-instance root@mysql-node-1:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
mysqlsh -- dba configure-instance root@mysql-node-2:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
mysqlsh -- dba configure-instance root@mysql-node-3:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
# Step 3: Connect to the first node and create the cluster
mysqlsh gradmin@mysql-node-1:3306
# Inside MySQL Shell:
var cluster = dba.createCluster('productionCluster', {
memberWeight: 90,
exitStateAction: 'ABORT_SERVER',
consistency: 'BEFORE_ON_PRIMARY_FAILOVER',
expelTimeout: 10
})
# Step 4: Add remaining nodes
cluster.addInstance('gradmin@mysql-node-2:3306', {recoveryMethod: 'clone'})
cluster.addInstance('gradmin@mysql-node-3:3306', {recoveryMethod: 'clone'})
# Step 5: Verify cluster status
cluster.status()
La opciónrecoveryMethod: 'clone'utiliza el complemento de clonación MySQL para realizar una copia de datos completa desde el miembro principal al miembro que se une, lo cual es mucho más rápido que la recuperación incremental de registros binarios para conjuntos de datos grandes.
Configuración del enrutador MySQL
El enrutadorMySQL se inicia en el clúster y genera automáticamente su archivo de configuración.
# Bootstrap MySQL Router against the cluster
mysqlrouter --bootstrap gradmin@mysql-node-1:3306 \
--directory /opt/mysqlrouter \
--conf-use-sockets \
--user=mysqlrouter \
--name='production-router'
# Start MySQL Router
/opt/mysqlrouter/start.sh
# Default ports after bootstrap:
# 6446 — R/W (routes to primary)
# 6447 — R/O (round-robin across secondaries)
# 6448 — R/W (X Protocol)
# 6449 — R/O (X Protocol)
Las aplicacionesse conectan al puerto R/W del enrutador para escrituras y al puerto R/O para réplicas de lectura. Cuando el primario falla, el enrutador detecta el cambio de topología y vuelve a enrutar en segundos.
Implementación de MySQL en varias regiones
Para recuperación ante desastres y lecturas de baja latencia en distintas geografías, MySQL se puede implementar en varias regiones. InnoDB ClusterSet amplía InnoDB Cluster para admitir la replicación asincrónica entre un clúster primario y uno o más clústeres de réplica en diferentes regiones.
InnoDB ClusterSet opera con un clúster primario que maneja todas las escrituras y uno o más clústeres de réplica que reciben cambios de forma asincrónica. En un escenario de desastre, un clúster de réplica se puede promover a primario a través de MySQL Shell.
# Create a ClusterSet from an existing InnoDB Cluster
mysqlsh gradmin@mysql-node-1:3306
var cluster = dba.getCluster()
var cs = cluster.createClusterSet('globalSet')
# Create a replica cluster in eu-west region
cs.createReplicaCluster('gradmin@mysql-eu-node-1:3306', 'euWestCluster', {
recoveryMethod: 'clone'
})
var euCluster = cs.getCluster('euWestCluster')
euCluster.addInstance('gradmin@mysql-eu-node-2:3306', {recoveryMethod: 'clone'})
euCluster.addInstance('gradmin@mysql-eu-node-3:3306', {recoveryMethod: 'clone'})
# Emergency failover (when primary cluster is unreachable)
cs.forcePrimaryCluster('euWestCluster')
MySQL en Kubernetes — Patrón de operador
La ejecución de MySQL en Kubernetes requiere resolver varios desafíos que no se aplican a cargas de trabajo sin estado: identidades de red estables, almacenamiento persistente, inicio y apagado ordenados y comprobaciones de estado del clúster. Los operadores de Kubernetes codifican este conocimiento operativo específico del dominio en un controlador que supervisa los recursos personalizados y concilia el estado real de MySQL con el estado deseado declarado en YAML.
MySQL Operador para Kubernetes (Oracle)
El operador MySQL de Oracle para Kubernetes implementa y administra instancias de InnoDB Cluster de forma nativa en Kubernetes. Crea StatefulSets para pods de servidores MySQL, implementaciones para enrutadores MySQL y maneja cambios automatizados de conmutación por error, escalado, respaldo y configuración.
# Install the MySQL Operator via Helm
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
helm install mysql-operator mysql-operator/mysql-operator \
--namespace mysql-operator \
--create-namespace \
--set image.pullPolicy=IfNotPresent
Una vez que el operador se esté ejecutando, implemente un clúster InnoDB creando un recurso personalizado.
apiVersion: v1
kind: Secret
metadata:
name: mysql-root-credentials
namespace: production
stringData:
rootUser: root
rootHost: '%'
rootPassword: 'ProductionSecurePass123!'
---
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: production-mysql
namespace: production
spec:
secretName: mysql-root-credentials
instances: 3
tlsUseSelfSigned: true
router:
instances: 2
datadirVolumeClaimTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: gp3-encrypted
mycnf: |
[mysqld]
innodb_buffer_pool_size=4G
innodb_log_file_size=1G
innodb_flush_log_at_trx_commit=1
sync_binlog=1
max_connections=500
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_read_io_threads=8
innodb_write_io_threads=8
performance_schema=ON
slow_query_log=ON
long_query_time=1
podSpec:
containers:
- name: mysql
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16Gi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: component
operator: In
values: [mysqld]
topologyKey: topology.kubernetes.io/zone
La regla antiafinidad de pods garantiza que los pods MySQL estén distribuidos en zonas de disponibilidad, lo que proporciona tolerancia a fallas a nivel de zona. El bloquemycnfle permite inyectar una configuración MySQL ajustada a producción directamente a través del CR.
Operador Percona para MySQL (PXC)
Percona Operador para MySQL implementa Percona XtraDB Cluster (PXC), una solución de replicación síncrona multiprimaria basada en Galera. PXC se diferencia de InnoDB Cluster en que cada nodo puede aceptar escrituras (verdaderamente multiprimario) y la replicación es sincrónica a nivel de certificación utilizando wsrep API.
# Install Percona Operator
helm repo add percona https://percona.github.io/percona-helm-charts/
helm repo update
helm install pxc-operator percona/pxc-operator \
--namespace pxc \
--create-namespace
# Percona XtraDB Cluster Custom Resource
apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBCluster
metadata:
name: production-pxc
namespace: pxc
spec:
crVersion: '1.14.0'
secretsName: pxc-secrets
pxc:
size: 3
image: percona/percona-xtradb-cluster:8.0.35
resources:
requests:
memory: 8Gi
cpu: "2"
limits:
memory: 16Gi
cpu: "4"
volumeSpec:
persistentVolumeClaim:
storageClassName: gp3-encrypted
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 200Gi
affinity:
antiAffinityTopologyKey: topology.kubernetes.io/zone
configuration: |
[mysqld]
innodb_buffer_pool_size=4G
innodb_flush_log_at_trx_commit=1
wsrep_provider_options="gcache.size=2G; gcs.fc_limit=256"
wsrep_slave_threads=8
wsrep_certify_nonPK=1
wsrep_trx_fragment_size=10M
max_connections=500
haproxy:
enabled: true
size: 3
image: percona/haproxy:2.8.5
resources:
requests:
memory: 1Gi
cpu: 500m
proxysql:
enabled: false
backup:
image: percona/percona-xtradb-cluster-operator:1.14.0-pxc8.0-backup-pxb8.0.35
storages:
s3-backup:
type: s3
verifyTLS: true
s3:
bucket: production-mysql-backups
region: us-east-1
credentialsSecret: aws-s3-credentials
schedule:
- name: daily-full
schedule: "0 3 * * *"
keep: 7
storageName: s3-backup
- name: hourly-incremental
schedule: "0 * * * *"
keep: 24
storageName: s3-backup
El Operador Percona maneja copias de seguridad automatizadas en S3, recuperación en un momento dado, actualizaciones continuas y ProxySQL o HAProxy para enrutamiento de conexiones. La replicación basada en Galera en PXC proporciona verdaderas escrituras multiprimarias sincrónicas: se garantiza que cada transacción confirmada existirá en todos los nodos.
Enrutamiento de conexión: enrutador MySQL frente a ProxySQL
Tanto el enrutador MySQL como el ProxySQL sirven como servidores proxy de bases de datos, pero tienen diferentes puntos fuertes.
Enrutador MySQLestá diseñado específicamente para InnoDB Cluster. Lee los metadatos del clúster, rastrea los cambios de topología y enruta las conexiones al primario o secundario correcto. Su configuración es mínima y se integra perfectamente con el ecosistema MySQL. La desventaja es el enrutamiento limitado a nivel de consulta: opera en el nivel de conexión, no en el nivel de consulta.
ProxySQLes un proxy MySQL de uso general con funciones avanzadas: división de lectura/escritura a nivel de consulta, almacenamiento en caché de consultas, multiplexación de conexiones, reescritura de consultas y reglas de enrutamiento sofisticadas. Sobresale en entornos donde se necesita un control detallado sobre cómo se distribuyen las consultas.
# ProxySQL configuration for read/write splitting
# proxysql.cnf
mysql_servers:
(
{ hostgroup_id=10, hostname="mysql-primary", port=3306, max_connections=200, weight=1000 },
{ hostgroup_id=20, hostname="mysql-secondary-1", port=3306, max_connections=200, weight=500 },
{ hostgroup_id=20, hostname="mysql-secondary-2", port=3306, max_connections=200, weight=500 }
)
mysql_query_rules:
(
{ rule_id=1, active=1, match_digest="^SELECT .* FOR UPDATE$", destination_hostgroup=10, apply=1 },
{ rule_id=2, active=1, match_digest="^SELECT", destination_hostgroup=20, apply=1 },
{ rule_id=3, active=1, match_digest=".*", destination_hostgroup=10, apply=1 }
)
mysql_replication_hostgroups:
(
{ writer_hostgroup=10, reader_hostgroup=20, comment="InnoDB Cluster" }
)
En entornos Kubernetes, ProxySQL puede ejecutarse como un contenedor complementario en sus módulos de aplicaciones o como una implementación dedicada. Ejecutarlo como sidecar elimina los saltos de red pero aumenta el uso de recursos del pod; una implementación dedicada es más fácil de gestionar a escala.
Comparación del proveedor de nube:
administrado versus autoadministradoAWS: RDS Multi-AZ frente a Aurora frente a autoadministrado en EKS
Amazon RDS Multi-AZproporciona conmutación por error automática entre una instancia principal y una instancia en espera en diferentes zonas de disponibilidad. La conmutación por error suele tardar entre 60 y 120 segundos. Utiliza replicación física síncrona en el modo de espera. Se pueden agregar réplicas de lectura para escalar la lectura, pero utilizan replicación asincrónica. RDS maneja copias de seguridad, parches y monitoreo, pero limita su control sobre la configuración de MySQL y la elección de versión.
Amazon Aurora MySQLes una reescritura nativa de la nube del motor de almacenamiento MySQL. Separa la computación del almacenamiento: la capa de almacenamiento es un sistema distribuido y tolerante a fallas que replica datos de seis maneras en tres AZ. Aurora proporciona conmutación por error en menos de 10 segundos, hasta 15 réplicas de lectura con un retraso de replicación mínimo y ampliación automática del almacenamiento hasta 128 TiB. Aurora Serverless v2 agrega escalamiento informático automático para cargas de trabajo impredecibles. La compensación es el costo (Aurora es entre un 20% y un 40% más caro que RDS) y una compatibilidad reducida con ciertas funciones de MySQL.
Autoadministrado en EKSle brinda control total sobre la versión, configuración y topología de replicación de MySQL. Úselo cuando necesite funciones específicas de MySQL que no estén disponibles en los servicios administrados, cuando necesite portabilidad de múltiples nubes o cuando la optimización de costos a escala justifique la sobrecarga operativa.
# EKS StorageClass for MySQL with gp3 volumes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3-encrypted
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "6000"
throughput: "250"
encrypted: "true"
fsType: ext4
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
Azure: servidor flexible versus autoadministrado en AKS
Base de datos Azure para servidor flexible MySQLofrece HA con redundancia de zona con conmutación por error automática, réplicas de lectura en la misma región y hasta 16 TiB de almacenamiento. Admite ventanas de mantenimiento configurables, la capacidad de detener/iniciar instancias (útil para ahorrar costos de desarrollo/pruebas) e integración con Azure Private Link para aislamiento de red. El nivel Business Critical proporciona el mejor rendimiento con almacenamiento SSD local.
Autoadministrado en AKSutiliza discos administrados Azure (SSD premium v2 recomendado para cargas de trabajo de bases de datos) con el operador MySQL o el operador Percona. AKS proporciona compatibilidad con zonas de disponibilidad y Azure CNI para la integración VNET a nivel de pod.
# AKS StorageClass for MySQL
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: premium-ssd-zrs
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_ZRS
cachingMode: None
DiskIOPSReadWrite: "5000"
DiskMBpsReadWrite: "200"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
Google Cloud: Cloud SQL frente a autoadministrado en GKE
Google Cloud SQL para MySQLofrece instancias regionales con conmutación por error automática entre zonas, réplicas de lectura (incluidas entre regiones) y copias de seguridad automatizadas con recuperación en un momento dado. Cloud SQL proporciona el más alto nivel de comodidad administrada con integración en el ecosistema de monitoreo, IAM y VPC de Google. El nivel Enterprise Plus agrega mantenimiento con tiempo de inactividad casi nulo y caché de datos para mejorar el rendimiento de lectura.
Autoadministrado en GKEutiliza disco persistente SSD o hiperdisco para almacenamiento. GKE Autopilot simplifica la administración de nodos y puede ejecutar el operador MySQL con una sobrecarga operativa mínima.
# GKE StorageClass for MySQL
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd-regional
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
replication-type: regional-pd
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
Metal desnudo: k3s + Ranchero + Longhorn
No todas las cargas de trabajo pertenecen a la nube pública. Para requisitos de soberanía de datos, cumplimiento, optimización de costos o latencia, los clústeres Kubernetes bare metal que ejecutan k3s con administración Rancher y almacenamiento Longhorn brindan una plataforma de nivel de producción para MySQL HA.
k3s Instalación y configuración
k3s es una distribución Kubernetes certificada y liviana, ideal para bordes y metal desnudo. Agrupa todos los componentes del plano de control en un único binario y utiliza SQLite o etcd integrado para el almacenamiento de estado.
# Install k3s server (first control-plane node)
curl -sfL https://get.k3s.io | sh -s - server \
--cluster-init \
--tls-san 10.10.0.10 \
--disable traefik \
--disable servicelb \
--write-kubeconfig-mode 644
# Join additional server nodes
curl -sfL https://get.k3s.io | K3S_TOKEN=$(cat /var/lib/rancher/k3s/server/node-token) sh -s - server \
--server https://10.10.0.10:6443 \
--tls-san 10.10.0.10
# Join worker nodes
curl -sfL https://get.k3s.io | K3S_URL=https://10.10.0.10:6443 \
K3S_TOKEN=$(cat /var/lib/rancher/k3s/server/node-token) sh -s -
Almacenamiento Longhorn para MySQL
Longhorn es un sistema de almacenamiento en bloques distribuido nativo de la nube creado para Kubernetes. Replica datos entre nodos, proporciona instantáneas y copias de seguridad y se integra de forma nativa con el controlador Kubernetes CSI. Para MySQL, Longhorn proporciona la capa de almacenamiento replicada y persistente que los proveedores de nube manejan con sus ofertas de discos administrados.
# Install Longhorn
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultReplicaCount=3 \
--set defaultSettings.storageMinimalAvailablePercentage=15 \
--set defaultSettings.guaranteedInstanceManagerCPU=12
# StorageClass for MySQL on Longhorn
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-mysql
provisioner: driver.longhorn.io
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
dataLocality: best-effort
diskSelector: ssd
fsType: ext4
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true
MetalLB para equilibrio de carga
En bare metal, no hay un equilibrador de carga en la nube. MetalLB llena este vacío asignando direcciones IP externas a servicios Kubernetes de tipo LoadBalancer usando el modo Capa 2 (ARP) o BGP.
# MetalLB IP Address Pool and L2 Advertisement
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: mysql-pool
namespace: metallb-system
spec:
addresses:
- 10.10.0.100-10.10.0.110
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: mysql-l2
namespace: metallb-system
spec:
ipAddressPools:
- mysql-pool
Estrategias de copia de seguridad y recuperación
Un clúster de alta disponibilidad protege contra fallas de nodo. Las copias de seguridad protegen contra la corrupción de datos, eliminaciones accidentales, errores de aplicaciones y escenarios de recuperación ante desastres en los que se pierde todo el clúster. Necesitas ambos.
Copias de seguridad lógicascon mysqldump
mysqldumpproduce copias de seguridad en formato SQL que son portátiles y legibles por humanos. Para bases de datos de menos de 50 GB, es la opción más sencilla. Para conjuntos de datos más grandes, el tiempo de bloqueo y exportación hace que no sea práctico para el uso en producción durante el horario comercial.
# Full logical backup with consistent snapshot
mysqldump --all-databases \
--single-transaction \
--routines \
--triggers \
--events \
--set-gtid-purged=ON \
--result-file=/backups/full-$(date +%Y%m%d-%H%M%S).sql
# Compressed backup piped to S3
mysqldump --all-databases --single-transaction | \
gzip | aws s3 cp - s3://mysql-backups/full-$(date +%Y%m%d).sql.gz
Copias de seguridad físicascon Percona XtraBackup
Percona XtraBackup realiza copias de seguridad físicas sin bloqueo y en caliente de los datos de InnoDB. Copia archivos de datos InnoDB mientras rastrea el registro de rehacer, luego aplica el registro de rehacer durante la fase de preparación para producir una copia de seguridad consistente. Es dramáticamente más rápido que mysqldump para grandes conjuntos de datos y admite copias de seguridad incrementales.
# Full physical backup
xtrabackup --backup \
--target-dir=/backups/full \
--user=backup_user \
--password=SecureBackupPass \
--parallel=4 \
--compress \
--compress-threads=4
# Incremental backup based on previous full
xtrabackup --backup \
--target-dir=/backups/incr-$(date +%H) \
--incremental-basedir=/backups/full \
--user=backup_user \
--password=SecureBackupPass
# Prepare (apply redo log) and restore
xtrabackup --prepare --target-dir=/backups/full
xtrabackup --prepare --target-dir=/backups/full \
--incremental-dir=/backups/incr-01
# Copy back to data directory
xtrabackup --copy-back --target-dir=/backups/full --datadir=/var/lib/mysql
chown -R mysql:mysql /var/lib/mysql
Recuperación de registro binario (binlog) en un momento dado
Los registros binarios registran cada transacción que modifica datos. Combinados con una copia de seguridad completa, permiten la recuperación en un momento dado (PITR), restaurando a cualquier momento específico, no solo al momento de la última copia de seguridad.
# Enable binlog retention (my.cnf)
[mysqld]
log_bin=mysql-bin
binlog_expire_logs_seconds=604800 # 7 days
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
# Restore from backup then replay binlogs to a specific point
mysqlbinlog --start-datetime="2026-04-12 08:00:00" \
--stop-datetime="2026-04-12 09:30:00" \
mysql-bin.000042 mysql-bin.000043 | mysql -u root -p
# Or replay to a specific GTID position
mysqlbinlog --include-gtids="3c2d4f9e-d17e-ec59-9029-6aafa8accef8:1-5000" \
mysql-bin.000042 | mysql -u root -p
Kubernetes Copia de seguridad CronJob
En Kubernetes, las copias de seguridad deben ejecutarse como CronJobs en lugar de comandos ad-hoc. Esto garantiza que las copias de seguridad estén automatizadas, monitoreadas y puedan recibir alertas si fallan.
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-backup
namespace: production
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 3
jobTemplate:
spec:
activeDeadlineSeconds: 7200
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: percona/percona-xtrabackup:8.0.35
command:
- /bin/sh
- -c
- |
BACKUP_DIR=/backups/$(date +%Y%m%d-%H%M%S)
mkdir -p $BACKUP_DIR
xtrabackup --backup \
--host=production-mysql.production.svc \
--user=backup_user \
--password=$BACKUP_PASSWORD \
--target-dir=$BACKUP_DIR \
--parallel=4 \
--compress
xtrabackup --prepare --target-dir=$BACKUP_DIR
# Upload to S3
aws s3 sync $BACKUP_DIR s3://mysql-backups/$(date +%Y%m%d)/
# Cleanup local
rm -rf $BACKUP_DIR
env:
- name: BACKUP_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-backup-credentials
key: password
volumeMounts:
- name: backup-scratch
mountPath: /backups
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "2"
memory: 4Gi
volumes:
- name: backup-scratch
emptyDir:
sizeLimit: 100Gi
Monitoreocon Monitoreo y Gestión de Percona (PMM)
Percona Monitoring and Management (PMM) es una plataforma de monitoreo de código abierto diseñada específicamente para la observabilidad de bases de datos. Mientras que Prometheus y Grafana brindan monitoreo general de Kubernetes, PMM agrega información específica de MySQL: análisis de consultas (QAN) que identifica consultas lentas, paneles de control de retraso de replicación, índices de aciertos del grupo de búfer de InnoDB, contención de bloqueo de tablas y más.
# Deploy PMM Server on Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: pmm-server
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: pmm-server
template:
metadata:
labels:
app: pmm-server
spec:
containers:
- name: pmm-server
image: percona/pmm-server:2
ports:
- containerPort: 443
env:
- name: DISABLE_TELEMETRY
value: "1"
volumeMounts:
- name: pmm-data
mountPath: /srv
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
cpu: "2"
memory: 8Gi
volumes:
- name: pmm-data
persistentVolumeClaim:
claimName: pmm-data-pvc
---
apiVersion: v1
kind: Service
metadata:
name: pmm-server
namespace: monitoring
spec:
type: ClusterIP
selector:
app: pmm-server
ports:
- port: 443
targetPort: 443
# Register MySQL instances with PMM Client (run on each MySQL pod or sidecar)
pmm-admin config --server-url=https://admin:password@pmm-server.monitoring:443 --server-insecure-tls
pmm-admin add mysql \
--username=pmm_monitor \
--password=MonitorPass123 \
--host=127.0.0.1 \
--port=3306 \
--query-source=perfschema \
--service-name=mysql-node-1
Query Analytics dePMM es particularmente valioso en producción. Captura cada consulta ejecutada en el servidor (a través de un esquema de rendimiento o un registro de consultas lentas), las agrega por huella digital y muestra métricas como latencia promedio, filas examinadas frente a filas enviadas y tiempo de bloqueo. Así es como identifica las consultas que están degradando el rendimiento de su aplicación.
Ajuste de configuración de producción
La configuración predeterminada de MySQL está optimizada para una carga de trabajo pequeña y de uso general. Los entornos de producción con servidores de bases de datos dedicados necesitan configuraciones significativamente diferentes. Estos son los parámetros críticos y cómo dimensionarlos.
Grupo de búfer InnoDB
El grupo de búfer de InnoDB es donde MySQL almacena en caché los datos de tablas e índices en la memoria. Es el parámetro de configuración más impactante. Para un servidor MySQL dedicado, configúrelo entre el 70% y el 80% de la RAM disponible.
[mysqld]
# Memory: 16Gi container limit -> allocate ~12Gi to buffer pool
innodb_buffer_pool_size = 12G
innodb_buffer_pool_instances = 8 # 1 per GB (up to 64)
innodb_buffer_pool_chunk_size = 1536M # pool_size / instances
Configuración del registro de rehacer
El registro de rehacer absorbe las escrituras antes de volcarlas en archivos de datos. Los registros de rehacer más grandes reducen la frecuencia de los vaciados de puntos de control y mejoran el rendimiento de escritura. MySQL 8.0.30+ usainnodb_redo_log_capacityen lugar del anteriorinnodb_log_file_size.
[mysqld]
# MySQL 8.0.30+
innodb_redo_log_capacity = 4G
# MySQL 8.0.29 and earlier
# innodb_log_file_size = 2G
# innodb_log_files_in_group = 2
Compensación entre durabilidad y rendimiento
La combinación deinnodb_flush_log_at_trx_commitysync_binlogdetermina su garantía de durabilidad.
- Máxima durabilidad(recomendado para producción):
innodb_flush_log_at_trx_commit=1+sync_binlog=1. Cada transacción se envía al registro de rehacer y al registro binario en el disco antes de ser reconocida. Cero pérdida de datos en caso de accidente. - Equilibrado:
innodb_flush_log_at_trx_commit=2+sync_binlog=1. El registro de rehacer se escribe en la caché del sistema operativo por confirmación, pero solo se descarga en el disco una vez por segundo. Se puede perder hasta 1 segundo de transacciones en caso de una falla del sistema operativo (la falla de MySQL aún es segura). - Máximo rendimiento(no recomendado para producción):
innodb_flush_log_at_trx_commit=0+sync_binlog=0. Las escrituras se agrupan y eliminan periódicamente. Riesgo de perder hasta 1 segundo de transacciones en caso de falla.
[mysqld]
# Production durability settings
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_doublewrite = ON
innodb_checksum_algorithm = crc32
Configuración de E/S de[mysqld]
# SSD-optimised I/O settings
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_flush_method = O_DIRECT
innodb_file_per_table = ON
innodb_open_files = 10000
Gestión de conexiones y subprocesos
[mysqld]
max_connections = 500
max_connect_errors = 1000000
thread_cache_size = 64
table_open_cache = 4096
table_open_cache_instances = 16
back_log = 1500
# Thread pool (MySQL Enterprise or Percona)
thread_pool_size = 16
thread_pool_max_threads = 1000
Tablas temporales y búferes de clasificación
[mysqld]
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
read_rnd_buffer_size = 2M
Plantilla de configuración de producción completa
[mysqld]
# Identity
server-id = 1
report_host = mysql-node-1
# GTID Replication
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW
log_bin = mysql-bin
binlog_expire_logs_seconds = 604800
log_slave_updates = ON
relay_log_recovery = ON
# InnoDB Engine
innodb_buffer_pool_size = 12G
innodb_buffer_pool_instances = 8
innodb_redo_log_capacity = 4G
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_doublewrite = ON
innodb_flush_method = O_DIRECT
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_file_per_table = ON
innodb_open_files = 10000
innodb_adaptive_hash_index = ON
innodb_change_buffering = all
# Connections
max_connections = 500
max_connect_errors = 1000000
thread_cache_size = 64
table_open_cache = 4096
table_open_cache_instances = 16
back_log = 1500
# Temp / Sort
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
# Monitoring
performance_schema = ON
slow_query_log = ON
long_query_time = 1
log_queries_not_using_indexes = ON
log_throttle_queries_not_using_indexes = 60
# Security
local_infile = OFF
skip_name_resolve = ON
default_authentication_plugin = caching_sha2_password
# Group Replication (InnoDB Cluster)
plugin_load_add = 'group_replication.so'
plugin_load_add = 'mysql_clone.so'
loose-group_replication_start_on_boot = OFF
loose-group_replication_bootstrap_group = OFF
loose-group_replication_recovery_use_ssl = ON
loose-group_replication_ssl_mode = REQUIRED
Pruebas de conmutación por error e ingeniería del caos
Un sistema de alta disponibilidad que nunca se ha probado en condiciones de falla no es realmente de alta disponibilidad: es una hipótesis. Las pruebas de conmutación por error deben ser parte de su cadencia operativa habitual, no algo que descubra que funciona (o no funciona) durante un incidente real.
Prueba de conmutación por error controlada
# Test 1: Graceful primary failover (InnoDB Cluster)
mysqlsh gradmin@mysql-node-1:3306
var cluster = dba.getCluster()
cluster.setPrimaryInstance('gradmin@mysql-node-2:3306')
# Verify: cluster.status() should show node-2 as PRIMARY
# Test 2: Simulate primary crash
# On the primary node:
kill -9 $(pidof mysqld)
# Monitor: watch the cluster elect a new primary
# Verify: applications reconnect via MySQL Router within seconds
# Test 3: Network partition simulation
# On the primary node, block Group Replication port:
iptables -A INPUT -p tcp --dport 33061 -j DROP
iptables -A OUTPUT -p tcp --dport 33061 -j DROP
# The isolated node should be expelled; cluster continues with remaining members
# Cleanup:
iptables -D INPUT -p tcp --dport 33061 -j DROP
iptables -D OUTPUT -p tcp --dport 33061 -j DROP
# Test 4: Kubernetes pod deletion
kubectl delete pod mysql-0 -n production --grace-period=0 --force
# The StatefulSet controller recreates the pod
# The operator rejoins it to the cluster
Ingeniería del Caos con Litmus o Chaos Mesh
Las herramientas de ingeniería del caos estructurado inyectan fallas sistemáticamente y miden el radio de la explosión. Chaos Mesh, un proyecto de CNCF, se integra de forma nativa con Kubernetes.
# Chaos Mesh: Kill a MySQL pod randomly
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: mysql-pod-kill
namespace: production
spec:
action: pod-kill
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
scheduler:
cron: "0 */4 * * *"
---
# Chaos Mesh: Network delay between MySQL pods
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: mysql-network-delay
namespace: production
spec:
action: delay
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
delay:
latency: "200ms"
jitter: "50ms"
duration: "5m"
scheduler:
cron: "30 */6 * * *"
---
# Chaos Mesh: Disk I/O stress
apiVersion: chaos-mesh.org/v1alpha1
kind: IOChaos
metadata:
name: mysql-io-latency
namespace: production
spec:
action: latency
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
volumePath: /var/lib/mysql
path: '*'
delay: '100ms'
percent: 50
duration: '5m'
Qué medir durante las pruebas de conmutación por error
- Objetivo de tiempo de recuperación (RTO): ¿Cuánto tiempo transcurre desde la detección de fallas hasta la restauración del servicio? InnoDB Cluster normalmente alcanza entre 5 y 30 segundos. Percona XtraDB Cluster puede ser más rápido porque no hay elección (todos los nodos se pueden escribir).
- Objetivo de punto de recuperación (RPO): ¿cuántos datos se pierden durante la conmutación por error? Con la replicación sincrónica (replicación de grupo en modo primario único, PXC), el RPO es cero para las transacciones confirmadas. Con la replicación asincrónica (ClusterSet entre regiones), RPO es igual al retraso de replicación.
- Tasa de errores de aplicaciones: ¿Cuántas solicitudes de aplicaciones fallan durante la ventana de conmutación por error? Esto prueba no solo la conmutación por error de la base de datos, sino también la lógica de reintento de conexión de su aplicación y la velocidad de redireccionamiento del enrutador MySQL.
- Tiempo de drenaje de la conexión: ¿Cuánto tiempo tardan las conexiones existentes al primario anterior en drenarse y volver a conectarse al nuevo primario?
: Lista de verificación de fallas del nodo primario
- Verifique que el clúster haya elegido un nuevo primario:
cluster.status() - Confirme que el enrutador MySQL está enrutando al nuevo primario: verifique los registros del enrutador y los recuentos de conexiones
- Supervisar el retraso de replicación en los secundarios restantes:
SELECT * FROM performance_schema.replication_group_member_stats - Si el nodo fallido se puede recuperar, vuelva a unirse a él:
cluster.rejoinInstance('gradmin@failed-node:3306') - Si el nodo fallido no se puede recuperar, elimínelo y agregue uno nuevo:
cluster.removeInstance('gradmin@failed-node:3306', {force: true}) - Verificar el estado del clúster: todos los miembros EN LÍNEA, sin errores de replicación, programación de respaldo intacta
- Actualice su plan de capacidad: ejecutar con 2 nodos significa que tiene tolerancia cero a fallos hasta que se restaure el tercero
Refuerzo de seguridad
Las implementaciones de producción MySQL deben abordar varios problemas de seguridad más allá de la autenticación básica.
Cifrado en tránsito y en reposo
[mysqld]
# TLS for client connections
ssl_ca = /etc/mysql/certs/ca.pem
ssl_cert = /etc/mysql/certs/server-cert.pem
ssl_key = /etc/mysql/certs/server-key.pem
require_secure_transport = ON
tls_version = TLSv1.3
# Encryption at rest (InnoDB tablespace encryption)
early-plugin-load = keyring_file.so
keyring_file_data = /var/lib/mysql-keyring/keyring
innodb_undo_log_encrypt = ON
innodb_redo_log_encrypt = ON
default_table_encryption = ON
Kubernetes Secretos y Secretos Sellados
# Never store database credentials in plain YAML
# Use Sealed Secrets or an external secret manager
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysql-root-credentials
namespace: production
spec:
encryptedData:
rootUser: AgBy3i4OJSWK+PiTy...
rootPassword: AgCtr7pJ2XQWK+Pi...
template:
metadata:
name: mysql-root-credentials
namespace: production
type: Opaque
Registro de auditoría
[mysqld]
# MySQL Enterprise Audit (or Percona Audit Log plugin)
plugin-load-add = audit_log.so
audit_log_format = JSON
audit_log_policy = LOGINS
audit_log_rotate_on_size = 100M
audit_log_rotations = 10
Matriz de decisiones: elección de su arquitectura MySQL HA
La arquitectura adecuada depende de sus requisitos específicos. Aquí hay un marco de decisión.
- Nube única, preferencia administrada, compatible con MySQL: use Aurora (AWS), Flexible Server Business Critical (Azure) o Cloud SQL Enterprise Plus (GCP). Estos proporcionan los gastos operativos más bajos.
- Nube única, autoadministrada, necesita control total de MySQL: use MySQL Operador o Percona Operador en EKS/AKS/GKE con clases de almacenamiento nativo de la nube.
- Nube múltiple o nube híbrida: utilice el operador Percona con PXC o el operador MySQL con clúster InnoDB. La capa de abstracción Kubernetes hace que su implementación MySQL sea portátil en todas las nubes.
- Metal desnudo o borde: utilice k3s con Rancher, almacenamiento Longhorn, MetalLB y operador MySQL o operador Percona.
- Rendimiento de escritura máximo, se requiere multiprimario: utilice el clúster Percona XtraDB (Galera) con el operador Percona. Todos los nodos aceptan escrituras con certificación síncrona.
- Distribución global con recuperación ante desastres: utilice InnoDB ClusterSet con replicación asincrónica entre regiones. Acepte la compensación de RPO de la replicación asincrónica por los beneficios de latencia de las escrituras locales.
para producción MySQL HA
Antes de declarar que su implementación MySQL HA está lista para producción, valide todos los elementos de esta lista de verificación.
- Estado del clúster: todos los miembros informan el estado EN LÍNEA. La replicación de grupo no muestra errores.
- Copias de seguridad automatizadas: CronJob o copias de seguridad administradas por el operador que se ejecutan según lo programado. Copias de seguridad verificadas mediante pruebas de restauración periódicas.
- Monitoreo: PMM o Prometheus/Grafana recopila métricas de MySQL. Alertas configuradas para retrasos en la replicación, saturación de conexiones, índice de aciertos del grupo de búfer por debajo del 99 % y espacio en disco.
- Conmutación por error probada: conmutación por error principal probada en los últimos 30 días. RTO y RPO medidos y dentro de los objetivos de SLA.
- Enrutamiento de conexión: enrutador MySQL o ProxySQL con estado comprobado y equilibrio de carga. Las cadenas de conexión de la aplicación apuntan al enrutador, no a instancias MySQL individuales.
- Seguridad: se requiere TLS para todas las conexiones. Cifrado en reposo habilitado. Credenciales almacenadas en un administrador secreto. Registro de auditoría activo. Usuarios de bases de datos con privilegios mínimos para cada aplicación.
- Límites de recursos: solicitudes y límites de recursos Kubernetes establecidos adecuadamente. PodDisruptionBudgets implementados. Antiafinidad de cápsulas que distribuyen cápsulas MySQL entre zonas.
- Plan de capacidad: utilización del almacenamiento monitoreada con alertas al 70 % y 85 %. Expansión de volumen probada. Procedimientos de escalado vertical y horizontal documentados.
- Runbooks: procedimientos documentados para conmutación por error principal, reemplazo de nodos, restauración de copias de seguridad, actualización de versiones y modo de solo lectura de emergencia.
- Pruebas de caos: experimentos de caos regulares programados para validar supuestos de resiliencia.
Conclusión
La alta disponibilidad deMySQL en producción no es una única opción tecnológica: es un sistema de decisiones entrelazadas que abarcan la capa de replicación, la plataforma de orquestación, el subsistema de almacenamiento, la pila de monitoreo y los procesos operativos que los rodean. InnoDB Cluster con replicación de grupo proporciona la primitiva HA fundamental. Los operadores Kubernetes de Oracle y Percona automatizan la gestión del ciclo de vida que, de otro modo, consumiría un tiempo de ingeniería significativo. Los servicios gestionados en la nube intercambian el control por conveniencia. Las implementaciones bare metal con k3s, Rancher y Longhorn demuestran que no se necesita un proveedor de nube para ejecutar MySQL HA de nivel de producción.
La idea más importante es que la alta disponibilidad es una propiedad de todo el sistema, no solo de la base de datos. Incluye cómo su aplicación maneja fallas y reintentos de conexión, cómo su capa de proxy detecta y enruta nodos fallidos, cómo su monitoreo alerta antes de que los usuarios se den cuenta, cómo su estrategia de respaldo permite la recuperación de escenarios que HA por sí sola no puede manejar y cómo su equipo practica procedimientos de conmutación por error para que se ejecuten limpiamente bajo el estrés de un incidente real.
Constrúyalo deliberadamente, pruébelo periódicamente y trate sus runbooks como documentos vivos que evolucionan con cada incidente y cada experimento de caos. Así es como MySQL se gana su lugar como plataforma de datos confiable y de alta disponibilidad en producción.