场景还原:一次看似完美的强制切换
在某中型制造企业的ERP系统维护窗口期,DBA计划对主节点服务器进行紧急的安全补丁更新。为了确保业务零中断,运维团队选择了AlwaysOn可用性组(AG)的手动强制故障转移(Forced Service Only)。在监控面板上,可以看到AG状态从“正常”变更为“正在故障转移”,随后短暂显示为“部分可用”,最终恢复为“正常”。业务侧报告连接测试通过,但紧接着,开发团队反馈新主节点上的核心交易表无法插入数据,报错提示:“无法更新或删除记录,因为对象是只读的”。
此时,运维人员回到旧主节点查看,发现该服务器上的数据库状态虽然显示为“已加入可用性组”,但实际状态为“正在还原”(Restoring),且没有任何日志传输迹象。这是一个典型的“脑裂”或状态不同步引发的逻辑锁死场景。
故障现象深度分析
经过初步排查,我们确认了以下事实:
- 新主库(Node B):可读写,业务连接正常,但数据量比预期略少(缺少最后几秒的事务)。
- 旧主库(Node A):处于“Restoring”状态,拒绝所有非只读路由的连接尝试,日志传送队列堆积。
- 监听器:指向Node B,但部分旧会话仍缓存了对Node A的连接。
问题的核心在于:为什么Node A在成为副本后,没有正确地从“主角色”转变为“辅助角色”,而是卡在了一个中间态?这通常涉及到事务日志序列号(LSN)的不连续或端点权限问题。
标准化排查步骤
第一步:验证可用性组状态与角色
首先,我们需要在两个节点上分别执行查询,确认当前的主副本和辅助副本状态。在SSMS(SQL Server Management Studio)中,右键点击可用性组 -> 查看可用性组状态。或者直接运行以下T-SQL脚本:
SELECT
ar.replica_server_name,
ds.role_desc,
ds.synchronization_health_desc,
ds.database_state_desc
FROM sys.dm_hadr_availability_replica_states ds
JOIN sys.availability_replicas ar ON ds.replica_id = ar.replica_id;
在案例中,我们发现Node A的role_desc显示为“SECONDARY”,但database_state_desc为“RESTORING”或“RECOVERING”,这表明它并未完全准备好接受写入,且未与新的主节点建立正确的日志流。
第二步:检查端点(Endpoint)权限与连通性
AlwaysOn可用性组依赖于特定的TCP端口(默认5022)进行通信。如果故障转移过程中网络策略临时阻断,或者端点权限配置错误,会导致数据同步停滞。
执行以下命令检查端点状态:
SELECT name, state_desc, port FROM sys.tcp_endpoints WHERE type = 4; -- 4 represents AlwaysOn Availability Groups endpoint
确保两端节点的端点状态均为“OPEN”,并且防火墙允许双向通信。特别注意,在企业内网中,有时安全策略会在切换期间误拦截流量,导致LSN无法对齐。
第三步:检查事务日志备份链
如果Node A之前是主库,它在故障转移前可能仍有未发送的事务日志。当它变为辅助角色时,它需要从新主库获取最新的日志增量。如果日志备份链断裂,或者共享文件夹权限变更,同步就会失败。
检查错误日志(Error Log),搜索关键字“Availability replica”。常见的错误包括:
- “The partner network address could not be resolved.”:DNS解析问题。
- “The database failed to resume because of an error...”:通常是LSN不匹配或权限不足。
解决方案与修复操作
针对Node A卡在“Restoring”状态的问题,我们需要将其强制重新加入同步循环,并清除错误的状态缓存。
方案一:重启日志传送服务(推荐)
大多数情况下,无需断开可用性组,只需重启Node A上的SQL Server代理服务,触发其重新连接监听器和端点。
- 在Node A上,停止SQL Server Agent服务。
- 等待30秒。
- 重新启动SQL Server Agent服务。
- 观察AG状态,通常会在几分钟内从“Restoring”过渡到“Online”。
方案二:强制重设主副本(极端情况)
如果方案一无效,且确认Node B是新主库且数据完整度可接受,可以在Node A上执行以下操作,强制其放弃之前的主副本身份,完全作为新辅助节点同步:
-- 在Node A上执行,先移除数据库再重新添加(需谨慎评估风险)
ALTER DATABASE [YourDatabaseName] SET HADR OFF;
-- 确认同步停止后
ALTER DATABASE [YourDatabaseName] SET HADR AVAILABILITY GROUP = [YourAGName];
此操作会强制Node A重新从Node B拉取全量数据和日志。务必确保Node B的数据是最新的,否则可能导致数据丢失。
方案三:修复只读路由配置
业务报告中的“只读”错误,往往是因为应用程序配置了“ReadOnlyRoutingList”,但路由目标仍是处于维护状态的Node A。检查可用性组的只读路由列表:
SELECT * FROM sys.availability_group_listeners;
如果Node A在“Restoring”状态下被路由访问,应用会收到只读错误。建议将故障节点从只读路由列表中暂时移除,直到其状态恢复正常。
预防与建议
为避免此类问题再次发生,建议采取以下措施:
- 定期演练故障转移:每季度进行一次手动故障转移测试,验证自动恢复机制的有效性。
- 监控LSN滞后:设置警报监控“Log Send Queue”和“Redo Queue”的大小,一旦超过阈值立即告警。
- 优化网络策略:确保AlwaysOn所需端口(TCP 1433, 5022等)在所有节点间永久开放,避免依赖动态端口协商。
- 应用层连接字符串优化: