网上关于sqlserver基于发布/订阅实现数据同步的文章很多,大多介绍不详细,各种copy。为实现发布服务器、订阅服务器数据库实时同步,近期花了几天时间认真研究了一下,并实践验证通过,希望本文能帮助到有同样需求的朋友们。

需求描述:项目部署2台web服务器采用负载均衡,2台db主从数据库,为确保主数据库发生故障时,通过快速切到从数据库服务器,程序不挂掉并且从数据库能最大化还原数据,减少数据丢失,基于sqlserver发布/订阅功能实现主从数据库数据实时同步。

一、发布/订阅配置

1、将主(发布服务器)数据库数据备份并在从(订阅服务器)数据库上还原,保持当前发布服务器和订阅服务器的一致。(此操作简单,这里不详细介绍)

2、新建分布(本文采用的是基于事务发布方式)

(1)发布服务器上新建发布

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql


(2)选择需要发布的数据库,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_02


(3)选择事务发布,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_03


(4)勾选所有的发布对象,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_04


(5)无需筛选发布中数据,直接点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_05


(6)立即创建快照,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_06


(7)安全设置

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_07


(8)输入发布SQL Server登录账户和密码,点击确定

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_08


(9)点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_09


(10)创建发布,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_10


(11)输入发布名称,点击完成

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_服务器_11


发布成功后,在本地SQL server管理工具的,复制->本地发布中,可以查看到刚刚发布的数据库。

3、新建订阅(本文采用的是推送订阅方式)

(1)登录订阅服务器,在订阅服务器中新建订阅

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_12


(2)查找发布服务器

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_13


(3)查找到刚刚做过发布的服务器,并使用发布服务器的登录名和密码,点击连接

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_14


(4)选择刚刚已经发布过的数据库,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_服务器_15


(5)选择在分发服务器上运行所有代理(推送订阅),点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_16


(6)添加订阅数据库,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_17


(7)配置订阅服务器连接属性

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_18


(8)输入发布服务器登录名和密码,点击确定

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_服务器_19


(9)点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_20


(10)代理计划是连续运行,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_数据库_21


(11)初始化时间为立即,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_22


(12)创建订阅,点击下一步

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_23


(13)完成订阅

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_24


完成订阅设置后,在本地SQL server管理工具的,复制->本地订阅中可以查看到刚刚订阅的数据库,以及查看订阅历史记录。

发布/订阅配置成功后,发布服务器数据库中的数据实时同步到订阅服务器数据库, 但发布服务器数据库新增的表并不会自动同步到订阅服务器数据库中。在实际应用中,时常需要新增表、索引,如果采用默认的设置,每次都需要重新初始化快照,从库重新应用快照和未执行的同步命令,从占用网络资源、时间上来说显然不是一种理想的方法。另一种方法是将新增的架构变更新建一个发布订阅,但会造成维护困难,增加出错的几率。

接下来给大家分享一下近期研究的解决办法。

二、发布服务器上新增表自动同步到订阅服务器

1、修改配置参数(通过设置immediate_sync和allow_anonymous 实现不重新初始化快照的前提下新增表。)

immediate_sync:指定每次运行快照代理时是否为发布创建同步文件。如果为 True,表示每次运行快照代理时都创建或重新创建同步文件。 如果为 False,则仅当有新订阅时,才创建同步文件。 当以增量方式向现有发布添加新项目,必须为每个订阅调用 sp_addsubscription。 订阅后订阅服务器无法接收同步文件,直到启动并完成快照代理为止。
allow_anonymous:指定是否可为给定发布创建匿名订阅。 如果为True,则 immediate_synchronization 也必须设置为 True。 如果为 False,则表示不允许对该发布创建匿名订阅。
查看参数值:
USE DH_DG --DH_DG发布数据库
sp_helppublication;
或者:
select immediate_sync ,allow_anonymous from dbo .syspublications;
修改参数值为0:

use DH_DG ; --DH_DG发布数据库
 EXEC sp_changepublication
 @publication = ‘DH_DG’, --发布名称
 @property = ‘allow_anonymous’ ,
 @value = ‘false’
 GO
 EXEC sp_changepublication
 @publication = ‘DH_DG’, --发布名称
 @property = ‘immediate_sync’ ,
 @value = ‘false’
 GO

