首页  >  文章  >  数据库  >  一个事务复制的bug--更新丢失

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

WBOY
WBOY原创
2016-06-07 17:40:351068浏览

一个事务复制的bug--更新丢失 描述 === 环境:事务复制的订阅是通过快照进行的初始化 条件: Logreader 没有运行。 操作:我们向 publicaiton 添加了一个新的 Article . 此时在log reader停止期间到完成添加article之前, publication 的 article 出现了更新

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

 

 

   

描述

===

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

条件:Logreader没有运行。

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

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

 

原因

===

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

 

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

Distributionagent包含两个进程,readerwriterReader负责从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 = -

) 

这个存储过程有6个参数,在Transactionalreplication 中,只会使用前4个(并且第三个参数和第四个参数的值是固定不变的.分别为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,如此往复。

 

Distributionagent是不会读取这些新加入的数据的,因为他们"太旧了"(他们的xact_seqno小于订阅的xact_senqo).

 

Log reader停止时, 我们是可以添加article的。 并且相应的操作也会向msrepl_transactionsmsrepl_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内共有四条记录

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn