有两种情况会造成更新丢失,第一种是不正确的设置,例如外键或触发器的“Not For Replication” (NFR)属性没有开启。详情请参考http://blogs.msdn.com/b/apgcdsd/archive/2012/01/10/10254809.aspx

第二种是产品bug,例如使用了 MaxCmdsInTran http://support.microsoft.com/kb/2648158

前一阵我在做case的时候遇到了一个新的bug。这个bug在sql server 2005,2008,  2008R2这些版本中都可以重现,并且目前没有推出相应的fix.  需要注意的是,sql server 2012中相关的行为已经重新进行了设计,不会存在这个问题。

描述

===

环境:事务复制的订阅是通过快照进行的初始化

条件:Logreader没有运行。

操作:我们向publicaiton添加了一个新的Article.

此时在log reader停止期间到完成添加article之前,publication的article出现了更新/删除/插入,那么这些变更都不会传递到订阅。 假设 Logreader在11:00停止,我们在12:00添加了一个新的artilce(假设瞬间完成),13:00重新启动Logreader 。那么11:00~12:00之间的更新将全部丢失。

原因

===

当publicationdatabase的article发生更新时, 会产生相应的日志,Log reader会读取这些日志信息,将他们写入到Distribution 数据库的msrepl_transactions和msrepl_commands中。具体的技术细节我会在以后的文章里介绍。

Msrepl_transactions中的每一条记录都有一个唯一标识xact_seqno,xact_seqno对应日志中的LSN。 所以可以通过xact_seqno推断出他们在publicationdatabase中的生成顺序,编号大的生成时间就晚,编号小的生成时间就早。

Distributionagent包含两个进程,reader和writer。 Reader负责从Distribution 数据库中读取数据,Writer负责将reader读取的数据写入到订阅数据库.

reader是通过sp_MSget_repl_commands来读取Distribution数据库中(读取Msrepl_transactions表和Msrepl_Commands表)的数据

下面是sp_MSget_repl_commands的参数定义

CREATE PROCEDURE sys.sp_MSget_repl_commands

(

@agent_id int,

@last_xact_seqno varbinary(16),

@get_count tinyint = 0,  -- 0 = no count, 1 = cmd and tran (legacy), 2 = cmd only

@compatibility_level int = 7000000,

@subdb_version int = 0,

@read_query_size int = -1

)

这个存储过程有6个参数,在Transactionalreplication 中,只会使用前4个(并且第三个参数和第四个参数的值是固定不变的.分别为0和10000000)。下面是一个例子:

execsp_MSget_repl_commands 46,0x0010630F000002A900EA00000000,0,10000000

@agent_id表示Distributionagentid,每个订阅都会有一个单独的Distributionagent来处理数据。 带入@agent_id后,就可以找到订阅对应的publication 和所有的article。

@last_xact_seqno 表示上一次传递到订阅的LSN。

大致逻辑是:Reader读取分发数据库中LSN大于@last_xact_seqno的数据。 Writer将读取到的数据写入订阅,并更新相应的LSN.(subscription数据库的 MSreplication_subscriptions表的 transaction_timestamp列和Distribution数据库的msDistribution_history表的xact_seqno列)。然后Reader会继续用新的LSN来读取后续的数据,再传递给Writer,如此往复。

假设现在订阅段的数据已经更新到了0x0010630F000002A900EA00000000, 之后我们认为地向Msrepl_transactions表和Msrepl_Commands表插入了一批数据,xact_seqno对为0x0010630E000002A900EA00000000. 虽然这些数据的格式全部有效, 但Distributionagent是不会读取这些新加入的数据的,因为他们"太旧了"(他们的xact_seqno小于订阅的xact_senqo).

