私はこのようなデータベースシステムを継承しました。現在、SQL Server 2008 R2 SP2マシンを搭載したWindows Server 2008 R2のSQL Server 2005互換モードでパブリッシャーデータベースを使用しています。ディストリビューターは同じマシン上にあります。サブスクライバーは2008R2 SP2であり、データベースはSQL Server 2008互換モードです。トランザクションレプリケーションを使用しています。分離レベルはRead Committedです。ディストリビューターはパブリッシャーに常駐しています。パブリケーションを右クリックしても、サブスクリプションがプルサブスクリプションとして表示されますが、ディストリビューターはパブリッシャー自体に存在するため、問題はないと思います。私が間違っていたら訂正してください。ストレージシステムは、パブリッシャーとサブスクライバーを含む5つのサーバーで共有されるIBM flexです。
数日後、数時間の遅延が発生します。それは午前中に追いつき、午後から再び上昇し始めます。私は https://www.mssqltips.com/sqlservertip/3598/troubleshooting-transactional-replication-latency-issues-in-sql-server/ に従って、何が起こっていたかを正確に確認しました。次のクエリを実行しました。
USE distribution
go
EXEC Sp_browsereplcmds
@xact_seqno_start = '<seq#>' -- seq# is same for start and end
,@xact_seqno_end = '<seq#>'
,@publisher_database_id = <publisher database id --this is different than database_id
レプリケーションに関係するいくつかのテーブルで大量の更新が行われていると思われ、ログリーダーはトランザクションログをスキャンしているだけで、トランザクションが完了するまで何もレプリケートできません。興味深いことに、パブリッシャーとサブスクライバーのどちらにもブロッキングが表示されません。分離レベルをRead Committed Snapshot Isolation(RCSI)に変更すると、ここで役立ちますか?ポーリング間隔を1に、readbatchsizeを1000または5000に変更すると役立ちます。その設定を変更するコマンドは何ですか?
ログリーダーエージェントのデフォルトプロファイルを次のように変更しました。ポーリング間隔が5から1に、ReadBatchSizeが5000になりました。これにより、待ち時間が13時間からほぼ瞬時にゼロになりました。しかし、13時間に戻ったようです。
レプリケーションは同期しており、レイテンシの原因となった実際の根本的な原因を特定する手掛かりはありませんでした。
ついにマイクロソフトのサポートに連絡する必要があり、パブリッシャーでDBCC LOG INFOと呼ばれる単純なコマンドを実行するだけで根本的な原因が明らかになりました。 8600以上のVLFを見ました!これがレイテンシの原因でした。また、ログファイルは538GBに事前に割り当てられています。
マイクロソフトとのケースを開いた翌日の午後4時にヘルプのフォローアップコールを受けたとき、レプリケーションはほぼ19時間ずれていました。実行する手順は本当に簡単でした。いくつかの時間パブリッシャーデータベースログをバックアップし、ログファイルを圧縮してみます。ログファイルの増分係数を、パーセンテージまたは500MBではなく、8GBまたは12GBで設定します。したがって、次回ログファイルが大きくなると、増分係数に応じて、8 GBまたは12 GBあたり16のVLFが作成されます。
ログをバックアップした後、ログファイルを350GBに、VLFの合計を約5300に圧縮することができました。レイテンシは下がりませんでした。それは22時間まで行きました。 VLFの数が原因の1つにすぎないのではないかと思い始めました。ただし、午後11時30分頃にレイテンシは約7時間30分に短縮され、その頃に空き領域が増え、VLFは2001に減少しました。午前2時までに、レプリケーションは同期されました。私は急いでログを2回バックアップし、ログファイルを10 GBに縮小して、約248 GBに戻しました。現在、VLFの総数は184であり、それ以降、レプリケーションは同期しています。ふew!ログファイルはほとんど空です。
これについて質問がある場合はお知らせください。お役に立ててうれしいです。うまくいけば、他の誰かがこの問題についてマイクロソフトに電話する必要はありません。
分離レベルをコミット読み取りスナップショット分離(RCSI)に変更すると、ここで役立ちますか?
これは単純な変更ではなく、tempdbのペナルティが追加されます。私は推奨しません環境で適切にテストして利点を確認せずに、分離レベルをRCSIに変更するだけです。私を信じて、これはそりハンマーのアプローチです。
最近同じ問題に遭遇しました
レプリケーションに関係するいくつかのテーブルで大規模な更新が行われ、ログリーダーがトランザクションログをスキャンしている
以下は私が問題を解決した方法です:
記事をバッチとして複製します(この変更は動的であり、再初期化は必要ありません):
@status
値。 16未満の値は、TSQLを使用して複製するように設定されていることを示します==> NOT Batched!1つの記事がBATCHに設定されていなくても、サブスクライバーに変更を適用すると、どの記事もBATCHEDされません。
TSQLの下で使用
EXEC sp_changearticle @publication = N'<pub name>' -- your publication Name
, @article = N'<article name>' -- your article Name
, @property = 'status'
, @value = 'parameters'
ディストリビューションデータベースにクラスタ化されていないインデックスを作成しました:
USE [distribution]
GO
CREATE NONCLUSTERED INDEX [nc_MSrepl_commands_DBA]
ON [dbo].[MSrepl_commands] ([publisher_database_id],[article_id],[xact_seqno])
INCLUDE ([type],[originator_id])
GO
より高度なチューニングについては、 Enhance Transactional Replication Performance 特にディストリビューションエージェントとログリーダーエージェントのパラメーターを参照してください。
以下は、T-Repレプリケーションのステータスを確認するために使用しているスクリプトです。
USE [distribution]
-- Ref: http://www.sqlservercentral.com/blogs/basits-sql-server-tips/2012/07/25/t-sql-script-to-monitor-transactional-replication-status/
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
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]