一、当镜像变成"单相思"——事故现象诊断

某金融公司周五下午3点,主数据库突然报错:"无法与镜像服务器建立连接"。DBA小张发现两地机房间的网络设备出现闪断,此时:

  • 主体数据库显示状态为"已断开"
  • 镜像数据库处于"正在恢复"状态
  • 事务日志堆积量达到15GB
  • 应用程序开始向日志写入大量超时错误
-- 查看镜像状态查询(需在主库执行)
SELECT 
    database_id,
    mirroring_state_desc, 
    mirroring_safety_level_desc,
    mirroring_partner_instance 
FROM sys.database_mirroring 
WHERE database_id = DB_ID('FinanceDB');

/* 返回结果示例:

database_id | mirroring_state_desc | mirroring_safety_level_desc | mirroring_partner_instance
-----------------------------------------------------------------------------------------
5           | DISCONNECTED         | FULL                        | TCP://mirror01:5022

*/

此时最危险的情况是:当网络恢复后,如果处理不当可能导致数据丢失或日志损坏。去年某电商就曾因此丢失2小时交易数据,教训深刻。

二、断网恢复四步急救法(基于SQL Server 2019)

2.1 第一步:网络层体检

# 测试双向网络连通性(需在主体服务器执行)
Test-NetConnection -ComputerName mirror01 -Port 5022

# 检查防火墙规则
Get-NetFirewallRule -DisplayName "SQL Mirroring*" | Format-Table Name,Enabled

# 示例输出:
# Name              Enabled
# ----              -------
# SQL_Mirror_Port   True

特别注意:跨机房的网络抖动往往伴随MTU设置问题,可通过以下命令检测:

ping -f -l 1472 mirror01

2.2 第二步:安全模式下的紧急同步

当使用高安全模式(High Safety)时,需特别注意事务日志的保留策略:

-- 强制切换安全模式(仅在紧急情况下使用)
ALTER DATABASE FinanceDB SET PARTNER SAFETY OFF;

-- 检查日志复用情况
DBCC SQLPERF(LOGSPACE);

-- 示例结果:
-- Database Name Log Size (MB) Log Space Used (%) 
-- FinanceDB      20480         98.76

此时如果日志即将填满,必须立即执行日志备份:

BACKUP LOG FinanceDB TO DISK = 'E:\Backup\FinanceDB_emergency.trn'
WITH COMPRESSION, FORMAT;

2.3 第三步:镜像重连的生死时速

重连操作就像给病人做心脏复苏,必须严格按照顺序:

-- 在主体服务器执行
ALTER DATABASE FinanceDB SET PARTNER RESUME;

-- 在镜像服务器执行
ALTER DATABASE FinanceDB SET PARTNER RESUME;

-- 验证恢复进度
SELECT 
    database_name = DB_NAME(database_id),
    redo_rate_KB_per_sec = 
        (redo_queue_size * 8) / NULLIF(DATEDIFF(second, last_redo_time, GETDATE()),0),
    mirroring_state_desc
FROM sys.dm_db_mirroring;

注意!如果遇到错误1412(超时),可尝试重置端点:

-- 重建端点(需在双方执行)
CREATE ENDPOINT Mirroring
STATE = STARTED
AS TCP (LISTENER_PORT = 5022)
FOR DATABASE_MIRRORING (ROLE = PARTNER);

2.4 第四步:数据一致性验证

使用DBCC校验数据完整性:

DBCC CHECKDB('FinanceDB') WITH 
    ALL_ERRORMSGS, 
    NO_INFOMSGS,
    DATA_PURITY;

当发现页级损坏时,可通过镜像数据库进行页面还原:

-- 从镜像恢复单个页面
RESTORE DATABASE FinanceDB 
PAGE = '1:154' 
FROM MIRROR PARTNER;

三、实战中的魔鬼细节

3.1 自动故障转移的陷阱

某次网络中断后自动切换成功,但实际存在数据差异:

-- 检测未提交事务
SELECT 
    transaction_id,
    database_transaction_log_bytes_used
FROM sys.dm_tran_database_transactions
WHERE database_id = DB_ID('FinanceDB');

此时必须使用日志传送进行数据补偿:

-- 应用增量日志
RESTORE LOG FinanceDB 
FROM DISK = 'E:\Backup\FinanceDB_log_001.trn'
WITH NORECOVERY;

3.2 性能优化急救包

网络恢复初期容易遇到IO瓶颈:

-- 调整异步提交模式的批量大小
ALTER DATABASE FinanceDB SET PARTNER TIMEOUT 15;

监控关键性能计数器:

Get-Counter -Counter "\SQLServer:Database Mirroring(*)\*" -SampleInterval 2

四、技术选型中的生存智慧

4.1 何时选择数据库镜像?

  • 跨地域的DR解决方案(100公里内)
  • 需要秒级故障转移的OLTP系统
  • 预算有限的HA方案(相比AlwaysOn节省30%成本)

4.2 镜像技术的阿喀琉斯之踵

某物流公司曾因以下配置错误导致数据丢失:

-- 错误示例:错误的安全模式切换
ALTER DATABASE OrderDB SET PARTNER SAFETY FULL; -- 应在两端执行

正确做法应通过配置管理器修改,并验证伙伴优先级:

SELECT 
    role_desc,
    partner_server,
    partner_priority
FROM sys.database_mirroring_endpoints;

五、灾备体系的最后防线

建议每季度执行断网演练:

  1. 随机断开镜像网络接口
  2. 制造10%数据写入负载
  3. 30分钟后恢复网络
  4. 测量RTO(恢复时间目标)和RPO(恢复点目标)

某银行通过该方法将RPO从15分钟缩短到47秒。

六、写给架构师的备忘录

  • 网络延迟超过5ms时考虑异步模式
  • 日志磁盘应保证至少20%的剩余空间
  • 定期清理镜像监控历史表:
DELETE FROM msdb.dbo.mirroring_history 
WHERE backup_finish_date < DATEADD(month, -3, GETDATE());

总结:与不确定性的持久战

通过某证券公司的真实案例:他们在2022年经历7次网络中断,但通过完善的恢复策略实现零数据丢失。关键要素包括:

  1. 实时网络质量监控(延迟>2ms自动告警)
  2. 双活日志传送通道(主备各保留3份日志)
  3. DBA团队的"肌肉记忆"训练(每月实战演练)

记住:数据库镜像不是银弹,而是需要配合网络层HA、存储层快照的复合型方案。当遇到持续断网超过TTL(生存时间)时,必须启动应急决策流程——这可能是DBA职业生涯中最艰难但最重要的判断时刻。