分发清除作业阻塞日志读取器代理

开发反馈做复制的表每隔一段时间会延迟,最大延迟时间超过15分钟。
打开复制监视器,找到发布所对应的订阅,查看是否有错误。在"发布服务器到分发服务器的历史记录"栏发现下图所示信息:

图中我们可以看出上下两条间隔大约15分钟,每条"正在传递复制的事务..."到下一条"复制代理在10分钟内没有记录任何进度消息..."之间,肯定命令没有传递到分发服务器。
至于"错误"消息出现多久后又开始正常传递复制的事务,这个单独从上图是很难界定的。上图最直观的反馈是,正常复制->日志代理异常->正常复制->日志代理异常,如此反复。证实开发所说的问题确实存在。
复制监视器实际上依赖于复制代理来定期报告状态信息。如果该报告未能在一个较长的时间内发送,复制监视器将报告问题。
错误消息只声明复制代理在10分钟内没有记录任何进度消息。这表明代理已停止或系统活动过多。错误消息建议手动检查记录仍然被复制以及网络是连通的。目标数据库检查发现记录没有被复制,检查网络没发现问题。
发布到分发对应的是日志读取器代理,查看相关作业,显示正在执行,历史记录空白。复制监视器中查看对应日志读取器代理状态显示正在运行。发布服务器查看正在执行的请求(dm_exec_requests),寥寥几行。
中间一段时间没有头绪,各种设想,各种置疑。后来请教大菠萝,他给了几个检查步骤:1确定日志读取器代理正在运行;2复制表数据情况,是否间隔性的发生数据变动;3看看ldf所在磁盘的性能(关注Avg. Disk sec/Write),是否有间隔性的性能问题;4看看锁等待;总之,看看有没有和15分钟相关的性能异常。
前面也怀疑存在某个周期性的操作影响到复制,但局限于发布服务器,并且异常间隔时间不固定,没能找出。
第二天,眼瞅着没啥进展。查看复制所有相关作业的历史记录,发现“分发清除:distribution”执行时间有点过长(20分钟左右)。查看作业属性,作业每10分钟执行一次。作业最近几次历史记录如下:

红框部分可以看到作业在2016-08-17 10:05:00.000开始执行,持续20分51秒;也就是从10点05分到10点26分作业一直在执行,而此期间复制命令一直没能传到分发服务器。可以查看分发库中MSrepl_transactions的记录,也可以从订阅端检查没有新数据过去。等作业执行完,它已跨越两次计划执行(15、25分)。2016-08-17 10:25:51.000起作业空闲,复制命令传送,直到下次作业执行(2016-08-17 10:35:00.000)。
2016-08-17 10:05:00.000~2016-08-17 10:25:51.000  分发清除作业执行,复制命令异常
2016-08-17 10:25:51.000~2016-08-17 10:35:00.000  复制命令正常传递
2016-08-17 10:35:00.000~2016-08-17 10:53:15.000  分发清除作业执行,复制命令异常
2016-08-17 10:53:15.000~2016-08-17 10:55:00.000  复制命令正常传递
单独从时间上来看,它和复制监视器中的信息完全吻合。基本上就是分发清除作业开始执行,复制命令异常,作业结束执行,复制命令正常。作业周期性执行,每次执行时长不定,最终我们看到的就是复制命令间隔性的延迟。
如何证明分发清除影响到日志读取器代理?分发清除为什么需要执行这么长时间,主要耗时在哪?
分发清除执行期间,我们查看分发服务器上的阻塞情况:

spid=86被spid=108阻塞,86和108对应的命令如下:


可以看到86是往分发库添加记录,108从分发库删除记录。我们查看它们的锁信息:

spid=108,对表MSrepl_transactions进行删除操作,在358918页上持有排它锁(X);spid=86,对表MSrepl_transactions进行写入操作,申请在358918页上的意向排它锁(IX);spid=86被spid=108阻塞。
分发清除作业主要耗时在哪个语句?下面是根据ApplicationName列筛选得到的跟踪文件,按照时长降序:

最大消耗在delete TOP(5000) MSrepl_transactions WITH (PAGLOCK) from MSrepl_transactions with (INDEX(ucMSrepl_transactions)) ...
逻辑读取次数(Reads)达到267791916,物理写入次数(Writes)仅有8,可见这个删除效率足够低!
什么原因导到如此低效的删除,表的记录索引情况如何:

MSrepl_commands和MSrepl_transactions记录数均达到2000+W,几乎占了整个库的全部。这些命令分别对应哪些表呢?

publisher_database_id=2,article_id=4对应的记录为20439213,对应就是复制异常的表。为什么有这么大的数据量?最小分发保持期(0小时),最大分发保持期(72小时)。检查各操作(insert、update、delete)命令数量如何?

