系统学习 学习路径总入口:先选领域,再建立模型,最后用故障演练验证

以 PostgreSQL 和 MySQL 为主线,完成数据库主从切换或故障转移的确认、摘流量、提升、切换、验证与回切

适用场景

先区分两个概念:switchover 是计划内切换,通常要求复制追平、可控、尽量零丢失;failover 是故障转移,可能丢失最后一段未复制的事务,必须明确 RPO 并选择数据最完整的从库。

前置检查

  1. 确认拓扑和复制健康。PostgreSQL 在主库查看复制状态、同步模式和复制槽,在从库查看回放进度:
psql -h <primary> -c "SELECT application_name, state, sync_state, sent_lsn, replay_lsn, write_lag, flush_lag, replay_lag FROM pg_stat_replication;"
psql -h <primary> -c "SHOW synchronous_standby_names;"
psql -h <primary> -c "SELECT slot_name, active, restart_lsn FROM pg_replication_slots;"
psql -h <replica> -c "SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), now() - pg_last_xact_replay_timestamp();"

MySQL 查看复制线程、GTID、延迟和只读状态:

mysql -h <primary> -e "SHOW REPLICA STATUS\G"
mysql -h <primary> -e "SELECT @@GLOBAL.gtid_mode, @@GLOBAL.enforce_gtid_consistency, @@GLOBAL.gtid_executed;"
mysql -h <replica> -e "SHOW REPLICA STATUS\G"
mysql -h <replica> -e "SELECT @@GLOBAL.read_only, @@GLOBAL.super_read_only;"

重点确认 Replica_IO_Running、Replica_SQL_Running 为 Yes,Seconds_Behind_Source 可接受,Retrieved_Gtid_Set 与 Executed_Gtid_Set 没有缺口,Auto_Position 已开启。字段名可能随版本变化,以官方文档为准。

  1. 评估数据边界。计划内切换应等从库追平,比较主库 LSN 或 GTID 与从库回放位置;故障转移要选择 LSN/GTID 最靠前、relay log 已回放完的从库,并记录可能丢失的事务范围。同步、半同步和 Group Replication 的确认机制不同,不能只看“复制线程还活着”。

  2. 确认所有写入方。列出应用、批处理、定时任务、CDC、报表、数据同步和运维脚本;检查连接串、DNS TTL、VIP、负载均衡、ProxySQL/MySQL Router、PgBouncer 等连接池。绕过代理直连旧主库的客户端可能继续写入旧主库,必须提前改造或关停。

  3. 准备权限和工具。确认复制账号、管理账号、pg_ctl、pg_rewind、pg_basebackup、mysqladmin、CHANGE REPLICATION SOURCE TO 和编排工具可用。计划内切换先在测试环境演练并记录耗时;故障转移要有一键隔离旧主库的手段,例如摘 VIP、关端口、停实例或网络 ACL。

  4. 备份与回滚材料。切换前做一次可验证的备份或存储快照,保留 WAL/binlog 归档、旧主库数据目录和配置。确认旧主库隔离后不会被自动拉起并接受写入;没有把握时先停止旧主库,再提升从库。

  5. 约定 RPO/RTO 和验收标准。业务方要明确可丢失窗口、恢复时间、读一致性要求和回切条件。准备监控看板:复制延迟、连接数、锁等待、慢查询、错误率、队列积压和备份归档状态。

操作步骤

1. 冻结变更并记录基线

暂停 DDL、数据迁移、批处理和会写库的定时任务,记录切换前的位置:

psql -h <primary> -Atc "SELECT pg_current_wal_lsn(), clock_timestamp();" > /backup/pg-before.txt
mysql -h <primary> -e "SELECT @@GLOBAL.gtid_executed, NOW();" > /backup/mysql-before.txt

记录主库、从库、复制模式、连接数和关键指标。计划内切换通知业务方;故障转移先同步影响面和决策人。

2. 确认复制并选定新主

计划内切换:等待从库追平,确认主库没有长时间运行的事务,复制槽没有失效;在 MySQL 中确认从库的 Executed_Gtid_Set 已包含主库的 gtid_executed,必要时用 WAIT_FOR_EXECUTED_GTID_SET 等待。

故障转移:先隔离旧主库,再从剩余从库中选择数据最完整的一台。检查其 relay log 是否回放完、GTID 是否连续、磁盘和网络是否健康;不要选择延迟最大或复制已中断的节点。使用 Patroni 时用 patronictl list 查看 leader 和 lag;使用 Group Replication 时查看成员状态和多数派。

3. 摘流量并阻止双写

先把旧主库从读写入口摘除,再停止写入。PostgreSQL 可以把默认事务设为只读并检查剩余连接,或直接停止实例;MySQL 设置只读并等待复制追平:

psql -h <primary> -c "ALTER SYSTEM SET default_transaction_read_only = on;"
psql -h <primary> -c "SELECT pg_reload_conf();"
psql -h <primary> -c "SELECT pid, usename, application_name, state FROM pg_stat_activity WHERE datname = 'app';"
mysql -h <primary> -e "SET GLOBAL read_only = ON; SET GLOBAL super_read_only = ON;"
mysql -h <primary> -e "SHOW PROCESSLIST;"

ALTER SYSTEM 只影响新会话,已有连接仍可能写入;要结合应用停机、连接池排空、撤销权限或防火墙隔离。MySQL 的 super_read_only 也会阻止高权限账号写入。确认没有写入后,再把旧主库从 VIP/负载均衡/DNS 移除。