当Log reader停止时, 我们是可以添加article的。 并且相应的操作也会向msrepl_transactions和msrepl_commands插入数据,这些数据并不是由Log reader传递的,而是通过linkedserver直接向Distributor直接写入数据。 Distributionagent会读取这些数据,并更新相应的xact_seqno。 而"Log reader停止"到"添加新article"这段期间发布产生的数据的xact_seqno是小于"添加新article"的xact_seqno,所以这些跟新会丢失。 说起来比较抽象,下面举个例子。

10:00到11:00期间publication database共生成了三条事务,对应的xact_seqno分别为

0x0010630F000006B9001E

0x0010630F000006F10004

0x0010630F000006F20004

11:01将log reader停止

11:01~12:00期间publication database共生成了4条事务

0x0010630F000006F30004

0x0010630F000007080005

0x0010630F000007D40205

0x0010630F0000098C005C

但由于log reader没有启动,所以msrepl_transactions表内依然是三条数据. 12:01完成添加article的操作,msrepl_transactions内生成相应的记录0x00106310000000100100。

此时msrepl_transations内共有四条记录

此时订阅端的xact_seqno为0x0010630F000006F20004, distribution agent将读取大于0x0010630F000006F20004的数据, 只有0x00106310000000100100符合要求。 订阅段完成的所有的数据同后,相应的xact_seqno为0x00106310000000100100

此时开启log reader, 累计的数据传递完毕后,msrepl_transactions共有8条记录,但distribution agent不会再去读取之前的数据了…

影响

===

在有些极端情况下,即使您认为Log reader处于运行状态,还是会出现跟新丢失的情况。原因在有些情况下,Log reader成为了deadlock的牺牲者被kill掉,但Log readeragentjob有自动retry的机制,会在一段时间后自动恢复, 所以您可能无法察觉。 是否出现死锁,您查询MSLog reader_history,MSrepl_errors会找到类似的"N'Transaction (Process ID 400) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.',NULL,1,N'  SQL Log Reader Agent encountered an error.    Publisher: xxx Publisher Database: xxx".

解决办法

===

将Distributor升级至sql servr 2012

如果您暂时没有办法升级,可以采用以下两种方法:

  1. 添加一个新的发布,将新的article添加到发布中。
  2. 在添加article前将Log reader和Distributionagent停止。添加完成后,启动Log reader,确认Log reader已经将之前的数据传送到了Distribution数据库后(可以使用tracertoken来确认Log reader是否已经完成同步), 启动Distributionagent。这样就可以避免数据丢失了。

更多(2013.10.23补充)

===

如果添加一个非快照初始化的订阅时,该发布对应的发布数据库的所有已存在订阅也会出现更新丢失的情况,无论这些都订阅通过何种方式初始化,或属于那个发布.

因为添加订阅的操作也会通过linked server向distribution database内写入数据

解决方法和之前相同

该问题已经在sql server 2008 r2 sp2 cu13中解决(2014.07.01补充)

http://support.microsoft.com/kb/2922526

