一个事务复制的bug--更新丢失
有两种情况会造成更新丢失,第一种是不正确的设置,例如外键或触发器的“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
如果您暂时没有办法升级,可以采用以下两种方法:
- 添加一个新的发布,将新的article添加到发布中。
- 在添加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--更新丢失的更多相关文章
- 一个事务复制的bug--更新丢失 续
阅读本文之前请参考http://www.cnblogs.com/stswordman/p/3258897.html 最近又做了一个case,环境是sql server 2008 R2. 客户添加了一个 ...
- SqlServer 使用脚本创建分发服务及事务复制的可更新订阅
原文:SqlServer 使用脚本创建分发服务及事务复制的可更新订阅 [创建使用本地分发服务器] /************************[使用本地分发服务器配置发布]*********** ...
- sqlserver 2000事务复制问题
2000现在用的估计不多了,把之前收集的一些复制问题整理发布出来.可能都是些很白很二的问题,但人总是由最初的无知不断成长,不对之处欢迎指正. sqlserver 2000事务复制问题服务器A(发布) ...
- SQL Server 2000事务复制问题
2000现在用的估计不多了,把之前收集的一些复制问题整理发布出来.可能都是些很白很二的问题,但人总是由最初的无知不断成长●-● SQL Server 2000事务复制问题服务器A(发布) 服务器B(分 ...
- sqlserver 2005 分布式架构 对等事务复制 .
http://www.cnblogs.com/qanholas/archive/2012/03/22/2412444.html 一.为什么要使用对等事务复制 首先要说明的是使用sqlserve ...
- 【数据库-Azure SQL Database】如何创建事务复制将本地数据同步到 SQL Azure
Azure SQL DB 可以被配置成为 SQL Server 事务复制的一个订阅者( subscriber ). 主要应用场景有两种: 将您的数据迁移到 Azure SQL DB, 并且没有宕机时间 ...
- Mysql锁机制--并发事务带来的更新丢失问题
Mysql 系列文章主页 =============== 刚开始学习 Mysql 锁的时候,觉得 Mysql 使用的是行锁,再加上其默认的可重复读的隔离级别,那就应该能够自动解决并发事务更新的问题.可 ...
- 一个简易的四则运算单元...(15.12.15 BUG更新)
网上找的, 没有作者信息, 只能在这里感谢一下了, 支持标准写法的四则运算 --2015-12-15 修改了一个内存泄漏的BUG - Pop方法没有释放申请的内存 unit Base.Calculat ...
- 事务复制5: Transaction and Command
事务复制使用 dbo.msrepl_transactions 和 dbo.MSrepl_commands 存储用于数据同步的Transaction和Command.在replication中,每个co ...
随机推荐
- ORACLE 数据库需要创建索引的规则
1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特别是大表的字段,应该建立索引: ...
- java 删除所有HTML工具类
import java.util.regex.Matcher;import java.util.regex.Pattern; public class HtmlUtil { private stati ...
- 数据库之Group By用法
sql语句Group By用法 sql语句Group By用法一则 sql语句Group By用法一则 如果我们的需求变成是要算出每一间店 (store_name) 的营业额 (sales),那怎么办 ...
- odoo10 费用报销
odo10 对费用报销进行了改进,恢复了 8.0 及之前版本具有的 单个报销包含多个 明细内容的功能. 使用步骤大致如下: 根据管理需要设立 相应的科目和分析帐户 科目 分析帐户 建立费用目录 员工录 ...
- dp、px、dpi、ppi
概念: dpi(Dots Per Inch):每英寸上的点数,最初用于衡量打印物上每英寸的点数密度,打印机在一英寸内打多少个点.DPI值越小越不精细. ppi(Pixels Per Inch):每英寸 ...
- iptables示例
[root@iZ23um2lv3tZ ~]# more /etc/sysconfig/iptables # Generated by iptables-save v1. :: *filter :INP ...
- Oracle sys和system用户、sysdba 和sysoper系统权限、sysdba和dba角色的区别
sys和system用户区别 1)最重要的区别,存储的数据的重要性不同 sys所有oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于oracle的运行是至关重要的,由数据库自己 ...
- 遇到的sql关键字
select count(1) 相当于 select count(*) 网上有比较差别的 菜鸟不用管
- ueditor问题简记录
一.百度ueditor下载地址:http://ueditor.baidu.com/website/download.html. uBuilder下载,个人选了一些自用的,.net的,但是很奇怪下载响应 ...
- Angular常用功能
1.默认选择让第0个元素的class为active ng-class="{active:$index == 0}" 2.指令的例子 <!DOCTYPE html> &l ...