双写是切换中最危险的状态。旧主库必须保持隔离或只读,直到新主库稳定、数据核对完成;不要把旧主库重新加入读写池,也不要在旧主库上手工补数据。

4. 提升新主

PostgreSQL 在选定从库上执行提升,并确认它已退出恢复模式:

pg_ctl promote -D <data-directory>
psql -h <new-primary> -c "SELECT pg_is_in_recovery(), pg_current_wal_lsn();"

也可以使用 SQL 函数 SELECT pg_promote();。提升后检查时间线和归档,确认新主库可以写入;如果原配置了同步复制,先调整 synchronous_standby_names,避免新主库因等待旧从库而阻塞写入。

MySQL 在选定从库上停止并清理复制配置,再开放写入:

mysql -h <new-primary> -e "STOP REPLICA; RESET REPLICA ALL;"
mysql -h <new-primary> -e "SET GLOBAL super_read_only = OFF; SET GLOBAL read_only = OFF;"
mysql -h <new-primary> -e "SELECT @@GLOBAL.gtid_executed, @@GLOBAL.read_only, @@GLOBAL.super_read_only;"

使用 InnoDB Cluster 时,用 cluster.status() 确认成员状态,并按工具的切换/强制选主流程执行;Orchestrator、MHA 或 Patroni 也优先用工具提升,避免手工步骤与自动故障转移冲突。

5. 切换流量

更新 VIP、DNS、负载均衡、ProxySQL/MySQL Router 和连接池配置,把读写流量指向新主库。提前降低 DNS TTL;切换后刷新连接池、重启或滚动重启应用,确认没有进程仍持有旧主库连接。先放少量流量做金丝雀,再逐步放大。

观察错误率、延迟、连接数、锁等待、复制延迟和队列积压。旧主库保持隔离;新主库稳定后,把其他从库重新指向新主库。PostgreSQL 更新 primary_conninfo 和复制槽后重启备库;MySQL 用 CHANGE REPLICATION SOURCE TO 指向新主库,GTID 模式设置 SOURCE_AUTO_POSITION=1,旧语法对应 CHANGE MASTER TO 和 MASTER_AUTO_POSITION=1。

6. 重建旧主库并准备回切

旧主库不能直接回到集群。PostgreSQL 若时间线已经分叉,用 pg_rewind 或 pg_basebackup 重建;pg_rewind 要求数据页校验或 wal_log_hints 等前提,不满足时直接做基础备份。MySQL 用克隆、物理备份或逻辑备份重新同步,再按 GTID 指向新主库。

回切应在业务稳定、复制追平、数据核对后按计划执行,不要在新主库刚接管时立即回切。步骤与切换对称:冻结写入、确认追平、摘流量、提升原主库、切换入口、重建从库。

验证

失败与回滚

新主库提升后不可用。 立即隔离该节点,从剩余从库中选择 LSN/GTID 最完整的一台提升;不要回到旧主库直接写入。记录已切换的流量和可能丢失的事务,业务侧暂停非关键写入。

出现双写。 立即停止一侧写入,比较 LSN/GTID、binlog 和业务数据,确定唯一权威主库;另一侧必须重建,不能靠手工合并猜测。双写期间产生的冲突要逐笔核对,必要时用备份和 PITR 恢复。

复制无法恢复。 PostgreSQL 检查 primary_conninfo、复制槽、pg_hba.conf、时间线和 WAL 是否缺失;必要时 pg_rewind 或重新 pg_basebackup。MySQL 检查 GTID、server_id、复制账号、binlog 保留和复制配置,无法追平时用备份重建。

应用仍连旧主库。 检查 DNS TTL、连接池、VIP、负载均衡健康检查和直连配置;让旧主库保持只读,再逐步重启或滚动应用,不要为恢复应用而放开旧主库写入。

故障转移丢失数据。 根据 LSN/GTID/binlog 量化丢失范围,评估是否需要从备份或 PITR 恢复到独立实例补数据;如实记录 RPO 违约,不要用“复制正常”掩盖已丢失的事务。

回切失败。 保持新主库继续服务,把回切当成新的变更重新评估;旧主库只有在数据一致、复制追平、写入已冻结时才能提升。计划内 switchover 才适合快速回切,故障转移后的回切要更保守。

相关命令

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. switchover 和 failover 的关键区别是什么?
  2. 为什么提升新主库之前必须先摘流量并隔离旧主库?
  3. PostgreSQL 与 MySQL 在切换后的复制重建上各有哪些关键差异?
答案
  1. switchover 是计划内切换,通常要求从库追平、可控、尽量零丢失;failover 是故障转移,主库已不可用,可能丢失最后一段未复制事务,必须选择数据最完整的从库并明确 RPO。
  2. 为防止双写和脑裂:旧主库仍可写会与新主库分叉;先摘流量、设只读或隔离旧主库,确认从库追平后再提升,保证只有一个可写主库。
  3. PostgreSQL 依赖 LSN、时间线、复制槽和 primary_conninfo,旧主常用 pg_rewind 或 pg_basebackup 重建;MySQL 依赖 GTID/binlog,使用 CHANGE REPLICATION SOURCE TO、RESET REPLICA ALL,旧主常用克隆或备份重建,并注意半同步与 Group Replication 的确认机制。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令