SQLSERVER監控復制并使用數據庫郵件功能發告警郵件
正題
上個月月底的時候因為要搬遷機房,需要將一個數據信息數據庫先搬到我們的機房,然后將客戶的數據庫
從原來的機房A搬到機房B,原來我們的數據信息庫(DataInfo)是放在機房A的,但是為了以后方便和防止信息泄露
就放到我們的托管機房,這里叫機房C
在搬遷機房的時候,盡量減少宕機時間,數據不能丟,搬遷機房真是一門學問。。。
雖然這麼忙,但我還是把寫文章的時間騰出來,把干貨分享給大家o(∩_∩)o
因為很多系統都在讀寫機房A的數據信息庫(DataInfo),我在上個月底的時候用備份文件初始化的方式搭建好復制把機房A的
機房A的數據信息庫(DataInfo)新插入的數據實時復制到機房C,先讓一部分系統能讀取機房C的數據信息庫(DataInfo),
等以后搬遷完所有系統之后再統一全部改連接地址
當然這篇文章不是講我這次的搬遷過程,在搭建好復制之后,由于我沒有設置訂閱庫的登錄用戶的權限為只讀,導致前幾天開發那邊
同時把新數據插入到訂閱庫,導致復制失敗(主鍵重復),分發命令積壓(大概26w+條命令未分發),然后一大堆后續工作。。。。。。
復制的坑其實挺多的,因為我們不可能24小時用肉眼盯著復制監視器,所以我們需要一些監控手段,
當遇到復制出錯的時候可以盡快知道然后進行修復
監控考慮的條件:
(1)單個點監控、多個點監控
(2)購買、自己開發
(3)比較實時、不是很實時
(4)數據庫服務器是否負載過高
我這里只考慮最簡單的一種:單個點的,不需要很實時,負載不高,如果服務器負載過高有可能連郵件也發不出了
然后就考慮到使用SQLSERVER自帶的數據庫郵件來發告警郵件
當然,如果需要同時滿足實時、多個點監控、成本足夠可以考慮購買成熟的解決方案
又或者
自己公司開發監控程序,支持短信告警更加及時
需求
(1)當遇到復制出錯的時候發郵件到我的郵箱
(2)每天間隔一定時間發郵件告訴我當前復制的情況
測試環境:Windows7 64位 、發布庫SQL2005 SP4 、訂閱庫SQL2012 SP1、發布庫和訂閱庫都在我的筆記本上
復制所用登錄用戶:[ReplicationUser]
在進行實驗之前,需要測試一下smtp.163.com,端口為25,這個地址是否可以訪問。如果不通有可能是你機器防火墻的問題
還有可能需要檢查殺毒軟件有沒有屏蔽了端口,否則會發送郵件失敗
呈上完整腳本
--測試復制郵件告警 USE [sss] GO --建立測試表 發布表一定要有主鍵 CREATE TABLE Repl_Test ( ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY , TestNAME VARCHAR(100) NULL , CreatDate DATETIME NULL ) /*********************************************************************/ --在發布庫和訂閱庫建立一個同名的登錄用戶,這兩個登錄用戶都對發布庫有訪問權限 /*********************************************************************/ --設置指定數據庫的復制選項 --存儲過程說明http://msdn.microsoft.com/zh-tw/library/ms188769.aspx use [sss] exec sp_replicationdboption @dbname = N'sss', @optname = N'publish', @value = N'true' GO /*********************************************************************/ -- 添加事務發布 --存儲過程說明http://www.yesky.com/imagesnew/software/tsql/ts_sp_repl_4s32.htm use [sss] exec sp_addpublication @publication = N'testpub-sss', @description = N'來自發布服務器“JOE”的數據庫“sss”的事務發布。', @sync_method = N'concurrent', @retention = 0, --訂閱是否過期,0為永不過期 @allow_push = N'true', --推送訂閱 @allow_pull = N'true', --請求訂閱為 @allow_anonymous = N'false', --false則表示不允許在該發布上使用匿名訂閱 @repl_freq = N'continuous', --是復制頻率的類型。默認設置為 continuous。如果是 continuous,則表示發布服務器提供所有基于日志的事務輸出。如果是 Snapshot,則表示發布服務器只生成已調度同步事件 @status = N'active', --指定發布數據是否可用 @independent_agent = N'true', --指定是否有用于發布的單獨的分發代理程序 @immediate_sync = N'false', --指定是否每次快照代理程序運行時都創建發布的同步文件 @replicate_ddl = 1, --復制DDL語句 @allow_initialize_from_backup = N'true' --是否允許備份初始化 GO /*********************************************************************/ --添加快照代理 --存儲過程說明http://www.yesky.com/imagesnew/software/tsql/ts_sp_repl_7ecj.htm exec sp_addpublication_snapshot @publication = N'testpub-sss', @frequency_type = 1, @frequency_interval = 0, @frequency_relative_interval = 0, @frequency_recurrence_factor = 0, @frequency_subday = 0, @frequency_subday_interval = 0, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 0, @active_end_date = 0, @job_login = null, @job_password = null, @publisher_security_mode = 1 /*********************************************************************/ -- 添加發布項目 --存儲過程說明http://www.yesky.com/imagesnew/software/tsql/ts_sp_repl_27s5.htm use [sss] exec sp_addarticle @publication = N'testpub-sss', @article = N'Repl_Test', @source_owner = N'dbo', @source_object = N'Repl_Test', --要發布的表 @type = N'logbased', @pre_creation_cmd = N'drop', --當應用該項目的快照時,指定系統在訂閱服務器上檢測到同名的現有對象時所應采取的操作 @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', --自增列范圍管理選項,manual為手動管理 @destination_table = N'Repl_Test', --是目的(訂閱)表 @destination_owner = N'dbo', @ins_cmd = N'CALL sp_MSins_dboRepl_Test', --是復制項目的插入時使用的復制命令類型 @del_cmd = N'CALL sp_MSdel_dboRepl_Test', --是復制項目的刪除時使用的復制命令類型 @upd_cmd = N'SCALL sp_MSupd_dboRepl_Test' --是復制項目的更新時使用的復制命令類型 GO /*********************************************************************/ --完整備份發布庫 BACKUP DATABASE [sss] TO DISK ='C:\SSS_FULLBACKUP2014-4-13.BAK' /*********************************************************************/ --在訂閱庫上還原數據庫 USE [master] RESTORE DATABASE [sss] FROM DISK = N'D:\sss_fullbackup2014-4-6.bak' WITH FILE = 1, MOVE N'sss' TO N'D:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\sss.mdf', MOVE N'sss_log' TO N'D:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\sss_log.ldf', NOUNLOAD, REPLACE, STATS = 5 GO /*********************************************************************/ --在發布庫新建訂閱 使用推送訂閱 use [sss] exec sp_addsubscription @publication = N'testpub-sss', @subscriber = N'JOE\SQL2012', @destination_db = N'sss', @subscription_type = N'Push', @sync_type = N'initialize with backup', @article = N'all', @update_mode = N'read only', @subscriber_type = 0, @backupdevicetype='disk', @backupdevicename='C:\SSS_FULLBACKUP2014-4-13.bak'--最后一次備份的備份文件(發布服務器上的存放位置) /*********************************************************************/ --添加分發代理 exec sp_addpushsubscription_agent @publication = N'testpub-sss', @subscriber = N'JOE\SQL2012', @subscriber_db = N'sss', @job_login = null, @job_password = null, @subscriber_security_mode = 0, @subscriber_login = N'ReplicationUser', @subscriber_password = N'ReplicationForUser', @frequency_type = 64, @frequency_interval = 0, @frequency_relative_interval = 0, @frequency_recurrence_factor = 0, @frequency_subday = 0, @frequency_subday_interval = 0, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 20140408, @active_end_date = 99991231, @enabled_for_syncmgr = N'False', @dts_package_location = N'Distributor' GO /*********************************************************************/ --腳本創建數據庫郵件 --開啟數據庫郵件 EXEC sp_configure 'show advanced options',1 RECONFIGURE WITH OVERRIDE GO EXEC sp_configure 'database mail xps',1 RECONFIGURE WITH OVERRIDE /*********************************************************************/ --創建郵件帳戶信息 EXEC msdb..sysmail_add_account_sp @ACCOUNT_NAME ='ReplicationErrorMailLog',--郵件帳戶名稱 @EMAIL_ADDRESS ='hiAT163.com',--發件人郵件地址 @DISPLAY_NAME ='系統管理員',--發件人姓名 @REPLYTO_ADDRESS =NULL, @DESCRIPTION = NULL, @MAILSERVER_NAME = 'SMTP.163.COM',--郵件服務器地址 @MAILSERVER_TYPE = 'SMTP',--郵件協議 @PORT =25,--郵件服務器端口 @USERNAME = 'hiAT163.com',--用戶名 @PASSWORD = 'xxx',--密碼 @USE_DEFAULT_CREDENTIALS =0, @ENABLE_SSL =0, @ACCOUNT_ID = NULL GO /*********************************************************************/ --數據庫配置文件 IF EXISTS(SELECT name FROM msdb..sysmail_profile WHERE name=N'ReplicationErrorProfileLog') BEGIN EXEC msdb..sysmail_delete_profile_sp @profile_name='ReplicationErrorProfileLog' END EXEC msdb..sysmail_add_profile_sp @profile_name = 'ReplicationErrorProfileLog',--profile名稱 @description = '數據庫郵件配置文件',--profile描述 @profile_id = null GO /*********************************************************************/ --用戶和郵件配置文件相關聯 EXEC msdb..sysmail_add_profileaccount_sp @profile_name = 'ReplicationErrorProfileLog',--profile名稱 @account_name = 'ReplicationErrorMailLog',--account名稱 @sequence_number = 1--account 在profile 中順序 GO /*********************************************************************/ --發送簡單文本的郵件 /*********************************************************************/ --創建鏈接服務器 --要開啟分發服務器上的Distributed Transaction Coordinator(MSDTC服務) USE [master] GO EXEC master.dbo.sp_addlinkedserver @server = N'JOE_DIST', @srvproduct=N'sqlserver', @provider=N'SQLOLEDB', @datasrc=N'JOE' GO EXEC master.dbo.sp_serveroption @server=N'JOE_DIST', @optname=N'rpc', @optvalue=N'true' GO EXEC master.dbo.sp_serveroption @server=N'JOE_DIST', @optname=N'rpc out', @optvalue=N'true' GO USE [master] GO EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N'JOE_DIST', --★Do @locallogin = NULL , @useself = N'False', @rmtuser = N'sa', --要求是對distribution有db_owner權限的 實際應用時最好不要用sa --★Do @rmtpassword = N'testxxx' --★Do GO /*********************************************************************/ ----發送郵件 ,這個步驟只是測試,檢查編寫的動態SQL是否正確 USE [distribution] GO DECLARE @SQL NVARCHAR(MAX) DECLARE @replcountersSQL NVARCHAR(MAX) DECLARE @replmonitorsubscriptionpendingcmdsSQL NVARCHAR(MAX) CREATE TABLE #replcounters ( [database] NVARCHAR(200) , [replicated_transactions] BIGINT , [replication_rate_trans_sec] DECIMAL(18, 2) , [replication_latency] DECIMAL(18, 2) , [replbeginlsn] BINARY(1000) , [replnextlsn] BINARY(1000) ) CREATE TABLE #replmonitorsubscriptionpendingcmds ( [pendingcmdcount] BIGINT , [estimatedprocesstime] BIGINT ) INSERT [#replmonitorsubscriptionpendingcmds] EXEC [JOE_DIST].distribution.dbo.SP_replmonitorsubscriptionpendingcmds 'JOE', --★Do 'SSS', 'testpub-sss', 'JOE\SQL2012', 'SSS', 0 --★Do INSERT [#replcounters] EXEC [distribution].[dbo].sp_replcounters SELECT * FROM [#replcounters] SELECT * FROM [#replmonitorsubscriptionpendingcmds] SET @replcountersSQL = N'<H3>數據庫滯后時間、吞吐量和事務計數的復制統計信息</H3>'+ '<table border="1">' + N'<tr><th>[database]</th> <th>[replicated_transactions]</th> <th>[replication_rate_trans_sec]</th> <th>[replication_latency]</th> <th>[replbeginlsn]</th> <th>[replnextlsn]</th> </tr>' + CAST(( SELECT [database] AS 'td' , '', [replicated_transactions] AS 'td','', [replication_rate_trans_sec] AS 'td','', [replication_latency] AS 'td','', CAST([replbeginlsn] AS INT) AS 'td','', CAST([replnextlsn] AS INT) AS 'td' FROM [#replcounters] FOR XML PATH('tr') , ELEMENTS-- TYPE ) AS NVARCHAR(MAX)) + N'</table>'; SET @replmonitorsubscriptionpendingcmdsSQL = N'<H3>事務發布的訂閱的等待命令數以及處理這些命令的粗略估計時間</H3>'+ '<table border="1">' + N'<tr><th>[pendingcmdcount]</th> <th>[estimatedprocesstime]</th> </tr>' + CAST(( SELECT [pendingcmdcount] AS 'td' , '', [estimatedprocesstime] AS 'td','' FROM [#replmonitorsubscriptionpendingcmds] FOR XML PATH('tr') , ELEMENTS-- TYPE ) AS NVARCHAR(MAX)) + N'</table>'; SET @SQL=@replcountersSQL+'</br>'+@replmonitorsubscriptionpendingcmdsSQL EXEC [msdb].[dbo].[sp_send_dbmail] @profile_name = 'ReplicationErrorProfileLog' , --★Do @recipients = 'xxxx@163.com', -- varchar(max) --收件人 --★Do @subject = N'數據庫復制的相關信息', -- nvarchar(255) 標題 --★Do @body_format = 'HTML', -- varchar(20) 正文格式可選值:text html @body = @SQL DROP TABLE [#replcounters] DROP TABLE [#replmonitorsubscriptionpendingcmds] /*********************************************************************/ --創建作業 作業命名規則:數據庫名_ReplicationInfo DECLARE @job_name SYSNAME SET @job_name='SSS_ReplicationInfo' --★Do EXEC msdb.dbo.sp_add_job @job_name=@job_name, @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'發送復制數據庫情況作業', @category_name=N'REPL-Checkup', @owner_login_name=N'sa' /*********************************************************************/ --添加作業步驟 DECLARE @job_name SYSNAME DECLARE @DBNAME NVARCHAR(100) DECLARE @SQL NVARCHAR(MAX) SET @DBNAME='distribution' SET @job_name='SSS_ReplicationInfo' --★Do SET @SQL = N'USE [distribution] GO DECLARE @SQL NVARCHAR(MAX) DECLARE @replcountersSQL NVARCHAR(MAX) DECLARE @replmonitorsubscriptionpendingcmdsSQL NVARCHAR(MAX) CREATE TABLE #replcounters ( [database] NVARCHAR(200) , [replicated_transactions] BIGINT , [replication_rate_trans_sec] DECIMAL(18, 2) , [replication_latency] DECIMAL(18, 2) , [replbeginlsn] BINARY(1000) , [replnextlsn] BINARY(1000) ) CREATE TABLE #replmonitorsubscriptionpendingcmds ( [pendingcmdcount] BIGINT , [estimatedprocesstime] BIGINT ) INSERT [#replmonitorsubscriptionpendingcmds] EXEC [JOE_DIST].distribution.dbo.SP_replmonitorsubscriptionpendingcmds ''JOE'', --★Do ''SSS'', ''testpub-sss'', ''JOE\SQL2012'', ''SSS'', 0 --★Do INSERT [#replcounters] EXEC [distribution].[dbo].sp_replcounters SELECT * FROM [#replcounters] SELECT * FROM [#replmonitorsubscriptionpendingcmds] SET @replcountersSQL = N''<H3>數據庫滯后時間、吞吐量和事務計數的復制統計信息</H3>''+ ''<table border="1">'' + N''<tr><th>[database]</th> <th>[replicated_transactions]</th> <th>[replication_rate_trans_sec]</th> <th>[replication_latency]</th> <th>[replbeginlsn]</th> <th>[replnextlsn]</th> </tr>'' + CAST(( SELECT [database] AS ''td'' , '''', [replicated_transactions] AS ''td'','''', [replication_rate_trans_sec] AS ''td'','''', [replication_latency] AS ''td'','''', CAST([replbeginlsn] AS INT) AS ''td'','''', CAST([replnextlsn] AS INT) AS ''td'' FROM [#replcounters] FOR XML PATH(''tr'') , ELEMENTS-- TYPE ) AS NVARCHAR(MAX)) + N''</table>''; SET @replmonitorsubscriptionpendingcmdsSQL = N''<H3>事務發布的訂閱的等待命令數以及處理這些命令的粗略估計時間</H3>''+ ''<table border="1">'' + N''<tr><th>[pendingcmdcount]</th> <th>[estimatedprocesstime]</th> </tr>'' + CAST(( SELECT [pendingcmdcount] AS ''td'' , '''', [estimatedprocesstime] AS ''td'','''' FROM [#replmonitorsubscriptionpendingcmds] FOR XML PATH(''tr'') , ELEMENTS-- TYPE ) AS NVARCHAR(MAX)) + N''</table>''; SET @SQL=@replcountersSQL+''</br>''+@replmonitorsubscriptionpendingcmdsSQL EXEC [msdb].[dbo].[sp_send_dbmail] @profile_name = ''ReplicationErrorProfileLog'' , @recipients = ''xxx@163.com'', -- varchar(max) --收件人 --★Do @subject = N''數據庫復制的相關信息'', -- nvarchar(255) 標題 --★Do @body_format = ''HTML'', -- varchar(20) 正文格式可選值:text html @body = @SQL DROP TABLE [#replcounters] DROP TABLE [#replmonitorsubscriptionpendingcmds] ' EXEC msdb.dbo.sp_add_jobstep @job_name = @job_name, @step_name = N'SendMail', @step_id = 1, @cmdexec_success_code = 0, @on_success_action = 3, @on_success_step_id = 0, @on_fail_action = 2, @on_fail_step_id = 0, @retry_attempts = 0, @retry_interval = 0, @os_run_priority = 0, @subsystem = N'TSQL', @command = @SQL, @database_name = @DBNAME, @flags = 0 /*********************************************************************/ --創建作業的調度計劃 每天每隔6個小時查看一次 DECLARE @job_name SYSNAME DECLARE @Time VARCHAR(100) DECLARE @Date DATETIME --修改作業的執行時間 SET @Date = '2014-01-08 00:20:00.000' SET @Time = REPLACE(CONVERT(VARCHAR, @Date, 8 ),':','') SET @job_name='SSS_ReplicationInfo' --★Do --修改作業的執行時間 SET @Time = REPLACE(CONVERT(VARCHAR, @Date, 8 ),':','') EXEC msdb.dbo.sp_add_jobschedule @job_name = @job_name, @name=N'Plan', @enabled=1, @freq_type=4, @freq_interval=1, @freq_subday_type=8, @freq_subday_interval=6, @freq_relative_interval=0, @freq_recurrence_factor=1, @active_start_date=20140414, @active_end_date=99991231, @active_start_time=@Time, @active_end_time=235959 EXEC msdb.dbo.sp_add_jobserver @job_name = @job_name, @server_name = N'(local)' /*********************************************************************/ --創建對于[distribution].[dbo].[MSrepl_errors]表的insert觸發器,當有錯誤的時候就發郵件 USE [distribution] GO IF ( OBJECT_ID('tgr_MSrepl_errors', 'tr') IS NOT NULL ) DROP TRIGGER tgr_MSrepl_errors GO CREATE TRIGGER tgr_MSrepl_errors ON [distribution].[dbo].[MSrepl_errors] FOR INSERT --插入觸發 AS
begin DECLARE @SQL NVARCHAR(MAX) SET @SQL = N'<H3>數據庫復制出錯信息</H3>' + '<table border="1">' + N'<tr><th>[xact_seqno]</th> <th>[id]</th> <th>[time]</th> <th>[source_name]</th> <th>[error_code]</th> <th>[session_id]</th> </tr>' + CAST(( SELECT e.[xact_seqno] AS 'td' , '' , e.[id] AS 'td' , '' , e.[time] AS 'td' , '' , e.[source_name] AS 'td' , '' , CAST(e.[error_code] AS NVARCHAR(200)) AS 'td' , '' , CAST(e.[session_id] AS NVARCHAR(200)) AS 'td' , '' FROM dbo.MSdistribution_history h JOIN inserted e ON h.error_id = e.id WHERE comments NOT LIKE '%transaction%'--失敗的代理 ORDER BY id DESC FOR XML PATH('tr') , ELEMENTS-- TYPE ) AS NVARCHAR(MAX)) + N'</table>'; EXEC [msdb].[dbo].[sp_send_dbmail] @profile_name = 'ReplicationErrorProfileLog', @recipients = 'xxxx@163.com', -- varchar(max) --收件人 @subject = N'數據庫復制出錯信息', -- nvarchar(255) 標題 @body_format = 'HTML', -- varchar(20) 正文格式可選值:text html @body = @SQL
end
GO
測試結果
手動啟動作業,就可以看到郵件會自動發到我的163郵箱
復制報錯的時候也會發郵件
我把復制用戶的權限去掉,馬上就會報錯
SQLSERVER會有一個重試時間,除非你馬上停止同步,否則SQLSERVER會不斷重試,然后不斷發郵件到你的郵箱提醒你~
把權限勾上后,沒有報錯了,也沒有再發郵件了
分發代理默認是每隔一分鐘重試4次
你會看到每隔一分鐘會收到4封郵件,其中有一封郵件是空的
而且大家可以看一下[MSrepl_errors]表,每分鐘會插入三條記錄到[MSrepl_errors]表這些都是重試記錄
USE [distribution] GO SELECT * FROM [distribution].[dbo].[MSrepl_errors] ORDER BY [time]
暫時還不清楚可以在哪里修改每分鐘的重試次數,還有為什么4封郵件中有一封是空的~
原理
(1)對[distribution].[dbo].[MSrepl_errors]表創建了insert觸發器,當有錯誤的時候,SQLSERVER會向這個表插入錯誤記錄
(2)利用job獲取下面的兩個存儲過程的結果監視復制發送郵件,這兩個存儲過程都在分發數據庫里
sp_replcounters --為每個發布數據庫返回有關滯后時間、吞吐量和事務計數的復制統計信息。 此存儲過程在發布服務器的任何數據庫中執行。
sp_replmonitorsubscriptionpendingcmds -- 返回有關對事務發布的訂閱的等待命令數以及處理這些命令的粗略估計時間的信息。
此存儲過程針對每個返回的訂閱返回一行。 在分發服務器的分發數據庫上執行此存儲過程,用于監視復制。
感謝群里面的朋友的幫助:何文通、高文佳、菠蘿
相關文章
Replication的犄角旮旯(四)--關于事務復制的監控
如有不對的地方,歡迎大家拍磚o(∩_∩)o
2015-11-13補充
更改郵件附件大小
EXEC msdb.dbo.sysmail_configure_sp 'MaxFileSize', 100000000
http://blog.163.com/yzc_5001/blog/static/2061963420083278856394/
文章列表