一个事务复制的bug--更新丢失的更多相关文章

  1. 一个事务复制的bug--更新丢失 续

    阅读本文之前请参考http://www.cnblogs.com/stswordman/p/3258897.html 最近又做了一个case,环境是sql server 2008 R2. 客户添加了一个 ...

  2. SqlServer 使用脚本创建分发服务及事务复制的可更新订阅

    原文:SqlServer 使用脚本创建分发服务及事务复制的可更新订阅 [创建使用本地分发服务器] /************************[使用本地分发服务器配置发布]*********** ...

  3. sqlserver 2000事务复制问题

    2000现在用的估计不多了,把之前收集的一些复制问题整理发布出来.可能都是些很白很二的问题,但人总是由最初的无知不断成长,不对之处欢迎指正. sqlserver 2000事务复制问题服务器A(发布) ...

  4. SQL Server 2000事务复制问题

    2000现在用的估计不多了,把之前收集的一些复制问题整理发布出来.可能都是些很白很二的问题,但人总是由最初的无知不断成长●-● SQL Server 2000事务复制问题服务器A(发布) 服务器B(分 ...

  5. sqlserver 2005 分布式架构 对等事务复制 .

    http://www.cnblogs.com/qanholas/archive/2012/03/22/2412444.html     一.为什么要使用对等事务复制 首先要说明的是使用sqlserve ...

  6. 【数据库-Azure SQL Database】如何创建事务复制将本地数据同步到 SQL Azure

    Azure SQL DB 可以被配置成为 SQL Server 事务复制的一个订阅者( subscriber ). 主要应用场景有两种: 将您的数据迁移到 Azure SQL DB, 并且没有宕机时间 ...

  7. Mysql锁机制--并发事务带来的更新丢失问题

    Mysql 系列文章主页 =============== 刚开始学习 Mysql 锁的时候,觉得 Mysql 使用的是行锁,再加上其默认的可重复读的隔离级别,那就应该能够自动解决并发事务更新的问题.可 ...

  8. 一个简易的四则运算单元...(15.12.15 BUG更新)

    网上找的, 没有作者信息, 只能在这里感谢一下了, 支持标准写法的四则运算 --2015-12-15 修改了一个内存泄漏的BUG - Pop方法没有释放申请的内存 unit Base.Calculat ...

  9. 事务复制5: Transaction and Command

    事务复制使用 dbo.msrepl_transactions 和 dbo.MSrepl_commands 存储用于数据同步的Transaction和Command.在replication中,每个co ...

随机推荐

  1. solr 中文分词 IKAnalyzer

    solr中文分词器ik, 推荐资料:http://iamyida.iteye.com/blog/2220474?utm_source=tuicool&utm_medium=referral 使 ...

  2. UVA 10054 (欧拉回路) The Necklace

    题目:这里 题意:有一种由彩色珠子连接而成的项链,每个珠子两半由不同颜色(由1到50的数字表示颜色)组成,相邻的两个珠子在接触的地方颜色相同,现在有一些零碎的珠子,确认它是否能 复原成完整的项链. 把 ...

  3. bootstrap-标题

    1.重置了margin-top和margin-bottom的值,h1到h3重置后margin-top的值都是20px:h4到h6重置后的值都是10px: 2.所有标题的行高都是1.1(也就是font- ...

  4. STL学习笔记

    简介 STL(Standard Template Library),即标准模版库,涵盖了常用的数据结构和算法,并具有跨平台的特点.STL是C++标准函数库的一部分,如下图所示: STL含有容器.算法和 ...

  5. U盘启动盘 安装双系统 详细教程

    U盘启动盘 安装win7+linux双系统 最近在看鸟哥的linux 私房菜 ,看到多重系统那部分,自然的安装多重系统的激情由此而燃.在网上看了很多资料,感觉都不全.经过艰辛的摸索,终于被我发现了一个 ...

  6. ASP数组全集,多维数组和一维数组[转]

    ASP数组是比较好用的装载大量数据的容器.1 定义数组 有两种方式:DIM和REDIM. DIM定义的是固定个数.数据类型的数组:而REDIM则不同,它可以定义不同类型的数据,也可以定义个数并非固定的 ...

  7. 【转载】最完美解决Nginx部署ThinkPHP项目的办法

    网上通用解决方法的配置如下: server { ... location / { index index.htm index.html index.php; #访问路径的文件不存在则重写URL转交给T ...

  8. Gray Code

    Gray Code The gray code is a binary numeral system where two successive values differ in only one bi ...

  9. CAD 二次开发--属性块

    1.属性块的定义 属性块是有构成的实体和附加信息(属性)组成的,属性块中块的定义与简单块中块的定义一样,而属性的定义主要是通过属性的AttributeDefinition类的有关属性和函数来实现的.具 ...

  10. echarts异步加载柱状图遇到的错误- Error: Component series. not exists. Load it first.

    今天看了下echarts教程之中的异步加载柱状图,我按照教程中的代码敲出来之后再运行,就报了一个 Error: Component series. not exists. Load it first. ...