Die Replikation ist eine der ältesten Technologien auf MS SQL Server, die von jedem Datenbankadministrator geliebt wird. Es ist eine großartige und zuverlässige Technologie, um Daten den Benutzern näher zu bringen, insbesondere für verteilte Berichte. Dadurch erhöht sich die Datenbankverfügbarkeit über mehrere SQL Server und Regionen hinweg.
Replikation wurde in SQL 2005 eingeführt. Können Sie glauben, dass es so alt ist? Obwohl regelmäßig neuere verwaltete SQL-Plattformen in der Cloud eingeführt werden, glaube ich, dass die SQL-Replikation hier bleiben wird. Wenn es ein Käfer oder Insekt wäre, würde ich es für eine Kakerlake halten. Es ist schwer zu quetschen!
Wenn Sie zu einer kleinen Gruppe von Administratoren gehören, die noch nie eine Datenbank verwaltet haben, gibt es eine offizielle Microsoft-Dokumentation zu diesem Thema. Beachten Sie jedoch, dass es ziemlich lang und umfassend ist und Ihnen eine Auszeit vom Urlaub oder von geplanten Binge-Watching-TV-Serien raubt. Außerdem bietet Codingsight den Einrichtungs- und Konfigurationsleitfaden für die SQL Server-Datenbankreplikation an.
Aber bevor Sie sich mit den technischen Dingen die Hände schmutzig machen, und ich weiß, dass Sie auch eifrig sind, ist es wichtig, dies zu planen.
Die Replikationsanforderung kann sich in Bezug auf den Standort ändern, wenn Sie auf SQL Servern bereitstellen, die in der Cloud ausgeführt werden. Aber sobald die SQL-Replikation wie eine gut geölte Maschine läuft und Produktionsdaten repliziert, müssen Sie planen, wie Sie sie verwalten.
In diesem Beitrag werde ich Ihnen einige Tipps und T-SQL-Skripte mitteilen, die Sie verwenden können, wenn Sie überprüfen müssen, ob viele SQL Agent-Jobs nach der Replikationskonfiguration erstellt wurden.
Replikationsagenten überwachen
Wenn Sie die SQL-Replikation einrichten und konfigurieren, werden auch eine Reihe eigenständiger Funktionen und SQL-Agent-Jobs erstellt, die als Replikationsagenten bezeichnet werden. Ihr Ziel ist es, Aufgaben im Zusammenhang mit dem Verschieben Ihrer Tabellen, auch Artikel genannt, auszuführen , in der Replikationskonfiguration von publisher an Abonnenten . Sie können Replication Agents von der Befehlszeile und von Anwendungen ausführen, die Replication Management Objects (RMO) verwenden.
SQL Server Replication Agents können über Replication Monitor und SQL Server Management Studio überwacht und verwaltet werden.
Das Hauptanliegen eines Datenbankadministrators/Replikationsadministrators besteht darin, sicherzustellen, dass alle SQL Agents-Replikationsjobs ausgeführt werden. Wenn der Auftrag des Replikationsagenten fehlschlägt, erhält der Abonnent möglicherweise keine Daten. Daher kann die Verteilungsdatenbank aufgrund von angesammelten Zeilen, die nicht in die Abonnentendatenbank verschoben werden, sehr groß werden.
Sie können einen weiteren Agentenjob erstellen, um eine Warnung für einen fehlgeschlagenen Replikations-Agent-Job festzulegen. Es überprüft die Auftragsfehler und sendet eine E-Mail an Ihr dba-Team, wenn es Probleme feststellt.
Nach fehlgeschlagenen Replication Agent-Jobs suchen
Verwenden Sie das folgende Skript:
declare @time time
set @time = dateadd(n,-30,getdate())
declare @date date
set @date = convert(date,getdate())
declare @publisher varchar(100)
set @publisher = @@SERVERNAME
SELECT LEFT(name,50) as [JobName], run_date AS [RunDate], run_time AS [RunTime], LEFT([message],50) AS [Message]
FROM
(select distinct b.name,a.run_date, run_time, message
from msdb..sysjobhistory a inner join msdb..sysjobs b on a.job_id = b.job_id where b.name like 'servername here%' and run_status <> 1 and message like '%error%'
and convert(date,convert(varchar,a.run_date ))= convert(date,getutcdate()) replace(convert(varchar(8),dateadd(n,-30,getutcdate())),':','') ) a
Erstellen Sie eine E-Mail-Benachrichtigung, um über den Auftragsfehler zu informieren
Wenden Sie das folgende Skript an:
exec msdb.dbo.sp_send_dbmail
@profile_name = 'DBA Alerts',
@recipients = 'your dba team email here',
@subject = '[Database name] Replication Jobs Failure',
@query = 'SELECT LEFT(name,50) as [JobName], run_date AS [RunDate], run_time AS [RunTime], LEFT([message],50) AS [Message]
FROM
(select distinct b.name, a.run_date, a.run_time, message
from msdb.dbo.sysjobhistory a inner join msdb.dbo.sysjobs b on a.job_id = b.job_id
where b.name like ''servername here %'' and
convert(date,convert(varchar,a.run_date)) = convert(date,getutcdate()) ) a
',
@attach_query_result_as_file = 0 ;
Überwachen Sie die Tabelle mit replizierten Befehlen
Um die msrepl_commands zu überwachen Tabelle können Sie ein weiteres Skript verwenden, das unten bereitgestellt wird. Beachten Sie, dass diese Tabelle zu groß und zu schnell wachsen sollte. Wenn dies der Fall ist, schlagen die Jobs des Replikations-Agents möglicherweise fehl oder es liegt ein Problem in der Replikationskonfiguration vor.
Das Skript lautet wie folgt:
use distribution
SELECT Getdate() AS CaptureTime, LEFT(Object_name(t.object_id),20) AS TableName, st.row_count
FROM sys.dm_db_partition_stats st WITH (nolock)
INNER JOIN sys.tables t WITH (nolock) ON st.object_id = t.object_id INNER JOIN sys.schemas s WITH (nolock) ON t.schema_id = s.schema_id WHERE index_id < 2 AND Object_name(t.object_id)
IN ('MSsubscriptions', 'MSdistribution_history', 'MSrepl_commands', 'MSrepl_transactions')
ORDER BY st.row_count DESC
Die msrepl_commands Tabellenwachstumstrend gibt Ihnen auch einen Hinweis darauf, wie gesund Ihre Replikationslatenz ist. Es gibt viele Einflussfaktoren. Wenn sich Ihre Umgebung in der Cloud befindet, kann die Regionsauswahl einen großen Beitrag zur Replikationslatenz leisten.
Erstellen Sie einen einfachen Bericht zur Replikation und senden Sie ihn per E-Mail
Sie können das folgende Skript verwenden:
Declare @Publisher sysname, @PublisherDB sysname
-- Set Publisher server and database name
Set @Publisher = 'publication server name';
Set @PublisherDB = 'publishing database name';
-- Refresh replication monitor data
USE [distribution]
Exec sys.sp_replmonitorrefreshjob @iterations = 1;
With MaxXact (ServerName, PublisherDBID, XactSeqNo)
As (Select S.name, DA.publisher_database_id, max(H.xact_seqno) From dbo.MSdistribution_history H with(nolock)
Inner Join dbo.MSdistribution_agents DA with(nolock) On DA.id = H.agent_id
Inner Join master.sys.servers S with(nolock) On S.server_id = DA.subscriber_id
Where DA.publisher_db = @PublisherDB
Group By S.name, DA.publisher_database_id), OldestXact (ServerName, OldestEntryTime)
As (Select MX.ServerName, Min(entry_time)
From dbo.msrepl_transactions T with(nolock)
Inner Join MaxXact MX On MX.XactSeqNo < T.xact_seqno And
MX.PublisherDBID = T.publisher_database_id
Group By MX.ServerName)
Select [Replication Status] = Case MD.status
When 1 Then 'Started'
When 2 Then 'Succeeded'
When 3 Then 'In progress'
When 4 Then 'Idle'
When 5 Then 'Retrying'
When 6 Then 'Failed'
End,
Subscriber = SubString(MD.agent_name, Len(MD.publisher) +
Len(MD.publisher_db) + Len(MD.publication) + 4,
Charindex('-', MD.agent_name,
Len(MD.publisher) + Len(MD.publisher_db) +
Len(MD.publication) + 5) -
(Len(MD.publisher) +
Len(MD.publisher_db) + Len(MD.publication) + 4)),
[Subscriber DB] = A.subscriber_db,
[Publisher DB] = MD.publisher_db,
Publisher = MD.publisher,
[Current Latency (sec)] = MD.cur_latency,
[Current Latency (hh:mm:ss)] = Right('00' + Cast(MD.cur_latency/3600 As varchar), 2) +
':' + Right('00' +
Cast((MD.cur_latency%3600)/60 As varchar), 2) +
':' + Right('00' +
Cast(MD.cur_latency%60 As varchar), 2),
[Latency Threshold (min)] = Cast(T.value As Int),
[Agent Last Stopped (sec)] = DateDiff(hour, agentstoptime, getdate()) - 1,
[Agent Last Sync] = MD.last_distsync,
[Last Entry TimeStamp] = OX.OldestEntryTime
From dbo.MSreplication_monitordata MD with(nolock)
Inner Join dbo.MSdistribution_agents A with(nolock) On A.id = MD.agent_id Inner Join dbo.MSpublicationthresholds T with(nolock) On T.publication_id = MD.publication_id And T.metric_id = 2 -- Latency
Inner Join OldestXact OX On OX.ServerName = SubString(MD.agent_name, Len(MD.publisher) + Len(MD.publisher_db) +
Len(MD.publication) + 4,
Charindex('-', MD.agent_name,
Len(MD.publisher) + Len(MD.publisher_db) +
Len(MD.publication) + 5) -
(Len(MD.publisher) +
Len(MD.publisher_db) + Len(MD.publication) + 4))
Where MD.publisher = @Publisher
And MD.publisher_db = @PublisherDB
And MD.publication_type = 0 -- 0 = Transactional publication And MD.agent_type = 3; -- 3 = distribution agent
IF (@@ROWCOUNT > 500)
BEGIN
-- send alerts here.. 500 rows of undistributed transactions , should be higher. run this on remote distributor
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DBA Alert',
@recipients = 'your dba team email here',
@body = 'This is replication latency alert. Check undistributed transactions query.',
@subject = 'Replication Latency Alert' ;
PRINT 'Alert here!' --since email is not yet working
END
Befragen Sie die Artikelliste und überprüfen Sie die Gesundheit der Abonnenten
Wenn Sie an einer Transaktionsreplikation arbeiten, sind diese Vorgänge äußerst wichtig. Hier ist ein Skript:
SELECT DISTINCT LEFT(srv.srvname,50) AS publication_server
, LEFT(a.publisher_db, 50) AS publisher_db
, LEFT(p.publication,25) AS publication_name
, LEFT(a.article, 50) AS [article]
, LEFT(a.destination_object,50) AS destination_object
, LEFT(ss.srvname,25) AS subscription_server
, LEFT(s.subscriber_db,25) AS subscriber_db
, LEFT(da.name,50) AS distribution_agent_job_name
FROM distribution..MSArticles a
JOIN distribution..MSpublications p ON a.publication_id = p.publication_id JOIN distribution..MSsubscriptions s ON p.publication_id = s.publication_id JOIN master..sysservers ss ON s.subscriber_id = ss.srvid
JOIN master..sysservers srv ON srv.srvid = p.publisher_id
JOIN distribution..MSdistribution_agents da ON da.publisher_id = p.publisher_id AND da.subscriber_id = s.subscriber_id
ORDER BY 1,2,3
Erstellen Sie eine Berichtszusammenfassung für das DBA-Team
Um alle Replikationsstatistiken und gelieferten und nicht gelieferten Befehle zu kombinieren, können Sie eine Tabelle in der Verteilungsdatenbank erstellen, die alle Replikationsdetails enthält.
Aus dieser Tabelle können Sie eine Berichtszusammenfassung erstellen, um sie an das DBA-Team zu verteilen . Diese Tabelle kann jeden Tag als Teil der täglichen Zustandsprüfung der Replikation aktualisiert werden, abgesehen von der standardmäßigen morgendlichen Zustandsprüfung des Datenbankadministrators.
USE [distribution]
IF OBJECT_ID('Tempdb.dbo.#ReplStats') IS NOT NULL
DROP TABLE #ReplStats
CREATE TABLE [dbo].[#ReplStats] (
[DistributionAgentName] [nvarchar](100) NOT NULL
,[DistributionAgentStartTime] [datetime] NOT NULL
,[DistributionAgentRunningDurationInSeconds] [int] NOT NULL ,[IsAgentRunning] [bit] NULL
,[ReplicationStatus] [varchar](14) NULL
,[LastSynchronized] [datetime] NOT NULL
,[Comments] [nvarchar](max) NOT NULL
,[Publisher] [sysname] NOT NULL
,[PublicationName] [sysname] NOT NULL
,[PublisherDB] [sysname] NOT NULL
,[Subscriber] [nvarchar](128) NULL
,[SubscriberDB] [sysname] NULL
,[SubscriptionType] [varchar](64) NULL
,[DistributionDB] [sysname] NULL
,[Article] [sysname] NOT NULL
,[UndelivCmdsInDistDB] [int] NULL
,[DelivCmdsInDistDB] [int] NULL
,[CurrentSessionDeliveryRate] [float] NOT NULL
,[CurrentSessionDeliveryLatency] [int] NOT NULL
,[TotalTransactionsDeliveredInCurrentSession] [int] NOT NULL
,[TotalCommandsDeliveredInCurrentSession] [int] NOT NULL ,[AverageCommandsDeliveredInCurrentSession] [int] NOT NULL ,[DeliveryRate] [float] NOT NULL
,[DeliveryLatency] [int] NOT NULL
,[TotalCommandsDeliveredSinceSubscriptionSetup] [int] NOT NULL ,[SequenceNumber] [varbinary](16) NULL
,[LastDistributerSync] [datetime] NULL
,[Retention] [int] NULL
,[WorstLatency] [int] NULL
,[BestLatency] [int] NULL
,[AverageLatency] [int] NULL
,[CurrentLatency] [int] NULL
) ON [PRIMARY]
INSERT INTO #ReplStats
SELECT da.[name] AS [DistributionAgentName]
,dh.[start_time] AS [DistributionAgentStartTime]
,dh.[duration] AS [DistributionAgentRunningDurationInSeconds] ,md.[isagentrunningnow] AS [IsAgentRunning]
,CASE md.[status]
WHEN 1
THEN '1 - Started'
WHEN 2
THEN '2 - Succeeded'
WHEN 3
THEN '3 - InProgress'
WHEN 4
THEN '4 - Idle'
WHEN 5
THEN '5 - Retrying'
WHEN 6
THEN '6 - Failed'
END AS [ReplicationStatus]
,dh.[time] AS [LastSynchronized]
,dh.[comments] AS [Comments]
,md.[publisher] AS [Publisher]
,da.[publication] AS [PublicationName]
,da.[publisher_db] AS [PublisherDB]
,CASE
WHEN da.[anonymous_subid] IS NOT NULL
THEN UPPER(da.[subscriber_name])
ELSE UPPER(s.[name])
END AS [Subscriber]
,da.[subscriber_db] AS [SubscriberDB]
,CASE da.[subscription_type]
WHEN '0'
THEN 'Push'
WHEN '1'
THEN 'Pull'
WHEN '2'
THEN 'Anonymous'
ELSE CAST(da.[subscription_type] AS [varchar](64))
END AS [SubscriptionType]
,md.[distdb] AS [DistributionDB]
,ma.[article] AS [Article]
,ds.[UndelivCmdsInDistDB]
,ds.[DelivCmdsInDistDB]
,dh.[current_delivery_rate] AS [CurrentSessionDeliveryRate] ,dh.[current_delivery_latency] AS [CurrentSessionDeliveryLatency] ,dh.[delivered_transactions] AS
[TotalTransactionsDeliveredInCurrentSession]
,dh.[delivered_commands] AS [TotalCommandsDeliveredInCurrentSession] ,dh.[average_commands] AS [AverageCommandsDeliveredInCurrentSession] ,dh.[delivery_rate] AS [DeliveryRate]
,dh.[delivery_latency] AS [DeliveryLatency]
,dh.[total_delivered_commands] AS
[TotalCommandsDeliveredSinceSubscriptionSetup]
,dh.[xact_seqno] AS [SequenceNumber]
,md.[last_distsync] AS [LastDistributerSync]
,md.[retention] AS [Retention]
,md.[worst_latency] AS [WorstLatency]
,md.[best_latency] AS [BestLatency]
,md.[avg_latency] AS [AverageLatency]
,md.[cur_latency] AS [CurrentLatency]
FROM [distribution]..[MSdistribution_status] ds
INNER JOIN [distribution]..[MSdistribution_agents] da ON da.[id] = ds.[agent_id]
INNER JOIN [distribution]..[MSArticles] ma ON ma.publisher_id = da.publisher_id
AND ma.[article_id] = ds.[article_id]
INNER JOIN [distribution]..[MSreplication_monitordata] md ON [md].[job_id] = da.[job_id]
INNER JOIN [distribution]..[MSdistribution_history] dh ON [dh].[agent_id] = md.[agent_id]
AND md.[agent_type] = 3
INNER JOIN [master].[sys].[servers] s ON s.[server_id] = da.[subscriber_id]
--Created WHEN your publication has the immediate_sync property set to true. This property dictates
--whether snapshot is available all the time for new subscriptions to be initialized.
--This affects the cleanup behavior of transactional replication. If this property is set to true,
--the transactions will be retained for max retention period instead of it getting cleaned up
--as soon as all the subscriptions got the change.
WHERE da.[subscriber_db] <> 'virtual'
AND da.[anonymous_subid] IS NULL
AND dh.[start_time] = (
SELECT TOP 1 start_time
FROM [distribution]..[MSdistribution_history] a
INNER JOIN [distribution]..[MSdistribution_agents] b ON a.[agent_id] = b.[id]
AND b.[subscriber_db] <> 'virtual'
WHERE [runstatus] <> 1
ORDER BY [start_time] DESC
)
AND dh.[runstatus] <> 1
SELECT 'Transactional Replication Summary' AS [Comments];
SELECT [DistributionAgentName]
,[DistributionAgentStartTime]
,[DistributionAgentRunningDurationInSeconds]
,[IsAgentRunning]
,[ReplicationStatus]
,[LastSynchronized]
,[Comments]
,[Publisher]
,[PublicationName]
,[PublisherDB]
,[Subscriber]
,[SubscriberDB]
,[SubscriptionType]
,[DistributionDB]
,SUM([UndelivCmdsInDistDB]) AS [UndelivCmdsInDistDB]
,SUM([DelivCmdsInDistDB]) AS [DelivCmdsInDistDB]
,[CurrentSessionDeliveryRate]
,[CurrentSessionDeliveryLatency]
,[TotalTransactionsDeliveredInCurrentSession]
,[TotalCommandsDeliveredInCurrentSession]
,[AverageCommandsDeliveredInCurrentSession]
,[DeliveryRate]
,[DeliveryLatency]
,[TotalCommandsDeliveredSinceSubscriptionSetup]
,[SequenceNumber]
,[LastDistributerSync]
,[Retention]
,[WorstLatency]
,[BestLatency]
,[AverageLatency]
,[CurrentLatency]
FROM #ReplStats
GROUP BY [DistributionAgentName]
,[DistributionAgentStartTime]
,[DistributionAgentRunningDurationInSeconds]
,[IsAgentRunning]
,[ReplicationStatus]
,[LastSynchronized]
,[Comments]
,[Publisher]
,[PublicationName]
,[PublisherDB]
,[Subscriber]
,[SubscriberDB]
,[SubscriptionType]
,[DistributionDB]
,[CurrentSessionDeliveryRate]
,[CurrentSessionDeliveryLatency]
,[TotalTransactionsDeliveredInCurrentSession]
,[TotalCommandsDeliveredInCurrentSession]
,[AverageCommandsDeliveredInCurrentSession]
,[DeliveryRate]
,[DeliveryLatency]
,[TotalCommandsDeliveredSinceSubscriptionSetup]
,[SequenceNumber]
,[LastDistributerSync]
,[Retention]
,[WorstLatency]
,[BestLatency]
,[AverageLatency]
,[CurrentLatency]
SELECT 'Transactional Replication Summary Details' AS [Comments];
SELECT [Publisher]
,[PublicationName]
,[PublisherDB]
,[Article]
,[Subscriber]
,[SubscriberDB]
,[SubscriptionType]
,[DistributionDB]
,SUM([UndelivCmdsInDistDB]) AS [UndelivCmdsInDistDB] ,SUM([DelivCmdsInDistDB]) AS [DelivCmdsInDistDB]
FROM #ReplStats
GROUP BY [Publisher]
,[PublicationName]
,[PublisherDB]
,[Article]
,[Subscriber]
,[SubscriberDB]
,[SubscriptionType]
,[DistributionDB]
Zusammenfassung
Ich hoffe, dass diese wenigen oben bereitgestellten T-SQL-Skripte Ihnen bei der Überwachung Ihrer Replikationsagenten helfen werden. Ich empfehle Ihnen dringend, sie genau zu überwachen. Andernfalls können sich Benutzer auf der Seite des Abonnenten endlos darüber beschweren, dass sie keine (nahezu) Echtzeitdaten haben.
In den kommenden Artikeln werde ich mich eingehender mit der SQL-Technologie zur Replikation von Daten in jeden Teil der Welt befassen. Viel Spaß beim Überwachen!