Высокая доступность MySQL в производстве: кластер InnoDB, групповая репликация и операторы Kubernetes
Руководство инженера-технолога по кластеру InnoDB, групповой репликации, оператору MySQL для Kubernetes, кластеру Percona XtraDB, многооблачным стратегиям и развертываниям k3s/Rancher на «голом железе» с хранилищем Longhorn.
Использование MySQL в производственной среде знакомо большинству инженерных групп. Запуск его с подлинно высокой доступностью — когда сбой узла, сетевой раздел или выход из строя всей зоны доступности не приводит к простою или потере данных — требует продуманной архитектуры. В этом руководстве рассматриваются все уровни этой архитектуры: от примитивов репликации внутри самого MySQL, операторов Kubernetes, которые автоматизируют управление жизненным циклом, управляемых и самоуправляемых опций каждого крупного поставщика облачных услуг и вплоть до «голых» кластеров k3s, управляемых Rancher.
К концу этой статьи вы получите полную мысленную модель выбора и эксплуатации MySQL HA в производственной среде, а также конкретные примеры конфигурации, которые вы сможете адаптировать к своей собственной среде.
MySQL Кластерная архитектура InnoDB
InnoDB Cluster — это интегрированное решение Oracle высокой доступности для MySQL. Оно объединяет три компонента: групповую репликацию MySQL для синхронизации данных, оболочку MySQL для администрирования кластера и маршрутизатор MySQL для прозрачной маршрутизации соединений и автоматического переключения при сбое. Вместе они образуют самовосстанавливающийся кластер, который может выдерживать сбои узлов без ручного вмешательства.
Архитектура элегантна в своей простоте. Приложения подключаются к маршрутизатору MySQL, который поддерживает информацию о топологии кластера, запрашивая схему метаданных кластера InnoDB. При сбое основного узла групповая репликация выбирает новый основной из оставшихся вторичных, а маршрутизатор MySQL автоматически перенаправляет трафик записи на новый основной — обычно в течение нескольких секунд. Трафик чтения можно распределить между всеми вторичными узлами для горизонтального масштабирования чтения.
Основы групповой репликации
MySQL Групповая репликация является основой кластера InnoDB. Он использует протокол консенсуса на основе Paxos, чтобы гарантировать, что каждая транзакция, совершенная на основном узле, реплицируется на большинство узлов перед подтверждением. Это обеспечивает виртуальную синхронную репликацию— гарантию того, что зафиксированные данные существуют как минимум на большинстве элементов кластера на момент фиксации.
Групповая репликацияработает в двух режимах:
- Одноосновной режим— один узел принимает запись (основной); все остальные являются вторичными устройствами только для чтения. Это рекомендуемый режим по умолчанию. Он полностью позволяет избежать конфликтов записи, поскольку только один узел может генерировать транзакции.
- Многоосновной режим— все узлы принимают записи одновременно. Это обеспечивает более высокую пропускную способность записи для рабочих нагрузок, которые четко распределяют данные по разным таблицам или пространствам ключей, но при этом возникает вероятность конфликтов сертификации, когда одновременные транзакции изменяют одни и те же строки. Конфликтующие транзакции откатываются на одном узле. Используйте multi-primary только в том случае, если ваше приложение предназначено для обработки ошибок сертификации и логики повторных попыток.
Настройка кластера InnoDB с оболочкой MySQL
MySQL Shell предоставляет AdminAPI — набор функций, которые автоматизируют весь жизненный цикл кластера. Вот полная последовательность настройки для кластера из 3 узлов.
# 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()
ОпцияrecoveryMethod: 'clone'использует подключаемый модуль клонирования MySQL для выполнения полного копирования данных с основного на присоединяемый элемент, что намного быстрее, чем инкрементное восстановление из двоичных журналов для больших наборов данных.
Конфигурация маршрутизатора MySQL
Маршрутизатор MySQL загружается с кластера и автоматически создает файл конфигурации.
# 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)
Приложенияподключаются к порту R/W маршрутизатора для записи и к порту R/O для реплик чтения. При выходе из строя основного маршрутизатора маршрутизатор обнаруживает изменение топологии и меняет маршрут в течение нескольких секунд.
Многорегиональное развертывание MySQL
Для аварийного восстановления и чтения с малой задержкой в разных географических регионах MySQL можно развернуть в нескольких регионах. InnoDB ClusterSet расширяет InnoDB Cluster для поддержки асинхронной репликации между основным кластером и одним или несколькими кластерами реплик в разных регионах.
InnoDB ClusterSet работает с одним основным кластером, который обрабатывает все записи, и одним или несколькими кластерами реплик, которые получают изменения асинхронно. В случае аварии кластер реплик можно повысить до основного с помощью 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 на Kubernetes — шаблон оператора
Для запуска MySQL на Kubernetes необходимо решить несколько задач, которые не применимы к рабочим нагрузкам без отслеживания состояния: стабильные сетевые идентификаторы, постоянное хранилище, упорядоченный запуск и завершение работы, а также проверки работоспособности с учетом кластера. Операторы Kubernetes кодируют эти специфичные для предметной области эксплуатационные знания в контроллере, который наблюдает за пользовательскими ресурсами и согласовывает фактическое состояние MySQL с желаемым состоянием, заявленным в YAML.
Оператор MySQL для Kubernetes (Oracle)
Оператор Oracle MySQL для Kubernetes развертывает и управляет экземплярами кластера InnoDB непосредственно на Kubernetes. Он создает наборы StatefulSet для модулей серверов MySQL, развертывания для маршрутизатора MySQL и обрабатывает автоматическое переключение при сбое, масштабирование, резервное копирование и изменения конфигурации.
# 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
После запуска оператора разверните кластер InnoDB, создав собственный ресурс.
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
Правило антисходства модулей обеспечивает распределение модулей MySQL по зонам доступности, обеспечивая отказоустойчивость на уровне зоны. Блокmycnfпозволяет вводить настроенную для производства конфигурацию MySQL непосредственно через CR.
Оператор Percona для MySQL (PXC)
Оператор Percona для MySQL развертывает Percona XtraDB Cluster (PXC), решение для синхронной репликации с несколькими первичными системами на основе Galera. PXC отличается от кластера InnoDB тем, что каждый узел может принимать записи (настоящий многоосновной), а репликация синхронна на уровне сертификации с использованием 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
Оператор Percona выполняет автоматическое резервное копирование на S3, восстановление на определенный момент времени, последовательные обновления, а также ProxySQL или HAProxy для маршрутизации соединений. Репликация на основе Galera в PXC обеспечивает настоящую синхронную запись с несколькими первичными узлами — каждая зафиксированная транзакция гарантированно существует на всех узлах.
Маршрутизация соединений: маршрутизатор MySQL и ProxySQL
Маршрутизатор MySQL и ProxySQL служат прокси-серверами базы данных, но у них разные преимущества.
Маршрутизатор MySQLспециально создан для кластера InnoDB. Он считывает метаданные кластера, отслеживает изменения топологии и направляет соединения к правильному первичному или вторичному серверу. Его конфигурация минимальна и легко интегрируется с экосистемой MySQL. Недостатком является ограниченная маршрутизация на уровне запроса — она работает на уровне соединения, а не на уровне запроса.
ProxySQL— это прокси-сервер MySQL общего назначения с расширенными функциями: разделение чтения/записи на уровне запроса, кэширование запросов, мультиплексирование соединений, перезапись запросов и сложные правила маршрутизации. Он отлично подходит для сред, где вам необходим детальный контроль над распределением запросов.
# 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" }
)
В средах Kubernetes ProxySQL может работать как дополнительный контейнер в модулях приложений или как выделенное развертывание. Запуск его в качестве дополнительного модуля исключает сетевые переходы, но увеличивает использование ресурсов модуля; выделенным развертыванием легче управлять в масштабе.
Сравнение облачных провайдеров: управляемый и самоуправляемый
AWS: RDS Multi-AZ, Aurora и самостоятельное управление на EKS
Amazon RDS Multi-AZобеспечивает автоматическое переключение при сбое между основным и резервным инстансом в разных зонах доступности. Аварийное переключение обычно занимает 60–120 секунд. Он использует синхронную физическую репликацию на резервный сервер. Реплики чтения можно добавлять для масштабирования чтения, но они используют асинхронную репликацию. RDS занимается резервным копированием, исправлениями и мониторингом, но ограничивает ваш контроль над конфигурацией MySQL и выбором версии.
Amazon Aurora MySQL— это облачная переработанная версия механизма хранения MySQL. Он отделяет вычисления от хранилища: уровень хранения представляет собой распределенную отказоустойчивую систему, которая реплицирует данные шестью способами в трех зонах доступности. Aurora обеспечивает аварийное переключение менее чем за 10 секунд, до 15 реплик чтения с минимальной задержкой репликации и автоматическое масштабирование хранилища до 128 ТиБ. В Aurora Serverless v2 добавлено автоматическое масштабирование вычислений для непредсказуемых рабочих нагрузок. Компромиссом является стоимость (Aurora на 20–40 % дороже, чем RDS) и ограниченная совместимость с некоторыми функциями MySQL.
Самоуправляемый на EKSдает вам полный контроль над версией MySQL, конфигурацией и топологией репликации. Используйте это, когда вам нужны определенные функции MySQL, недоступные в управляемых сервисах, когда вам требуется переносимость в несколько облаков или когда оптимизация затрат в масштабе оправдывает операционные накладные расходы.
# 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: гибкий сервер или самоуправляемый сервер на AKS
База данных Azure для гибкого сервера MySQLпредлагает зону высокой доступности с автоматическим переключением при сбое, реплики чтения в том же регионе и хранилище объемом до 16 ТиБ. Он поддерживает настраиваемые окна обслуживания, возможность остановки/запуска экземпляров (полезно для экономии затрат на разработку/тестирование) и интеграцию с Azure Private Link для изоляции сети. Уровень Business Critical обеспечивает наилучшую производительность при использовании локального SSD-накопителя.
с самостоятельным управлением на AKSиспользует управляемые диски Azure (твердотельный накопитель премиум-класса версии 2, рекомендуемый для рабочих нагрузок базы данных) с оператором MySQL или оператором Percona. AKS обеспечивает поддержку зон доступности и Azure CNI для интеграции виртуальной сети на уровне модуля.
# 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 против самостоятельного управления на GKE
Google Cloud SQL для MySQLпредлагает региональные экземпляры с автоматическим переключением при сбое между зонами, репликами чтения (в том числе между регионами) и автоматическим резервным копированием с восстановлением на определенный момент времени. Cloud SQL обеспечивает высочайший уровень удобства управления благодаря интеграции с IAM, VPC и экосистемой мониторинга Google. Уровень Enterprise Plus обеспечивает практически нулевое обслуживание и кэширование данных для повышения производительности чтения.
Самоуправляемый на GKEиспользует SSD-накопитель Persistent Disk или Hyperdisk для хранения данных. GKE Autopilot упрощает управление узлами и позволяет запускать оператор MySQL с минимальными эксплуатационными расходами.
# 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
Голый металл: k3s + Rancher + Longhorn
Не каждая рабочая нагрузка находится в общедоступном облаке. Для обеспечения суверенитета данных, соответствия требованиям, оптимизации затрат или требований к задержке кластеры Kubernetes без ОС, работающие под управлением k3s с управлением Rancher и системой хранения данных Longhorn, представляют собой платформу производственного уровня для MySQL HA.
Установка и настройка k3s
k3s — это легкий сертифицированный дистрибутив Kubernetes, идеально подходящий для работы на периферии и на голом железе. Он объединяет все компоненты плоскости управления в один двоичный файл и использует SQLite или встроенный etcd для хранения состояния.
# 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 -
Система хранения данных Longhorn для MySQL
Longhorn — это облачная распределенная блочная система хранения данных, созданная для Kubernetes. Он реплицирует данные между узлами, предоставляет моментальные снимки и резервные копии, а также естественным образом интегрируется с драйвером Kubernetes CSI. Для MySQL Longhorn предоставляет постоянный, реплицируемый уровень хранения, который поставщики облачных услуг используют в своих предложениях по управляемым дискам.
# 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 для балансировки нагрузки
На «голом железе» облачного балансировщика нагрузки нет. MetalLB заполняет этот пробел, назначая внешние IP-адреса службам Kubernetes типа LoadBalancer с использованием режима Layer 2 (ARP) или 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
Стратегии резервного копирования и восстановленияКластер высокой доступности защищает от сбоев узлов. Резервные копии защищают от повреждения данных, случайного удаления, ошибок приложений и сценариев аварийного восстановления, при которых теряется весь кластер. Вам нужны оба.
Логическое резервное копирование с помощью mysqldump
mysqldumpсоздает портативные и удобочитаемые резервные копии в формате SQL. Для баз данных размером менее 50 ГБ это самый простой вариант. Для больших наборов данных время блокировки и экспорта делает непрактичным их использование в рабочее время.
# 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
Физическое резервное копирование с помощью Percona XtraBackup
Percona XtraBackup выполняет горячее неблокирующее физическое резервное копирование данных InnoDB. Он копирует файлы данных InnoDB, отслеживая журнал повторов, а затем применяет журнал повторов на этапе подготовки для создания согласованной резервной копии. Он значительно быстрее, чем mysqldump, для больших наборов данных и поддерживает инкрементное резервное копирование.
# 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
Двоичный журнал (binlog) Восстановление на определенный момент времени
Двоичные журналы записывают каждую транзакцию, изменяющую данные. В сочетании с полным резервным копированием они обеспечивают восстановление на определенный момент времени (PITR) — восстановление до любого конкретного момента, а не только до момента создания последней резервной копии.
# 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 Резервное копирование CronJob
В Kubernetes резервное копирование должно выполняться как CronJobs, а не как специальные команды. Это гарантирует, что резервное копирование автоматизировано, контролируется и может быть предупреждено в случае сбоя.
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
Мониторинг с помощью Percona Monitoring and Management (PMM)
Percona Monitoring and Management (PMM) — это платформа мониторинга с открытым исходным кодом, специально созданная для наблюдения за базами данных. В то время как Prometheus и Grafana обеспечивают общий мониторинг Kubernetes, PMM добавляет информацию, специфичную для MySQL: аналитику запросов (QAN), которая определяет медленные запросы, информационные панели задержек репликации, коэффициенты попадания в буферный пул InnoDB, конфликты за блокировку таблиц и многое другое.
# 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
Аналитика запросовPMM особенно ценна в производстве. Он фиксирует каждый запрос, выполняемый на сервере (через схему производительности или журнал медленных запросов), объединяет их по отпечаткам пальцев и показывает такие показатели, как средняя задержка, количество проверенных и отправленных строк, а также время блокировки. Таким образом вы определяете запросы, которые снижают производительность вашего приложения.
Настройка производственной конфигурацииКонфигурация MySQL по умолчанию настроена на небольшую рабочую нагрузку общего назначения. Производственные среды с выделенными серверами баз данных требуют совершенно других настроек. Вот критические параметры и способы их определения.
Буферный пул InnoDB
Буферный пул InnoDB — это место, где MySQL кэширует данные таблиц и индексов в памяти. Это единственный наиболее важный параметр конфигурации. Для выделенного сервера MySQL установите значение 70–80 % доступной оперативной памяти.
[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
Конфигурация журнала повторов
Журнал повторного выполнения поглощает записи до того, как они будут записаны в файлы данных. Журналы повторного выполнения большего размера уменьшают частоту сбросов контрольных точек и повышают пропускную способность записи. В MySQL 8.0.30+ используетсяinnodb_redo_log_capacityвместо более старогоinnodb_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
: компромисс между долговечностью и производительностью
Комбинацияinnodb_flush_log_at_trx_commitиsync_binlogопределяет вашу гарантию долговечности.
- Максимальная долговечность(рекомендовано к производству):
innodb_flush_log_at_trx_commit=1+sync_binlog=1. Каждая транзакция перед подтверждением записывается в журнал повторного выполнения и двоичный журнал на диске. Нулевая потеря данных при сбое. - Сбалансированный:
innodb_flush_log_at_trx_commit=2+sync_binlog=1. Журнал повторов записывается в кэш ОС при каждом коммите, но сбрасывается на диск только один раз в секунду. При сбое ОС может быть потеряно до 1 секунды транзакций (сбой MySQL по-прежнему безопасен). - Максимальная производительность(не рекомендуется к производству):
innodb_flush_log_at_trx_commit=0+sync_binlog=0. Записи периодически группируются и сбрасываются. Риск потери до 1 секунды транзакций при любом сбое.
[mysqld]
# Production durability settings
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_doublewrite = ON
innodb_checksum_algorithm = crc32
Конфигурация ввода-вывода[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
Соединение и управление потоками
[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
Временные таблицы и буферы сортировки
[mysqld]
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
read_rnd_buffer_size = 2M
Шаблон полной производственной конфигурации
[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
Тестирование аварийного переключения и хаос-инжиниринг
Система высокой доступности, которая никогда не тестировалась в условиях сбоя, не является действительно высокой доступностью — это гипотеза. Тестирование отказоустойчивости должно быть частью вашего обычного рабочего графика, а не чем-то, что вы обнаружите, что оно работает (или не работает) во время реального инцидента.
Тестирование управляемого аварийного переключения
# 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
Хаос-инжиниринг с помощью Litmus или Chaos Mesh
Инструменты структурированного хаоса систематически выявляют сбои и измеряют радиус взрыва. Chaos Mesh, проект CNCF, изначально интегрируется с 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'
Что измерять во время тестов аварийного переключения
- Целевое время восстановления (RTO)— Сколько времени проходит от обнаружения сбоя до восстановления обслуживания? Кластер InnoDB обычно достигает 5–30 секунд. Кластер Percona XtraDB может работать быстрее, поскольку здесь нет выборов (все узлы доступны для записи).
- Целевая точка восстановления (RPO)— какой объем данных теряется во время аварийного переключения? При синхронной репликации (групповая репликация в одноосновном режиме, PXC) RPO для зафиксированных транзакций равен нулю. При асинхронной репликации (межрегиональный набор кластеров) RPO равен задержке репликации.
- Частота ошибок приложений— Сколько запросов приложений терпят неудачу во время периода аварийного переключения? При этом проверяется не только аварийное переключение базы данных, но и логика повторных попыток подключения вашего приложения, а также скорость повторной маршрутизации маршрутизатора MySQL.
- Время разрядки соединения— Сколько времени требуется существующим подключениям к старому основному устройству для разрядки и повторного подключения к новому основному устройству?
Runbook: контрольный список сбоев основного узла
- Убедитесь, что кластер выбрал новый основной узел:
cluster.status(). - Убедитесь, что маршрутизатор MySQL выполняет маршрутизацию к новому основному устройству: проверьте журналы маршрутизатора и количество подключений.
- Мониторинг задержки репликации на остальных вторичных серверах:
SELECT * FROM performance_schema.replication_group_member_stats - Если вышедший из строя узел можно восстановить, повторно присоединитесь к нему:
cluster.rejoinInstance('gradmin@failed-node:3306') - Если неисправный узел невозможно восстановить, удалите его и добавьте новый:
cluster.removeInstance('gradmin@failed-node:3306', {force: true}) - Проверка работоспособности кластера: все участники ОНЛАЙН, ошибок репликации нет, расписание резервного копирования не повреждено
- Обновите свой план мощности: работа с двумя узлами означает нулевую отказоустойчивость до тех пор, пока третий не будет восстановлен.
Усиление безопасности
Производственное развертывание MySQL должно решать несколько проблем безопасности, помимо базовой аутентификации.
Шифрование при передаче и хранении
[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 и запечатанные секреты
# 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
Журнал аудита
[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
Матрица решений: выбор архитектуры высокой доступности MySQL
Правильная архитектура зависит от ваших конкретных требований. Вот схема принятия решений.
- Единое облако, управляемые предпочтения, совместимость с MySQL— используйте Aurora (AWS), Flexible Server Business Critical (Azure) или Cloud SQL Enterprise Plus (GCP). Они обеспечивают минимальные эксплуатационные накладные расходы.
- Единое облако с самоуправлением, требует полного управления MySQL.— используйте оператор MySQL или оператор Percona на EKS/AKS/GKE с собственными облачными классами хранения.
- Мультиоблачное или гибридное облако— используйте оператор Percona с PXC или оператор MySQL с кластером InnoDB. Уровень абстракции Kubernetes делает развертывание MySQL переносимым в облаках.
- Голый металл или край— используйте k3s с Rancher, хранилищем Longhorn, MetalLB и оператором MySQL или оператором Percona.
- Максимальная пропускная способность записи, требуется несколько основных процессоров— используйте кластер Percona XtraDB (Galera) с оператором Percona. Все узлы принимают записи с синхронной сертификацией.
- Глобальное распространение с аварийным восстановлением.— используйте InnoDB ClusterSet с асинхронной репликацией между регионами. Примите компромисс между RPO асинхронной репликации и преимуществами задержки при локальной записи.
для производственного MySQL HA
Прежде чем объявить о готовности вашего MySQL HA к развертыванию в рабочей среде, проверьте каждый пункт в этом контрольном списке.
- Состояние кластера— все участники сообщают о статусе ОНЛАЙН. Репликация группы не показывает ошибок.
- Автоматическое резервное копирование— CronJob или резервное копирование, управляемое оператором, выполняется по расписанию. Резервные копии проверены периодическими тестами восстановления.
- Мониторинг— PMM или Prometheus/Grafana для сбора показателей MySQL. Оповещения настроены для задержки репликации, насыщенности соединений, коэффициента попадания в буферный пул ниже 99 % и дискового пространства.
- Проверено аварийное переключение— основное аварийное переключение протестировано в течение последних 30 дней. RTO и RPO измерены и находятся в пределах целевых показателей SLA.
- Маршрутизация соединений— маршрутизатор MySQL или ProxySQL с проверкой работоспособности и балансировкой нагрузки. Строки подключения приложения указывают на маршрутизатор, а не на отдельные экземпляры MySQL.
- Безопасность— TLS требуется для всех подключений. Шифрование неактивных данных включено. Учетные данные хранятся в секретном менеджере. Ведение журнала аудита активно. Пользователи базы данных с наименьшими привилегиями для каждого приложения.
- Ограничения ресурсов— соответствующие запросы и ограничения ресурсов Kubernetes. PodDisruptionБюджеты на месте. Антисвязность модулей, распределяющая модули MySQL по зонам.
- План емкости— использование хранилища отслеживается с помощью предупреждений на уровне 70 % и 85 %. Расширение объема проверено. Документированы процедуры вертикального и горизонтального масштабирования.
- Runbook— документированные процедуры первичного переключения при сбое, замены узла, восстановления из резервной копии, обновления версии и аварийного режима только для чтения.
- Тестирование хаоса— запланированы регулярные эксперименты с хаосом для проверки предположений об устойчивости.
Заключение
Высокая доступность MySQL в производстве — это не просто выбор технологии — это система взаимосвязанных решений, охватывающая уровень репликации, платформу оркестрации, подсистему хранения, стек мониторинга и связанные с ними операционные процессы. Кластер InnoDB с групповой репликацией обеспечивает базовый примитив высокой доступности. Операторы Kubernetes из Oracle и Percona автоматизируют управление жизненным циклом, которое в противном случае потребовало бы значительного времени на разработку. Управление обменом облачными услугами для удобства. Развертывание «голого железа» с k3s, Rancher и Longhorn доказывает, что вам не нужен облачный провайдер для запуска MySQL HA промышленного уровня.
Наиболее важным моментом является то, что высокая доступность — это свойство всей системы, а не только базы данных. Сюда входит то, как ваше приложение обрабатывает сбои и повторные попытки подключения, как ваш прокси-уровень обнаруживает вышедшие из строя узлы и маршрутизирует их, как ваш мониторинг предупреждает об этом до того, как пользователи это заметят, как ваша стратегия резервного копирования обеспечивает восстановление в сценариях, с которыми не может справиться только HA, и как ваша команда практикует процедуры аварийного переключения, чтобы они выполнялись без ошибок в условиях реального инцидента.
Создавайте его сознательно, регулярно тестируйте и относитесь к своим модулям Runbook как к живым документам, которые развиваются с каждым инцидентом и каждым экспериментом хаоса. Именно поэтому MySQL заслужил свое место в качестве надежной и высокодоступной платформы данных в производстве.