上图从sys.dm_exec_cached_plans得到存储过程执行次数,可以看到约30个小时内sp_MSupd_dboAccountsinFo执行了800+万次(72小时约2000万)。也就是大量的命令是对AccountsinFo更新操作。
查看发布,allow_anonymous、immediate_sync属性设置为True。如果immediate_sync为true, snapshot 文件和replicated transaction将一直保留到data retention。然后才会被删除。这会导致distribution 数据库增长,复制性能下降。 所以推荐设置为false。需要注意的时,如果一个数据库有多个publication,只要其中有一个publication的immediate_sync为true,将会导致 这个数据库的所有publication的replicated transaction的保留期都延长至data retention。
最终的解决方案是,禁用allow_anonymous、immediate_sync属性。
总结
个人思路不清晰,考虑问题过于狭隘。感谢大菠萝。
参考
事务复制清除的故障分析https://blogs.msdn.microsoft.com/apgcdsd/2012/09/06/623/
Replication的犄角旮旯(四)--关于事务复制的监控http://www.cnblogs.com/diabloxl/p/3630410.html
SQL SERVER Transactional Replication中添加新表怎么不初始化整个快照http://www.cnblogs.com/kerrycode/p/4266646.html
复制代理JOBhttp://www.cnblogs.com/zerocc/p/3208621.html
distribution数据库过大问题http://www.cnblogs.com/datazhang/p/5106721.html

时间: 2024-10-31 09:07:15

分发清除作业阻塞日志读取器代理的相关文章

SqlServer 可更新订阅队列读取器代理错误:试图进行的插入或更新已失败

原文:SqlServer 可更新订阅队列读取器代理错误:试图进行的插入或更新已失败 今天发现队列读取器代理不停地尝试启动但总是出错: 其中内容如下: 队列读取器代理在连接"PublicationServer"上的"pubDB"时遇到错误"试图进行的插入或更新已失败, 原因是目标视图或者目标视图所跨越的某一视图指定了 WITH CHECK OPTION, 而该操作的一个或多个结果行又不符合 CHECK OPTION 约束.". 请确保正确定义了分发

SqlServer代理执行[分发清除: distribution] 无法删除快照文件

每天偶尔检查数据库作业是否失败,发现有错误 [sql] view plaincopy select top 10 job_id,run_date,run_time,run_duration,step_name,message from  msdb..sysjobhistory where run_status = 0 order by run_date desc,run_time desc 该作业失败. 计划 12(复制代理计划.)调用了该作业.最后运行的是步骤 1(运行代理.).. 已以用户 

Java Log Viewer日志查看器

工欲善其事必先利其器 在投奔怒海--一个Domino老程序员眼里的Java开发我提到目前所做的Java开发中遇到的大量日志之问题.服务器控制台刷屏似地滚动,日志文件飞快地增长,debug的时候相关信息常常被例常日志淹没,在众多Logger滔滔不绝的输出下,要找出错误所在有时都挺费眼.日志的作用无可置疑,大型项目中日志海量产生也不少见.在以前的Domino开发中,Domino服务器在产生日志方面相当节制,程序员对日志的依赖程度也不高.转换到Java开发,我用一直最喜爱的文本编辑器EditPlus肉

python清除数据库错误日志

# coding=gbk from encodings import gbk import re import sys import  os import  pyodbc import traceback import decimal #连接数据库 conn = pyodbc.connect('DRIVER={SQL Server};SERVER=192.168.1.43;DATABASE=master;UID=sa;PWD=passwd123!') # 获取cursor对象来进行操作 curs

java PriorityBlockingQueue 基础的优先级队列,可阻塞的读取操作.

package org.rui.thread.newc; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.PriorityB

简单记录一次REDO文件损坏报错 ORA-00333重做日志读取块出错

一.故障描述 首先是实例恢复需要用到的REDO文件损坏 二.解决方法 1.对于非当前REDO或者当前REDO但是无活动事务使用以下CLEAR命令: 用CLEAR命令重建该日志文件SQL>alter database clear logfile group 3: 如果是该日志组还没有归档,则需要用SQL>alter database clear unarchived logfile group 3: 因为是当前实例恢复需要用的REDO,且未归档,使用是CLEAR命令不行的. 2.没备份,有备份可

SharePoint ULS Log Viewer 日志查看器

SharePoint ULS Log Viewer 日志查看器 项目描述 这是一个Windows应用程序,更加轻松方便查看SharePoint ULS日志文件.支持筛选和简单的视图. 信息 这是一个WPF应用程序,LINQ支持. 目前版本有以下特点: 1. 转换和打开多个SharePoint ULS日志(如果选择多个或合并). 2. 记录并改变列大小,在任何列排序. 3. 支持Severity.Category和Process或自定义文本过滤.搜索. 4. 将多行单个日志跟踪记录分组更容易查看.

OpenCV:基于MFC的视频播放器和图片读取器

实例工程包下载[OpenCV:基于MFC的视频播放器和图片读取器] 一.实现的功能 1.打开本地视频进行读取.播放.暂停.停止控制 2.图片打开功能分为两种:可使用"打开图片"按钮打开本地图片,或者点击comobox里面设定的图片列表选择并显示图片 二.编译环境 OS:Win8.1 x64 IDE:  Visual Studio 2013 OpenCV: 2.4.8 三.主要思路 1.视频的滑动条控制: ①主窗体的OnHScroll()响应函数负责响应slider滑动条的变化,这样就轻

简单的XML读取器

XML 指可扩展标记语言(EXtensible Markup Language) (有个很明显的槽点),是一种主要设计用来数据传输存储的语言. 有关语法规则我是参考了这个链接. http://www.w3school.com.cn/xml/xml_syntax.asp 看 gcc4 的时候觉得数据驱动编程很酷,于是顺带觉得xml很酷,正好暑假闲就写了个xml读取器看看,鼓捣了几天,弄好了大致上的功能,这里所说大致上,是能够满足检查语法错误并给出错误信息到标准输出设备(不保证报错信息绝对有用).如