2、将新增的表(Article)添加到发布、订阅端(基于Job实现实时同步,以下操作均在发布服务器执行)

Job配置如下(注:Job分为2步,步骤1设置“成功时,转到下一步”)

sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_25


sql server 基于ip的发布和订阅 sqlserver订阅发布性能_sql_26


步骤1脚本:

declare @publication varchar(50)
 declare @dbName varchar(50)
 declare @tableName varchar(100)
 declare @sql varchar(max)
 set @publication=‘DH_DG’ --发布名称
 set @dbName=‘DH_DG’ --数据库名称


–游标遍历数据库中的所有表(含主键且不是系统表的表)

DECLARE GRID_CUR CURSOR FOR
 SELECT Name FROM SysObjects Where xtype=‘U’ --xtype=’U’ 表示对象类型为表
 and category<> 2 – category = 2系统表
 and id in (select parent_obj from SysObjects where xtype=‘PK’ --xtype=‘PK’ 含主键的表) ORDER BY Name
 Open GRID_CUR
 Fetch Next From GRID_CUR into @tableName
 while(@@FETCH_STATUS=0)
 begin
 set @sql=’’
 if not exists (select 1 from dbo.sysarticles where name = @tableName) --没有发布的表
 begin


–将新增的表(Article)添加到发布端。

set @sql=‘exec sp_addarticle @publication = N’’’+@publication+’’’,’
 set @sql=@sql+’@article = N’’’+@tableName+’’’,’
 set @sql=@sql+’@source_owner = N’‘dbo’’,’
 set @sql=@sql+’@source_object = N’’’+@tableName+’’’,’
 set @sql=@sql+’@type = N’‘logbased’’,’
 set @sql=@sql+’@description = null,’
 set @sql=@sql+’@creation_script = null,’
 set @sql=@sql+’@pre_creation_cmd = N’‘drop’’,’
 set @sql=@sql+’@schema_option = 0x000000000803509D,’
 set @sql=@sql+’@identityrangemanagementoption = N’‘manual’’,’
 set @sql=@sql+’@destination_table = N’’’+@tableName+’’’,’
 set @sql=@sql+’@destination_owner = N’‘dbo’’,’
 set @sql=@sql+’@vertical_partition = N’‘false’’,’
 set @sql=@sql+’@force_invalidate_snapshot = 1,’
 set @sql=@sql+’@ins_cmd = N’‘CALL sp_MSins_dbo’++@tableName+’’’,’
 set @sql=@sql+’@del_cmd = N’‘CALL sp_MSdel_dbo’++@tableName+’’’,’
 set @sql=@sql+’@upd_cmd = N’‘SCALL sp_MSupd_dbo’++@tableName+’’’;’
 exec(@sql)

–将新增的表(Article)添加到订阅端。
exec sp_addsubscription @publication=@publication,
@article=@tableName,
@subscriber=‘DTH_DB2’, --订阅服务器机器名
@destination_db=‘DH_DG’, --订阅数据库
@reserved=‘Internal’ –内部保留字段,默认值为‘reserved’,官方帮助文档上似乎也查不到,挺坑的,这里必须设置为‘Internal’,有兴趣的朋友可以去国外网站搜搜。
end
Fetch Next From GRID_CUR into @tableName
end
Close GRID_CUR
deallocate GRID_CUR

步骤2脚本:

3、重新启动可为发布生成初始快照的快照代理作业 。

if exists (select 1 from dbo.syssubscriptions where dest_db=‘DH_DG’ AND status<>2) --status=2订阅状态为使用中
begin
exec sp_startpublication_snapshot @publication=‘DH_DG’ --发布名称
End

注:以上将新增的表(Article)添加到发布端、订阅端语句执行效率高,占用资源少,我这里设置Job是每分钟执行一次,如对实时性要求更高,可进一步调整作业计划属性设置,无需担心Job影响数据库系统性能。

至此,完美实现发布数据库与订阅数据库数据的实时同步。