許多歷史應用(如樓宇自控系統)不支持連接字符串 MultiSubnetFailover=True 或重試邏輯。當 SQL Server 可用性群組/故障轉移叢集 (FCI) 發生故障轉移時,SQL Server 服務在新節點重啟,非感知應用連接中斷導致業務凍結。雖可部署 SCOM/監控平台,但跨團隊協調成本高。本文提供零依賴、極低維護的 Agent 作業通知方案。
SQL Server Agent 作業支持 「啟動時執行」 排程類型。故障轉移本質是資源組移動 → SQL Server 服務重啟 → Agent 服務跟隨啟動 → 作業自動觸發 → 發送郵件通知。
msdb.dbo.sysmail_account、profile 測試發送成功。
USE msdb;
GO
CREATE OR ALTER PROC dbo.usp_Notify_Failover
@Subject NVARCHAR(255) = N'SQL Server 服務啟動/故障轉移告警',
@Body NVARCHAR(MAX) = N'',
@ProfileName SYSNAME = 'DBA_Alert_Profile',
@Recipients NVARCHAR(MAX) = 'dba-team@company.com;vendor-support@vendor.com'
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Instance NVARCHAR(128) = @@SERVERNAME;
DECLARE @Time DATETIME = GETDATE();
DECLARE @FullBody NVARCHAR(MAX) = CONCAT(
N'實例: ', @Instance, CHAR(13), CHAR(10),
N'時間: ', CONVERT(NVARCHAR, @Time, 120), CHAR(13), CHAR(10),
N'類型: 服務啟動 (可能為故障轉移/計劃重啟/崩潰恢復)', CHAR(13), CHAR(10),
N'詳情: ', ISNULL(NULLIF(@Body, ''), N'無附加信息'), CHAR(13), CHAR(10),
N'請登錄叢集管理器/可用性群組儀表板核實狀態。'
);
EXEC msdb.dbo.sp_send_dbmail
@profile_name = @ProfileName,
@recipients = @Recipients,
@subject = @Subject,
@body = @FullBody,
@importance = 'HIGH';
END
GO
DBA_Notify_Failover_Restart、類別 Alerts、擁有者 sa、啟用 ✅。Send_Alert、類型 Transact-SQL、命令:
EXEC dbo.usp_Notify_Failover
@Body = N'由 Agent 啟動觸發器自動發送。當前節點: ' + CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS NVARCHAR(128));
高級頁:輸出文件 C:\SQLLogs\Agent_Failover_Notify_$(ESCAPE_SQUOTE(STRTDT))_$(ESCAPE_SQUOTE(STRTTM)).log(便於事後審計)。On_Agent_Start、類型 「SQL Server Agent 啟動時」(關鍵!)。
USE msdb;
GO
DECLARE @jobId BINARY(16);
EXEC dbo.sp_add_job
@job_name = N'DBA_Notify_Failover_Restart',
@enabled = 1,
@category_name = N'[Uncategorized (Local)]',
@owner_login_name = N'sa',
@job_id = @jobId OUTPUT;
EXEC dbo.sp_add_jobstep
@job_id = @jobId,
@step_name = N'Send_Alert',
@subsystem = N'TSQL',
@command = N'EXEC dbo.usp_Notify_Failover @Body = N''Agent 自動通知。節點: '' + CAST(SERVERPROPERTY(''ComputerNamePhysicalNetBIOS'') AS NVARCHAR(128));',
@database_name = N'msdb',
@flags = 4, -- 輸出到文件
@output_file_name = N'C:\SQLLogs\Agent_Failover_Notify_$(ESCAPE_SQUOTE(STRTDT))_$(ESCAPE_SQUOTE(STRTTM)).log';
EXEC dbo.sp_add_jobschedule
@job_id = @jobId,
@name = N'On_Agent_Start',
@freq_type = 64, -- Agent 啟動時
@active_start_time = 0;
EXEC dbo.sp_add_jobserver @job_id = @jobId;
GO
IF EXISTS (SELECT 1 FROM dbo.MaintenanceWindow WHERE GETDATE() BETWEEN StartTime AND EndTime) RETURN; 抑制通知。
-- 作業步驟增強:附帶最近 5 條錯誤日誌
DECLARE @ErrLog TABLE (LogDate DATETIME, ProcessInfo NVARCHAR(50), Text NVARCHAR(MAX));
INSERT INTO @ErrLog EXEC sp_readerrorlog 0, 1, N'Recovery', N'Starting up'; -- 或其他關鍵字
SELECT TOP 5 @Body = COALESCE(@Body + CHAR(13)+CHAR(10), '') + CONVERT(NVARCHAR, LogDate, 120) + N' ' + Text
FROM @ErrLog ORDER BY LogDate DESC;
EXEC dbo.usp_Notify_Failover @Body = @Body;
| 局限 | 補充建議 |
|---|---|
| 僅通知「服務啟動」,無法區分故障轉移/計劃重啟/崩潰 | 結合錯誤日誌關鍵字、叢集事件日誌 (System/Application) 進一步分類 |
| Agent 服務本身故障不發送 | 部署外部心跳監控(Zabbix/Prometheus + Blackbox Exporter 探針 TCP 1433/服務狀態) |
| 郵件通道單點失效 | 配置 Database Mail 多 Profile 故障轉移、或並行發送 Webhook (Teams/Slack/DingTalk) |
| 大規模實例管理分散 | 納入 CMS (Central Management Server) 統一推送作業腳本、集中查看歷史 |
這個「幾分鐘部署、零代碼依賴、原生集成」的方案,雖簡單卻極其有效,能第一時間讓相關方知悉核心數據庫狀態變化,為非集群感知應用的故障恢復爭取寶貴時間窗口。建議納入 DBA 標準化交付清單,每個生產叢集實例必備。