MySQL 高可用基石 - 复制监控与常见 HA 方案
MySQL 复制核心原理
MySQL 复制允许数据从一个 MySQL 数据库服务器(称为主库 - Primary,旧称 Master)复制到一个或多个其他的 MySQL 服务器(称为从库 - Replica,旧称 Slave)。
复制的主要目的:
- 高可用性 (High Availability):当主库发生故障时,可以将一个从库提升为新的主库,从而快速恢复服务。
- 读扩展 (Read Scalability):可以将读密集型的查询分发到从库上执行,减轻主库的压力,提高整体读取性能。
- 备份 (Backups):可以在从库上执行备份操作,避免对主库产生额外的负载和锁竞争。
- 地理分布 (Geographic Distribution):可以将从库部署在不同地理位置,让用户就近访问数据,或作为异地灾备。
基本架构 (主从复制):
- 主库 (Primary/Master):
- 接收所有写操作(INSERT, UPDATE, DELETE)。
- 将所有数据变更事件记录到其二进制日志 (Binary Log,
binlog
) 中。
- 从库 (Replica/Slave):
- 连接到主库。
- 拥有一个 I/O 线程 (I/O Thread):该线程从主库请求并读取
binlog
事件,然后将这些事件写入到从库本地的中继日志 (Relay Log,relay-log
)。 - 拥有一个 SQL 线程 (SQL Thread):该线程读取中继日志中的事件,并在从库上重放 (replay) 这些事件,从而使从库的数据与主库保持一致。
二进制日志格式 (Binlog Formats):
binlog_format
参数的设置对复制的可靠性和行为有重要影响:
- STATEMENT (SBR - 基于语句的复制):(已不推荐用于生产) 直接记录执行的 SQL 语句。对于某些非确定性函数(如
UUID()
,NOW()
依赖于执行时间)或包含用户定义函数的语句,可能导致主从数据不一致。 - ROW (RBR - 基于行的复制):强烈推荐使用。记录实际发生变更的数据行(通常是变更前后的行镜像,或仅变更后的镜像)。更安全,更能保证数据一致性,对绝大多数场景都适用。这是 MySQL 5.7.7 及之后版本的默认格式。
- MIXED (混合格式):MySQL 会尝试对“安全”的语句使用 SBR,对“不安全”的语句使用 RBR。
GTID (全局事务标识符 - Global Transaction Identifier):
在 MySQL 5.6 版本之后引入,强烈推荐在所有新的复制环境中使用 GTID。
- 没有 GTID 的痛点: 传统的基于
binlog
文件名和位置 (position) 的复制,在进行故障切换、添加新从库、改变复制源等操作时非常复杂,容易出错,尤其是在多级复制或更复杂的拓扑中。 - GTID 如何解决: 为复制拓扑中的每一个已提交的事务分配一个全局唯一的 ID (格式如
source_id:transaction_id
)。主库和从库都会记录已执行的 GTID 集合。
- 优势: 极大简化了故障切换(从库可以自动找到正确的复制点)、添加新从库、以及在不同主库之间切换复制源等操作。
- 配置: 需要在
my.cnf
中设置gtid_mode=ON
和enforce_gtid_consistency=ON
。
半同步复制 (Semi-Synchronous Replication):
- 异步复制 (Asynchronous - 默认):主库在本地提交事务后,就向客户端返回成功,然后异步地将
binlog
事件发送给从库。如果主库在事件发送到从库并被从库应用前崩溃,可能会导致数据丢失(RPO > 0)。 - 半同步复制: 为了减少数据丢失的风险,主库在本地提交事务后,会等待至少一个从库确认已接收到该事务的
binlog
事件(并已写入其 relay log)之后,才向客户端返回成功。
- 这将写操作的延迟增加了一个网络来回的时间,但显著降低了主库单点故障时数据丢失的概率。
- 可以配置超时时间 (
rpl_semi_sync_master_timeout
),如果超时仍未收到从库确认,主库会自动转为异步复制模式,以保证可用性。
监控复制健康状态
对于 SRE 来说,持续监控复制链路的健康状况至关重要。一个断开或延迟严重的复制链路意味着失去了高可用保障,并且可能导致数据不一致。
核心监控点 (通过 SHOW REPLICA STATUS\G
或旧版的 SHOW SLAVE STATUS\G
查看):
Replica_IO_Running
(或Slave_IO_Running
): 必须是Yes
。如果为No
,表示 I/O 线程没有运行或没有连接到主库。需要检查网络连通性、主库状态、复制用户权限、密码等。Replica_SQL_Running
(或Slave_SQL_Running
): 必须是Yes
。如果为No
,表示 SQL 线程已停止,通常是因为在应用某个binlog
事件时遇到了错误(如主键冲突、表不存在等)。需要检查Last_SQL_Error
字段获取详细错误信息。Seconds_Behind_Source
(或Seconds_Behind_Master
): 这是一个非常常见但容易被误解的指标。它表示 SQL 线程当前正在执行的事件的时间戳与该事件在主库上原始执行时的时间戳之间的秒数差。
- 局限性:
- 如果从库负载很高(例如,同时处理大量读查询),SQL 线程可能会被阻塞,导致这个值增大,即使 I/O 线程可能已经拉取了最新的
binlog
。 - 主从服务器之间的时钟不同步也会影响其准确性。
- 它不能完美反映“真实”的复制延迟。
Executed_Gtid_Set
: (如果使用 GTID) 从库上已经执行完毕的 GTID 集合。Retrieved_Gtid_Set
: (如果使用 GTID) 从库 I/O 线程已经从主库获取到的 GTID 集合。Last_IO_Error
,Last_SQL_Error
: 这两个字段包含了最近一次 I/O 线程或 SQL 线程出错的详细信息,是排查复制问题的关键线索。
更准确的延迟监控工具:
pt-heartbeat
(Percona Toolkit): 这个工具会在主库上定期插入一个带有时间戳的“心跳”记录,然后监控这个记录出现在从库上需要多长时间。这能更准确地衡量端到端的复制延迟。
通过 Prometheus 监控 (使用 mysqld_exporter
):
mysqld_exporter
暴露了大量关于复制状态的指标,例如:
mysql_slave_status_slave_io_running
mysql_slave_status_slave_sql_running
mysql_slave_status_seconds_behind_master
mysql_slave_status_retrieved_gtid_set
mysql_slave_status_executed_gtid_set
- 以及各种错误计数器。
关键告警: 务必为以下情况设置告警:
Replica_IO_Running != Yes
Replica_SQL_Running != Yes
- 复制延迟 (
Seconds_Behind_Source
或pt-heartbeat
延迟) 超过预设阈值。 - 出现复制错误 (
Last_SQL_Error
或Last_IO_Error
非空)。
常见 MySQL 高可用 (HA) 方案概览
基于 MySQL 复制,社区和厂商发展出了多种高可用解决方案:
- 主从复制 + 手动/脚本化故障切换:
- 最简单的配置。当主库故障时,需要 DBA 或 SRE 手动介入,将某个从库提升为新的主库,并修改应用连接。
- 缺点: RTO 较长,依赖人工操作,容易出错。
- 主从复制 + 虚拟 IP (VIP) / DNS 切换:
- 使用一个浮动的 VIP 指向当前活动的主库。故障切换时,通过脚本将 VIP 漂移到新提升的主库上。
- 或者,在故障切换后更新 DNS A 记录指向新主库(但 DNS 缓存和 TTL 可能导致切换生效延迟)。
- 可以使用
keepalived
等工具来管理 VIP。
- MHA (Master High Availability Manager and Tools for MySQL):
- 开源的 MySQL 主库自动故障切换和从库提升工具。
- MHA Manager 节点负责监控主库健康,当主库故障时,它会自动选择最佳从库,应用差异日志(保证数据一致性),提升为新主库,并让其他从库指向新主。
- 相对成熟,被广泛使用,但配置和管理仍有一定复杂度。
- Orchestrator:
- 开源的 MySQL 复制拓扑管理器和故障切换工具。
- 提供 Web UI、API 和命令行界面,用于可视化和管理复制拓扑。
- 能够自动检测主库故障,并执行自动或半自动的故障切换(支持基于 GTID 的切换)。
- MySQL InnoDB Cluster (MySQL Group Replication + MySQL Router + MySQL Shell):
- Oracle 官方推出的基于组复制 (Group Replication) 的高可用和高一致性解决方案。
- 组复制: 提供“几乎同步”的复制,内置冲突检测和解决机制,成员自动加入和移除。可以配置为单主模式(所有写操作在一个节点)或多主模式(所有节点可写,但并发写入可能引发冲突和性能问题,需谨慎使用)。
- MySQL Router: 轻量级中间件,自动感知 InnoDB Cluster 的拓扑变化,将应用连接路由到活动的写节点(单主模式下)或所有可写节点(多主模式下)。
- MySQL Shell: 用于配置和管理 InnoDB Cluster 的管理工具。
- Percona XtraDB Cluster (PXC) / Galera Cluster:
- 基于 Galera 技术栈的同步多主复制解决方案。集群中的所有节点都是对等的,都可以接受写操作(但并发写入多个节点可能导致死锁和性能下降)。
- 提供强数据一致性(“真同步”或“几乎同步”),节点加入和离开自动处理。
- 优缺点: 数据一致性强,无单点写瓶颈(理论上)。但对网络延迟敏感,写性能可能不如异步复制,运维和调优复杂度较高。
- 数据库代理 (Database Proxies) 如 ProxySQL, MaxScale:
- 这些是智能的数据库中间件,位于应用程序和 MySQL 服务器之间。
- 功能丰富:连接池、读写分离、查询缓存、查询路由与重写、SQL 防火墙、以及基于后端健康检查的自动故障切换和流量重定向。
- 它们通常与上述的某种复制架构(如主从复制、InnoDB Cluster)结合使用,提供更完善的接入层高可用和管理能力。
- 云厂商托管服务 (如 AWS RDS, GCP Cloud SQL, Azure Database for MySQL):
- 主流云服务商都提供托管的 MySQL 服务,并内置了高可用选项(例如,跨可用区的主备部署和自动故障切换)。
- 优点: 极大简化了运维复杂度,云厂商负责底层基础设施、复制设置、备份和故障切换。
- 缺点: 对底层细节的控制力较弱,可能存在厂商锁定,成本也需要考量。
选择 HA 方案的考量:
- 业务的 RPO 和 RTO 需求: 这是最重要的驱动因素。
- 数据一致性要求: 对同步复制还是异步复制的容忍度。
- 应用特性: 读密集型还是写密集型?是否能容忍写冲突?
- 运维复杂度与团队技能: 团队是否有能力管理和维护复杂的集群方案?
- 成本: 硬件、软件许可(如果需要)、人力成本。
- 厂商锁定: 是否希望避免被特定云厂商或商业软件锁定。
总结
MySQL 复制是实现其高可用性、读扩展和灾难恢复的基石。作为 SRE,持续、有效地监控复制链路的健康状况(包括延迟、错误、线程状态)是日常核心工作。当需要更高层次的可用性保障时,我们可以根据业务需求、成本和团队能力,从多种 HA 解决方案中进行选择,从简单的 VIP/DNS 切换,到 MHA/Orchestrator 自动化故障转移,再到基于组复制的 InnoDB Cluster 或 PXC/Galera 这类同步/多主集群,以及利用 ProxySQL 等中间件或云厂商的托管服务。
选择没有绝对的好坏,只有是否适合。
了解了如何保障 MySQL 的持续在线和数据复制后,下一个重要议题自然是数据库的性能。如何监控 MySQL 的性能指标?如何建立性能基线?如何初步诊断常见的性能问题?这些都将在我们下一篇中探讨。敬请期待!