4. 数据库灾备故障:Oracle DataGuard日志断档、MySQL主从同步延迟与中断、SQL Server AlwaysOn副本状态异常
数据库灾备,说白了就是给数据买份“保险”。但保险也有失效的时候。我干了十几年运维,见过太多灾备系统在关键时刻掉链子。今天咱们就聊聊三种主流数据库的灾备故障——Oracle DataGuard、MySQL主从、SQL Server AlwaysOn。这些坑,我基本都踩过。
核心观点:灾备故障不可怕,可怕的是你不知道它为什么挂。日志断档、同步延迟、副本异常——每个问题背后都有固定的排查路径。
4.1 Oracle DataGuard 日志断档
DataGuard的日志断档,是我个人最头疼的问题之一。为什么?因为一旦断档,主备库之间的数据差距会越来越大,恢复起来极其痛苦。
4.1.1 断档的典型表现
你登录备库,执行 select * from v$archive_gap;,发现有记录。或者你在告警日志里看到类似这样的信息:
FAL[client]: Failed to request gap sequence
GAP - thread 1 sequence 100-200
嗯,这就是断档了。备库缺少了100到200号归档日志,中间断了。
4.1.2 为什么会断档?
我遇到过的情况,无非这么几种:
- 网络抖动:主库传日志到备库时,网络闪断,日志没传过去。
- 磁盘空间满:备库的归档目录满了,新日志写不进去。
- 主库归档删除过快:主库的归档日志被RMAN或其他脚本删了,备库还没来得及应用。
- 备库宕机:备库重启后,发现主库已经归档了好几个日志,中间出现了空洞。
警告:千万不要在主库上随意删除归档日志,除非你确认备库已经应用完毕。我曾经见过一个同事,为了省空间,把主库的归档全删了,结果备库断档了三天,最后只能重新搭建。
4.1.3 排查与修复步骤
遇到断档,我的习惯是这么处理:
- 确认断档范围:在备库执行
select * from v$archive_gap;,记录缺失的日志序列号。 - 检查主库归档是否存在:在主库上找找这些日志还在不在。如果还在,直接拷贝到备库,用
alter database register logfile注册。 - 如果主库归档已删除:那就只能用RMAN的增量备份来恢复了。从主库做一个增量备份,恢复到备库。
- 调整归档策略:修改主库的归档删除策略,确保备库应用完再删。比如设置
CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY;。
-- 备库检查断档
SQL> SELECT * FROM V$ARCHIVE_GAP;
-- 主库注册缺失日志(假设日志文件还在)
SQL> ALTER DATABASE REGISTER LOGFILE '/u01/arch/1_100_123456.arc';
4.2 MySQL 主从同步延迟与中断
MySQL的主从同步,可以说是最常用的灾备方案,但也是最容易出问题的。延迟、中断,几乎是家常便饭。
4.2.1 同步延迟的根源
你想想看,主库每秒能处理几千个事务,从库却只有一个线程在应用binlog。这能不延迟吗?
我遇到过最夸张的一次,延迟达到了两小时。查了半天,发现是从库上有个大事务在跑,把IO打满了。
技巧:用 show slave status\G 查看 Seconds_Behind_Master 字段。但这个值并不完全准确,它只代表SQL线程的延迟,不代表IO线程的延迟。
4.2.2 常见中断原因
| 错误类型 | 典型错误号 | 原因 |
|---|---|---|
| 主键冲突 | 1062 | 从库上已有相同主键的数据,插入失败 |
| 表不存在 | 1146 | 从库上缺少某张表,或者表结构不一致 |
| 连接失败 | 2003 | 从库连不上主库,网络或认证问题 |
| 日志损坏 | 1594 | binlog文件损坏,无法解析 |
4.2.3 排查与修复
我的排查流程是这样的:
- 看状态:执行
show slave status\G,重点关注Slave_IO_Running和Slave_SQL_Running是不是YES。 - 看错误:如果
Last_Error有内容,直接看错误信息。比如主键冲突,就跳过这条记录,或者手动修复从库数据。 - 看延迟:如果
Seconds_Behind_Master很大,检查从库的CPU、IO、内存。是不是有慢查询?是不是磁盘IO瓶颈? - 临时跳过:如果错误不影响大局,可以用
set global sql_slave_skip_counter=1;跳过一条错误。但注意,这只是权宜之计。
-- 查看从库状态
mysql> show slave status\G
-- 跳过一条错误(慎用)
mysql> stop slave;
mysql> set global sql_slave_skip_counter=1;
mysql> start slave;
警告:跳过错误会导致数据不一致。如果你做主从切换,这些不一致的数据可能会引发更大的问题。我建议,能修复就修复,别偷懒。
4.3 SQL Server AlwaysOn 副本状态异常
SQL Server的AlwaysOn,比前两个要复杂一些。它涉及可用性组、副本、侦听器,任何一个环节出问题,都可能导致副本状态异常。
4.3.1 常见异常状态
在AlwaysOn仪表盘里,你会看到副本状态变成这些:
- NOT SYNCHRONIZING:副本没有在同步。可能是网络断了,或者副本挂了。
- SYNCHRONIZING:正在同步,但进度卡住了。数据一直在传,就是传不完。
- HEALTHY:正常状态,但数据可能已经延迟。
- RESOLVING:副本正在尝试重新加入可用性组。通常是重启后出现的。
4.3.2 排查思路
我个人习惯,先看三个地方:
- Windows事件查看器:AlwaysOn的很多错误会记录在系统日志里。
- SQL Server错误日志:执行
xp_readerrorlog查看最近的错误。 - DMV视图:用
sys.dm_hadr_database_replica_states查看每个数据库的同步状态。
-- 查看每个数据库的同步状态
SELECT
ar.replica_server_name,
db_name(drs.database_id) as db_name,
drs.synchronization_state_desc,
drs.synchronization_health_desc,
drs.last_sent_time,
drs.last_received_time,
drs.last_hardened_time,
drs.last_redone_time
FROM sys.dm_hadr_database_replica_states drs
JOIN sys.availability_replicas ar ON drs.replica_id = ar.replica_id;
4.3.3 修复案例
我记得有一次,一个客户的AlwaysOn副本状态变成了“NOT SYNCHRONIZING”。查了半天,发现是主副本上的日志文件太大,导致日志传送超时。
解决方案很简单:
- 先备份主副本的日志,缩小日志文件。
- 然后手动恢复副本上的日志,让副本追上进度。
- 最后重新加入可用性组。
-- 在主副本上备份日志
BACKUP LOG [YourDatabase] TO DISK = 'D:\Backup\YourDatabase_log.trn';
-- 在副本上恢复日志(带 NORECOVERY)
RESTORE LOG [YourDatabase] FROM DISK = 'D:\Backup\YourDatabase_log.trn' WITH NORECOVERY;
技巧:AlwaysOn的日志传送是异步的(默认),但你可以改成同步模式。同步模式能保证数据不丢,但会增加主库的写入延迟。怎么选?看业务需求。
4.4 本章知识体系
下面这张图,是我总结的三种数据库灾备故障的排查逻辑。你可以把它当成一个速查表。
说白了,数据库灾备故障的根因,无非就是日志连续性被打破、网络不稳定、磁盘空间不足。你只要抓住这三个点,排查起来就有方向了。