Replication là một trong những công nghệ lâu đời nhất trên MS SQL Server, được mọi quản trị viên cơ sở dữ liệu yêu thích. Đây là một công nghệ tuyệt vời và đáng tin cậy để đưa dữ liệu đến gần hơn với người dùng, đặc biệt là đối với báo cáo phân tán. Nhờ nó, tính khả dụng của cơ sở dữ liệu tăng trên nhiều Máy chủ SQL và các khu vực.
Bản sao đã được giới thiệu trong SQL 2005. Bạn có thể tin rằng nó cũ như vậy không? Mặc dù các nền tảng SQL được quản lý mới hơn trên đám mây được giới thiệu thường xuyên, tôi tin rằng bản sao SQL sẽ vẫn ở đây. Nếu đó là một con bọ hoặc côn trùng, tôi sẽ nghĩ nó giống như một con gián. Thật khó để đánh bóng!
Nếu bạn là một trong những người thuộc nhóm ít quản trị viên chưa từng quản lý cơ sở dữ liệu, thì có tài liệu chính thức của Microsoft về chủ đề này. Tuy nhiên, hãy lưu ý rằng nó khá dài, toàn diện và sẽ khiến bạn mất một khoảng thời gian sau kỳ nghỉ hoặc xem phim truyền hình say sưa theo kế hoạch. Ngoài ra, Codingsight cung cấp hướng dẫn thiết lập và cấu hình sao chép cơ sở dữ liệu SQL Server.
Nhưng trước khi bạn nhúng tay vào những thứ kỹ thuật và tôi biết bạn cũng háo hức, điều quan trọng là phải lên kế hoạch cho nó.
Yêu cầu sao chép có thể thay đổi liên quan đến vị trí khi bạn triển khai Máy chủ SQL chạy trên đám mây. Nhưng một khi bản sao SQL đang chạy như một cỗ máy được bôi dầu tốt và sao chép dữ liệu sản xuất, bạn cần lập kế hoạch quản lý nó như thế nào.
Trong bài đăng này, tôi sẽ chia sẻ một số mẹo và tập lệnh T-SQL để bạn sử dụng khi bạn cần kiểm tra nhiều công việc SQL Agent được tạo sau khi cấu hình bản sao.
Giám sát tác nhân nhân rộng
Khi bạn thiết lập và cấu hình sao chép SQL, nó cũng tạo ra một tập hợp các chức năng độc lập và các công việc Tác nhân SQL được gọi là tác nhân sao chép. Mục tiêu của họ là thực hiện các tác vụ liên quan đến việc di chuyển bảng của bạn, còn được gọi là bài báo , trong cấu hình sao chép từ nhà xuất bản tới / s người đăng ký . Bạn có thể chạy các tác nhân nhân bản từ dòng lệnh và bằng các ứng dụng sử dụng Đối tượng quản lý nhân bản (RMO).
Tác nhân sao chép SQL Server có thể được giám sát và quản lý thông qua Replication Monitor và SQL Server Management Studio.
Mối quan tâm chính của quản trị viên cơ sở dữ liệu / quản trị viên nhân bản là đảm bảo rằng tất cả các công việc sao chép Đại lý SQL đang chạy. Nếu công việc nhân bản không thành công, người đăng ký có thể không nhận được dữ liệu. Do đó, cơ sở dữ liệu phân phối có thể phát triển rất lớn do các hàng tích lũy sẽ không chuyển đến cơ sở dữ liệu người đăng ký.
Để đặt cảnh báo cho bất kỳ lỗi công việc đại lý nhân bản nào, bạn có thể tạo một công việc đại lý khác. Nó sẽ kiểm tra lỗi công việc và gửi email đến nhóm dba của bạn nếu xác định được vấn đề.
Kiểm tra Công việc Tác nhân Nhân bản Không thành công
Sử dụng tập lệnh dưới đây:
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
Tạo thông báo qua email để thông báo về việc thất bại trong công việc
Áp dụng tập lệnh sau:
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 ;
Theo dõi bảng chứa các lệnh được lặp lại
Để giám sát msrepl_commands bảng, bạn có thể sử dụng một tập lệnh khác được cung cấp bên dưới. Lưu ý rằng bảng này sẽ phát triển quá lớn và quá nhanh. Nếu đúng như vậy, các công việc của tác nhân nhân bản có thể không thành công hoặc có thể có sự cố trong cấu hình nhân bản.
Tập lệnh như sau:
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
msrepl_commands xu hướng tăng trưởng bảng cũng cung cấp cho bạn một gợi ý về mức độ lành mạnh của độ trễ sao chép của bạn. Có nhiều yếu tố tác động. Nếu môi trường của bạn là trong đám mây, việc lựa chọn khu vực có thể góp phần lớn vào độ trễ sao chép.
C hiết xuất một Báo cáo Đơn giản về Sao chép và Gửi nó qua Email
Bạn có thể sử dụng tập lệnh sau:
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
H uu cầu Danh sách Bài viết và Kiểm tra Tình trạng Người đăng ký
Nếu bạn đang làm việc trên một bản sao giao dịch, các thao tác này là cực kỳ quan trọng. Đây là một tập lệnh:
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
Tạo Tóm tắt Báo cáo cho Nhóm DBA
Để kết hợp tất cả thống kê sao chép và các lệnh đã gửi và chưa gửi, bạn có thể tạo một bảng trong cơ sở dữ liệu phân phối để chứa tất cả các chi tiết sao chép.
Từ bảng này, bạn có thể tạo tóm tắt báo cáo để phân phối cho nhóm dba . Bảng này có thể được làm mới hàng ngày như một phần của kiểm tra sức khỏe nhân bản hàng ngày ngoài kiểm tra sức khỏe buổi sáng của quản trị viên cơ sở dữ liệu tiêu chuẩn.
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]
Tóm tắt
Tôi hy vọng rằng một vài tập lệnh T-SQL được cung cấp ở trên sẽ giúp bạn trong việc giám sát tác nhân nhân bản của mình. Tôi thực sự khuyên bạn nên theo dõi chúng chặt chẽ. Nếu không, người dùng ở cuối người đăng ký có thể phàn nàn không ngừng về việc không có (gần) dữ liệu thời gian thực.
Trong các bài tới, tôi sẽ tìm hiểu sâu hơn về công nghệ sao chép dữ liệu của SQL đến bất kỳ khu vực nào trên thế giới. Chúc bạn theo dõi vui vẻ!