MySQL 复制不是多起几个 Pod。进入源库与副本拓扑后,身份、存储、读写路由、复制延迟和故障切换必须一起验证。本文使用 MySQL 8.4 的 source / replica 术语;旧版本文档里的 master / slave 命令不能直接照搬。
复制最基本的逻辑
- 源库负责写入并产生 binary log
- 副本拉取并重放 binary log
- 客户端通常写源库,按一致性要求决定是否读副本
概念看起来并不复杂,真正麻烦的是:复制延迟起来后怎么办,主库挂了之后怎么办,客户端到底连到了谁。
为什么 Kubernetes 会让这件事更立体
在 Kubernetes 里,一个复制集通常会依赖:
- StatefulSet 提供稳定序号身份
- Headless Service 提供 Pod 级 DNS
- 每个副本独立 PVC
- 更谨慎的 readiness 和切主逻辑
先补齐 StatefulSet、Headless Service、PV 与 PVC 和 StorageClass 的基础,再处理数据库复制。
一开始最值得确认的四件事
在你真正去看 MySQL 复制状态前,先确认:
- 每个副本是不是都有自己独立的 PVC
- 每个副本的 DNS 身份是不是稳定
- readiness 是不是代表真实可用
- 客户端是否清楚哪个地址负责写、哪个负责读
这些基础没搭对,后面主从问题通常只会显得更乱。
复制延迟为什么最值得盯
主从系统最危险的地方在于:表面看起来一切都“活着”,其实复制已经悄悄落后了。Pod Running 不代表复制健康,Service 正常也不代表读出来的数据够新。
所以,复制延迟几乎总是最关键的信号之一。
最常见的延迟来源
- 磁盘慢
- CPU 被打满
- 节点间网络抖动
- 大事务
- readiness / promote 逻辑设计不合理
真遇到问题时,第一反应通常应该先看 IO 和资源压力,而不是先去调一堆数据库参数。
路由问题和复制问题经常混在一起
很多时候,复制本身正常,流量却打错了地方。
典型模式:
- 写流量进主库 Service
- 读流量进从库 Service
- 管理或复制链路用 Pod 级 DNS
如果 Service selector、DNS 名称或客户端连接串写错,症状会看起来像“一致性问题”,但根因其实是路由关系错了。
一套可复用的检查单
上线或排障时,我会优先确认:
- 主从角色是不是明确区分了
- 每个副本是不是一卷一实例
- 读请求到底有没有真的走到从库
- 主库挂了以后谁来升主
- 旧主恢复后怎么重新加入
这些问题决定了这个系统是“看起来会跑”,还是“真的能扛事”。
先看这些命令通常最有帮助
kubectl get pods -n <ns> -o wide
kubectl get pvc -n <ns>
kubectl get svc -n <ns>
kubectl get endpointslice -n <ns> \
-l kubernetes.io/service-name=<svc> -o wide
kubectl describe pod -n <ns> <pod>
先进入源库,确认实际版本和 binary log 坐标:
kubectl exec -it -n db mysql-source-0 -- mysql -uroot -p
SELECT VERSION();
SHOW BINARY LOG STATUS\G
再进入副本:
kubectl exec -it -n db mysql-replica-0 -- mysql -uroot -p
SHOW REPLICA STATUS\G
至少检查 Replica_IO_Running、Replica_SQL_Running、Seconds_Behind_Source、Last_IO_Error 和 Last_SQL_Error。Seconds_Behind_Source 为 0 只能说明采样时没有可见延迟,不能单独证明数据一致;为 NULL 时还要判断复制线程是否停止。MySQL 8.4 已移除 SHOW MASTER STATUS 和 SHOW SLAVE STATUS,旧集群应先执行 SELECT VERSION(),再使用该版本支持的命令。
真正的考验其实是 failover
复制最危险的错觉就是:“有副本,所以应该没问题。”
复制搭起来并不难,真正决定系统韧性的,是:
- 主库挂了以后多久能升主
- 客户端在切换期会怎样
- 旧主怎么重新加入
- 这期间会不会读到旧数据或丢数据
至少在 staging 里做一次受控切主,看看:
- 提升主库要多久
- 旧主重新加入要多久
- 客户端中断窗口有多长
- 实际一致性边界是什么
三个复制验收判断
Q: 有了主从复制,就等于高可用了吗? A: 不等于。复制只是基础能力,高可用还取决于切主逻辑、客户端路由和恢复流程是否真的可靠。
Q: 如果读出来的数据不新,第一步先查什么? A: 先看复制延迟,再看磁盘和 CPU 压力,然后确认读流量是不是确实进了从库,而不是进错了服务。
Q: 为什么 Kubernetes 没法自动帮我解决这些最难的问题? A: 因为 Kubernetes 管的是生命周期和调度,不是 MySQL 的主从协议、角色提升和业务一致性语义。
把数据库链路补完整
- Helm 部署 MySQL:检查 Chart 默认值是否真的实现预期拓扑。
- Kubernetes 有状态应用:补齐备份、恢复和升级边界。
- Kubernetes 部署 MySQL:对照单实例基线。
故障切换最低验收线
在 staging 中停止源库,记录副本提升时间、写入口切换时间、客户端错误窗口、旧源库重新加入方式和可能丢失的事务范围。只看到副本 Pod Running,不算完成故障切换验证。