Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

原文:Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

《Replication的犄角旮旯》系列导读

Replication的犄角旮旯(一)--变更订阅端表名的应用场景

Replication的犄角旮旯(二)--寻找订阅端丢失的记录

Replication的犄角旮旯(三)--聊聊@bitmap

Replication的犄角旮旯(四)--关于事务复制的监控

Replication的犄角旮旯(五)--关于复制identity列

Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟)

Replication的犄角旮旯(八)-- 订阅与发布异构的问题

Replication的犄角旮旯(九)-- sp_setsubscriptionxactseqno,赋予订阅活力的工具

---------------------------------------华丽丽的分割线--------------------------------------------

前言:这是昨天刚刚发生的案例,尽管事件的起因只是一个简单的DDL操作,但影响面和影响时间可以说是大大超出了预期;我们将在描述本案例的前因后果之后,聊聊如何近似估算DDL的操作进度,以及关于logreader延迟的问题;

由于直接找MS开了case,直接引用标准回复格式;

=====================华丽丽的分割线========================

问题描述

=========

对于一张11亿的数据进行PK字段的int到bigint的类型转换,一直没有完成。发现replication延迟仅1小时

问题排查

=========

1.sp_replcounters发现replbeginlsn的值一直没有改变,但是replnextlsn一直在变化

2.sp_replcounters返回未发送的transaction持续上升

发生原因

=========

1. 执行ALTER TABLE修改PK字段从INT到bigint时,由于一直没有完成,这被视为是一个active transaction,这个值代表当前LOG的minLSN, 由于这个transaction一直没有做完,所以这个值一直没有变化


Replbeginlsn


binary(10)


Log sequence number (LSN) of the current truncation point in the log.

http://technet.microsoft.com/en-us/library/ms190486(v=SQL.110).aspx

2. 但是根据我们对于log reader的理解,这个beginLSN即使一直没有变化,也不会影响log reader对于日志的读取,因为log reader会直接从replnextlsn开始扫描

3. 由于active transaction一直没有提交,导致日志无法被截断,日志持续自增,目前已经有270GB, 4000个VLF

4. VLF太多通常是会导致log reader读取日志较慢,但是由于目前4000个VLF中只有2500个处于status=2的活动状态,并不是很多,这也不是导致replication延迟的原因

5.select *from fn_dblog(null,null)发现有大量的LOP_MODIFY_COLUMN的日志记录 (处理在LCX_HEAP上),这个应该针对于每一条记录做类型转换时都需要记录的日志.而这个记录还在不断增多.由于这部分日志会有超过11亿条,并且replication不需要发送这些日志(因为这张表已经从article中移除).但是这部分日志还是需要被log reader扫描一遍,然后跳过去,这样的扫描造成了log reader读取日志变慢,从而导致replication的延迟.

解决方案

========

1.持续等待到ALTER TABLE做完,这样log reader跳完了所有的日志以后,replication的延迟会自动追上去

2.手动cancel这个alter table,让他回滚,这样就不会产生新的日志,log reader不需要再扫描那些日志,也会慢慢追上延迟

最后您通过cancel这个alter table的语句,这个问题得以缓解.

下一步方案

========

根据我们以前case的历史背景,和今天的电话沟通,我建议您对于这张表的字段修改还是使用导到新表,然后重命名的方式.因为这样的办法使用的是select into,属于BULK操作,在SIMPLE模式下是不记日志的,所以不会对replication有影响.

=====================华丽丽的分割线========================

案例补充说明:

由于alter table操作并不能直接获取操作的进度(sys.dm_exec_requests中的percent_complete对alter table操作不计算执行进度),经过MS工程师的指点,我们依然可以间接的估算出操作进度;以下通过一个测试案例说明

1、创建一个数据表,填充数据;

test_1表,id列为主键自增列,类型bigint;填充数据51W条,数据大小2G左右;

2、修改id类型(int改为bigint),由于id是主键,所以需要先删除主键约束才能继续alter table。删除主键约束后,手动checkpoint一下,清理一下fn_dblog;

