4. MySQL高可用实战:基于Operator的MySQL集群部署、主从复制、半同步复制与故障切换
各位好,今天我们聊点硬核的——MySQL高可用。说实话,在云原生时代之前,搞MySQL高可用那叫一个折腾:VIP漂移、MHA、Orchestrator,每个方案都有各自的坑。我最早在传统IDC里做MySQL主从切换,半夜被报警叫醒是家常便饭。后来到了Kubernetes环境,发现Operator模式确实把这件事简化了不少,但前提是你得理解它背后的原理。
今天这一章,我们就围绕MySQL Operator,把集群部署、主从复制、半同步复制、故障切换这几个核心环节彻底讲透。嗯,我会把我在生产环境中踩过的坑也一并分享出来。
4.1 为什么选择MySQL Operator?
说白了,Operator就是Kubernetes上的“自动化运维机器人”。它把DBA的日常操作——部署、扩缩容、备份、故障恢复——都变成了声明式的YAML配置。
我个人习惯用 Percona XtraDB Cluster Operator 或者 MySQL InnoDB Cluster Operator。前者基于Galera,后者基于Group Replication。今天咱们以Percona Operator为例,因为它社区活跃,文档也相对完善。
核心优势:
- 声明式部署:一个CR(Custom Resource)搞定集群
- 自动故障检测与恢复:Pod挂了自动拉起
- 半同步复制原生支持:数据一致性有保障
- 与Kubernetes生态无缝集成:Service、PV、ConfigMap
4.2 部署MySQL集群:从YAML到Running
先别急着写YAML,你得先装好Operator本身。我记得第一次部署时,忘了装CRD,结果apply下去报了一堆“unknown field”错误。嗯,这个坑我替你们踩过了。
安装Operator很简单,一条命令搞定:
kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/main/deploy/bundle.yaml
然后,我们来定义一个MySQL集群的CR。这里我给出一个生产级别的配置示例:
apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBCluster
metadata:
name: mysql-cluster-prod
spec:
secretsName: mysql-secrets
pxc:
size: 3
image: percona/percona-xtradb-cluster:8.0.32
resources:
requests:
memory: 2Gi
cpu: "1"
limits:
memory: 4Gi
cpu: "2"
volumeSpec:
persistentVolumeClaim:
storageClassName: fast-ssd
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
haproxy:
enabled: true
size: 2
image: haproxy:2.8
backup:
image: percona/percona-xtradb-cluster-operator:1.13.0-backup
schedule: "0 2 * * *"
storages:
s3:
type: s3
bucket: my-backup-bucket
region: us-east-1
credentialsSecret: s3-secret
这里有几个关键点:
- pxc.size: 3 —— 三节点集群,这是高可用的最低要求。两节点的话,脑裂风险很高。
- haproxy.enabled: true —— 开启HAProxy做流量入口,应用层不需要关心后端哪个MySQL活着。
- backup.schedule —— 定时备份到S3,我建议至少每天一次。
小提示: 存储类(storageClassName)一定要选对。我遇到过用普通HDD做MySQL数据盘的情况,那IO延迟简直感人。生产环境请务必用SSD,最好是本地NVMe盘。
4.3 主从复制与半同步复制:不只是“抄作业”
MySQL的复制,说白了就是主库写binlog,从库拉过来回放。但这里有个问题:异步复制下,主库写完binlog就返回客户端成功,从库可能还没收到。如果主库突然挂了,数据就丢了。
半同步复制(Semi-Sync Replication)就是为了解决这个问题的。它要求主库在提交事务时,至少等待一个从库确认收到了binlog,才返回客户端成功。这样,即使主库宕机,数据也不会丢。
在Percona Operator中,半同步复制是默认开启的。你可以通过配置来调整行为:
spec:
pxc:
configuration: |
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000
rpl_semi_sync_slave_enabled=1
这里 rpl_semi_sync_master_timeout=10000 的意思是:如果10秒内没有从库确认,就退化为异步复制。为什么要设超时?因为如果从库一直不响应,主库会卡住,影响业务写入。
警告: 半同步复制不是万能的。它只能保证binlog被至少一个从库接收,但不能保证从库已经应用了这些日志。如果从库在应用前挂了,数据依然可能丢失。所以,你还需要配合可靠的备份策略。
4.4 故障切换:当主库挂了之后
这是高可用最核心的部分。Operator是怎么做故障切换的?我简单梳理一下流程:
- 检测故障: Operator通过Kubernetes的liveness/readiness探针,或者通过Galera的gcache状态,判断某个节点是否健康。
- 选主: 如果主库挂了,剩下的从库会通过Galera的投票机制选出一个新主。这个过程是自动的,不需要人工干预。
- 流量切换: HAProxy会自动将流量指向新的主库。应用层无感知。
- 旧主恢复: 如果旧主库重新加入集群,它会自动同步数据,然后作为从库运行。
我曾经遇到过一个问题:主库挂了,但Operator没有立即切换。排查后发现,是因为liveness探针的超时时间设置得太长。默认是30秒,我改成了10秒,切换速度明显提升。
spec:
pxc:
livenessProbes:
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbes:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
避坑指南: 我曾经把readiness探针的timeoutSeconds设成1秒,结果集群频繁误判节点不可用,导致HAProxy不断切换后端,业务出现间歇性中断。后来我改成3秒,问题解决。探针参数一定要根据实际负载调整,别照抄文档。
4.5 知识体系与核心逻辑
为了让你更直观地理解整个架构,我画了一张流程图。它展示了从客户端请求到数据持久化的完整链路:
这张图里,你看到的是从客户端到存储的完整链路。HAProxy做流量分发,MySQL三节点通过半同步复制保证数据一致性,底层用SSD的PV做持久化,最后定时备份到S3。整个架构没有单点故障。
4.6 生产环境实战建议
最后,我总结几条实战建议,都是真金白银换来的经验:
| 场景 | 建议 | 原因 |
|---|---|---|
| 集群规模 | 至少3节点,推荐5节点 | 3节点可容忍1个节点故障,5节点可容忍2个 |
| 存储选型 | 本地NVMe SSD + 分布式存储(如Longhorn) | 本地盘性能好,分布式存储提供高可用 |
| 备份策略 | 每天全量备份 + 每6小时增量备份 | 全量用于恢复,增量减少恢复时间 |
| 监控告警 | Prometheus + Grafana + 自定义告警规则 | 关注复制延迟、连接数、磁盘空间 |
| 故障演练 | 每月至少一次手动杀Pod测试 | 验证Operator的自动恢复能力 |
最后说一句: 技术方案再完美,也抵不过人为误操作。我见过有人直接 kubectl delete pod 删了主库,结果Operator自动拉起后,数据因为半同步复制没丢。但如果是 kubectl delete pvc 呢?那数据就真没了。所以,权限管控和操作审计同样重要。
好了,这一章的内容就到这里。MySQL高可用不是一蹴而就的事,需要你在实践中不断调优。希望今天的分享能帮你少走一些弯路。