之前的一篇已经介绍了如何配置复制,介绍了发布者、分发者和订阅者以及事务日志运行的简单关系。其中提到了复制代理,我们这篇将详细介绍复制代理,它是什么?在事务复制的步骤中起到了什么作用?
代理和工作
首先我们要知道事务复制不是被SQLServer数据库引擎执行的,而是被其他外部的服务。这些服务中就包括了SQLServer 复制代理。
复制代理主要包括了快照代理、日志读代理和分发代理。双向复制也使用了队列-读代理。
这些代理可以理解为在复制场景链接服务器并且促使数据移动的Windows 程序。在标准的复制安装过程中,由SQLServer代理来执行代理步骤。SQL Server代理有独立的工作步骤模型(本地分发、远程分发)。除此之外,有一些额外的作业在事务复制的配置阶段将被创建。这些作业主要负责清理任务和探测问题的工作。
接下来我们举例来看一下那些作业将被在那些步骤来创建
本地分发模式
当你设置一个服务器为分发服务器,有几个作业需要被创建。图1 显示了完全的列表,其中只有syspolicy_purge_history 不是复制的作业。所有其他的作业都是被复制创建用来维护的作业。
图1
远程分发模式
当在发布服务器上设置远程分发的时候,只有一个维护作业被创建。如图2所示,这个作业是用来删除在发布服务器上过期的元数据。
图2
发布
复制安装的下一步就是创建发布了,这里需要两个新的作业分在分发数据库。如图3所示,两个的名字叫做“W7A\R2A-ReplA-1” and “W7A\R2A-ReplA-MyFirstPublication-1”代表了日志读和快照两个代理。
图3
通过在SQLServer 代理作业活动监视器中观察category列,你能分辨出这些作业分别代表什么吗?图4所示
图4
推送订阅
对于每一个订阅服务有一个额外的作业,这个作业表示了分发代理,以防推送订阅的作业出问题。你能看到一个实例在图5中。分发作业的名字叫做“W7A\R2A-ReplA-MyFirstPublication-W7C\R2A-2”。在订阅模式下,所有的代理和作业都在分发数据库上。
图5
请求订阅
以防在订阅数据库的分发代理的请求订阅失效,如图6配置,这个代理作业的名称是W7A\R2A-ReplA-MyFirstPublication-W7C\R2A-ReplB-3E02694F-8281-4EBA-81CE-185B3BDE0830”。
图6
如果你打算确认正在工作的分发代理,你可以参考SQL Server代理作业活动监视器中的category 列。如图7
图7
代理
乍看,大量的作业和代理,每一个作何不同事情在不同的时间。但是,当你自己观察会发现仅有三个主要的作业在事务复制中:
快照代理,日志读代理和分发代理。图8给出了三个代理的概览
图8
图中绿色的箭头代表读取,红色箭头表示写入。分发代理在分发数据库还是在订阅服数据库,取决于订阅的模式。
快照代理
快照代理是在快照复制中起到重要作用。在事务复制和其他所有复制类型中,快照代理被用来初始化同步。快照代理不是唯一的初始化同步方式,但是确实是最方便的方式。
创建一个快照包含两个步骤。第一是将所有的订阅端复制对象快照代理的删除和创建的脚本放置在快照文件夹。它生成BCP文件后发表的所有表中的数据,所有生成的文件将被保存在分发数据库,
运行这个语句在Listing1 中的,看看每个BCP文件的条目。
对于快照复制而言当BCP文件被生成时一个共享锁被加在了所有发布的表上。这就允许快照代理去保证了事务的数据一致性,但是它锁住了其他所有同时想去写入表数据的请求。取决于这次涉及的表的大小可能锁的时间是相当大的。在快照复制中这是唯一的方式去保证事务一致性。
事务处理的一致性通过以下几点来保证:
- 一旦快照的进程开始,一个表锁将被加到所有发布包含的表上。然后一个快照进程开始的标识将被写入发布数据库的日志文件里面。在标记记录完以后这个锁将被释放。BCP文件将被生成并不带有表锁。但是更多细粒度且短暂的锁将被将在页或者行级别上。
- BCP文件创建完成后,另一个标记被写入到发布数据库的日志文件中,它标识着快照进程的结束。对于复制的表,所有已提交的更改将被记录在日志文件中且在日志文件中的两个标记中间,然后通过日志读代理复制到发布数据库。
- 当去应用快照到订阅数据库的时候,通过使用之前的脚本在快照文件夹中删除并重建表。然后来自BCP文件的数据被复制到这些表里,同时一个表锁住全部的表。伴随着锁,最后一个环节是分发代理使用快照产生之间捕捉的日志数据来保证所有的表在事务处理一致性。
通过SQL Server默认的为每个发布执行的快招代理创建SQL的代理作业。这些作业的命名依据一下模式:<Server>-<Publication Database>-<Publication>-<number>。当然你也可以手工创建开启一个代理或者安排它过一段时间执行。
日志-读代理
日志-读代理是负责将所有发生改变的发布数据库的对象的事务处理以复制事物日志记录的形式复制到分发数据库。正如我们知道的,每一次数据库任何对象发生变化首先记录到数据库的事务日志中,然后才会将改变实现在真是数据页上面。这是任何关系数据库的原子性的核心部分。
同样的,在复制的发布系统通过将发布的复制对象的改变的事务日志最终发送到订阅数据库的目标对象上。
假如一个DML改变或者DDL改变发生在非发布数据库的发布对象上,则这些改变的日志记录会被标记一个复制的状态,这些非复制对象的将不会被标记也就不会被复制到分发数据库,即使他们在一个事务里面。
假如你已经配置好了复制,请注意你发布数据库的日志文件的大小,你可以使用下面的查询来看是否复制正在阻止日志记录重新使用。假如
log_reuse_wait_desc 列中包含了值R‘REPLICATION’,则复制发生了不被预期的日志增长,写操作将被阻止。
在复制数据库中首次配置复制发布的期间,SQLServer将创建一个单一的SQL代理作业来执行日志-读代理。命名格式如下:<Publisher>-<Publication Database>-<number>。所有其他在这个数据库的发布将重用这个作业。这个作业被默认安排与SQLServer一同启动,根据我们之前的理论这意味着它总是在运行顺序中优先执行,并且你不应该改变这个常规。
分发代理
分发代理负责将数据传送从分发数据库传送到订阅数据库。分发代理连接分发服务器并且读取改变的记录。然后它连接订阅服务器将改变以相同的顺序在再次实现,顺序在单一订阅服务器是被保证的。但是假如你有两个发布在相同的数据库的不同对象上,并且有两个相同订阅数据库的订阅,则顺序只被保证在每一个发布里面,而不再属于独立发布的语句中(如,一个sp关系到两个表的改变,而这两个表属于不同的复制发布,则对于每个表的修改记录是按顺序进行而两个表的之间没有先后顺序)。
按照默认模式,SQLServer创建一个作业为每个订阅去执行分发代理。这个作业有两种执行模式。
(“Push Subscription”) 这种模式的命名管惯例:<Publisher>-<Publication Database>-<Publication>-<Subscriber>-<number>
(“Pull Subscription”)而这种则看起来有点不同:<Publisher>-<Publication Database>-<Publication>-<Subscriber>-<Subscription Database>-<GUID>
Jobs(作业)
正如文章开头提到的那些作业,这些额外的作业是复制系统所需要的,我们应该有所了解主要以下几个,具体的作用请参考MSDN我就不一一解释了,如下:
- Agent history clean up
- Distribution clean up
- Expired subscription clean up
- Replication agents checkup
总结
在这片文章里,我介绍了复制代理作业的内部逻辑,我们能够了解到每个作业代理的目的和作用,这对我们理解复制的细节和优化维护复制有非常大的帮助,尤其是实际生产环境中的特殊情况提供了底层的应对机制。复制作为SQLServer高可用的一个应用功能为跨服务器跨实例跨系统等提供了非常好的实用价值。接下来我将继续深入的了解复制的其他用途和细节。