3、执行alter table语句并检查fn_dblog

可以看到大量的修改行的记录,完成alter table后再查一下fn_dblog,总记录数51W多,基本与数据量一致;

4、按照下面的脚本筛选一下,可以看到,alter table操作(对堆表),实际是每行都急了一条modify的日志

SELECT [Current LSN],Operation,Context,[Transaction ID],[Log Record Fixed Length],[Log Record Length],
AllocUnitId
FROM fn_dblog(NULL,NULL) fnlog
WHERE Operation=‘LOP_MODIFY_ROW‘ AND Context=‘LCX_HEAP‘ AND [Transaction ID]=‘0000:00ed4660‘

然后我们在对Current LSN分析,看看跨了几个VLF

形如:00028b3d:0000002f:001e

其中第一段00028b3d表示VLF号,于是将上述结果集中的Current LSN按第一段分组计数,使用下面的脚本即可;

--查询fn_dblog中每个VLF包含的记录数
SELECT LEFT([Current LSN],CHARINDEX(‘:‘,[Current LSN])-1),COUNT(1)
FROM fn_dblog(NULL,NULL) fnlog
WHERE Operation=‘LOP_MODIFY_ROW‘ AND Context=‘LCX_HEAP‘ AND [Transaction ID]=‘0000:00ed4660‘
GROUP BY LEFT([Current LSN],CHARINDEX(‘:‘,[Current LSN])-1)

可以看到,目前查询到的记录中,平均每个VLF中包含1900左右的记录数

4、先计算出按照平均1900/VLF,需要多少个VLF才能支持写完51W条记录(510000/1900,约为268个VLF)

5、结合DBCC LOGINFO,可以得出当前活动VLF的数量(当alter table执行时,由于未提交或回滚,VLF处于活动状态而不能被截断),在比较预计VLF数和当前活动的VLF,即可知道当前alter table的进度

这里最好加一个限定,fn_dblog查出来的VLF号是16进制的,换成10进制是166717,再去DBCC LOGINFO的结果集查询,增加 fseqno>=166717的条件;

小结:根据fn_dblog中某一段的日志情况(通过Operation=‘LOP_MODIFY_ROW‘ AND Context=‘LCX_HEAP‘ AND [Transaction ID]=‘0000:00ed4660‘确认正在执行的DDL操作,其中[Transaction ID]和Current LSN的起始位置,可以通过dbcc opentran确定),统计出平均VLF中的记录数(由于实际环境中影响日志记录的因素较多,因此需要多看几个VLF来估算DDL操作日志量的平均占比情况),再根据DBCC LOGINFO中当前活动VLF的数量推算出DDL操作的进度;

时间: 2024-10-02 05:15:32

Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)的相关文章

校花的贴身高手 第一卷 神奇的任务 第050章 一个篮球引发的血案(上)

第050章 一个篮球引发的血案(上) “嗷——”邹若明痛苦的嚎叫了一声,他的手腕已经被砸的脱臼了,篮球穿过了他的双手,直接向他的脸上拍去! “砰”,又是一声巨响,邹若明这次连嚎叫都没来得及嚎叫,就鼻孔飞血的倒在了地上,鲜血在空中划出了一道彩虹,很有冷酷的美感. 邹若明被直接拍的昏死了过去,一旁和他一起玩篮球的走狗们也都傻了眼了,这还是篮球么?简直就是炮弹了! 再看那个始作俑者,林逸很是没事儿人似的,拍了拍手上的灰尘,向教学楼继续走去.林逸心里暗暗不屑,和我装犊子呢?这次算是轻的了,要是还有下次,

Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟)

原文:Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟) <Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Replication的犄角旮旯(三)--聊聊@bitmap Replication的犄角旮旯(四)--关于事务复制的监控 Replication的犄角旮旯(五)--关于复制identity列 Replicat

一个无线网卡引发的血案

经常听说一个馒头引发血案,今天我要说的是一个无线网卡的故事...... 最近有同事反应无线网卡连接公司网络无法正常连接,但是连接家里的网络是OK了,于是让桌面支持的同事检测了一下,结果他们把系统重新安装了也还是不能够正常连接,为此只能自己出马了: 1.更新驱动至最新版 查看了一下网卡型号为Intel wireless-N 1030 ,于是下载了一个最新的网卡驱动给其安装了Wifi_Intel_Win7_32_VER15312.zip 2.开启无线事件记录功能 采集日志发现以下错误: #Event

一个脚本引发的血案

我们本身是一家互联网金融公司,公司的主流业务就是p2p,因为各种原因吧,15年底启动建设众筹平台.考虑到前期开发过程中的一些弊端和架构经验,本次架构引用了dubbo做soa服务的治理,web容器nginx+tomcat,后端语言采用java,框架选择spring+mybaits,前端模板引擎使用的是btl,app采用原生+h5的模式.这个架构可以参考我之前写的文章从零到百亿互联网金融架构发展史中的第三代系统架构,之前的文章主要介绍了架构的变迁,本篇文章主要介绍在第三代平台中遇到的问题以及解决方法

一个bug引发的血案——从程序员角度看罗一笑事件

我这人有个毛病一直改不掉,不过好像也没怎么试过去改,那就是自命清高.这应该是文青的一大特点,总觉得跟文化这么高雅的东西挂钩怎么都低俗不了. 在做公众号这件事情上,自命清高就体现在不谈热点.去年一年火的事情不少--阿尔法狗大战李世乭.王宝强事件,以及川普当选美国总统.为什么不谈呢?首先是因为大家都在谈,我也跟着凑上去有种蹭热点的嫌疑,而且更有种人云亦云的庸俗感.其次是因为有一贯关注的主题,平时工作已经够忙的了,闲下来的时间还是要分配给它们. 到了新的一年,我要洗心革命,要跟人民群众靠拢,不能再做一

【转】Druid连接池一个设置引发的血案

https://my.oschina.net/haogrgr/blog/224010 今天在一台配置很低的机器上运行批量更新的程序~~~ 大概跑了三十分钟~~~这配置~~~这程序~~~ 然后华丽丽的报异常了~~~ 具体异常是这样的, DEBUG: (BaseJdbcLogger.java:132)    ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4d4e22e1] [2014-07-17 15:1

Matlab一个错误引发的血案:??? Error using ==&gt; str2num Requires string or character array input.

Matlab总遇到一些神奇的问题,让人摸不着头脑.昨天编写程序的时候遇到一个让我十分火大的问题,也是自己的matlab基础不好吧. 先描述一下问题,再GUI界面有个listbox,Tag属性是’listbox1’,里面是这样的数据,我的目的是要把这些数据转换成数值类型的矩阵: list_string = get(handles.listbox1,'string') data=str2num((list_string)); 使用上面两行代码进行转换却异常出错了!看后台的错误描述如下: ??? Er

一个空格引发的血案

我写了一个Js字典,字典里的内容如"个体户":110,我用jquery取dom里的值,取到的是"个体户 ".我看它值的时候是用alert看的,看到的是"个体户".我之后就用mydic[var]取,当然是取不到值的.因为var为"个体户 ".之后用typeof看数据类型也是string.tmd的瞬间不淡定了,之后就用firebug调试咯,看到了"个体户 ".顿时喜出望外........ 唉作为刚入职的菜b,不

JavaScript中一个函数引发的血案

规则: 1.所有的对象都有__proto__属性,指向他构造函数的原型 2.函数具有prototype属性,指向该函数的prototype 3.函数也是对象,所以函数也有__proto__属性,指向构造函数的原型,其构造函数即为Function函数 4.所有的函数都是Function的实例 5.所有函数的原型的__proto__都是Object的一个实例 6.内置函数的构造函数是一个匿名函数,且没有prototype 如 Function,Array,Object 7.JavaScript高级程