1. 程式人生 > >SQL Server Replication II

SQL Server Replication II

Sql Server Replication Scripting Setup

  1. 大概的一個拓撲, 我們將三種角色分別安裝在三臺不同的 sql server 伺服器上
    1.1 distributor
    1.2 publisher, publication, article
    1.3 subscriber , subscription
    1.4 Agents , Schedulers

  2. 簡單的一個實現, 以 snapshot replication 為例子

2.1 distributor script :
我們會在 distributor 角色的 sql server 伺服器上,將這臺伺服器設定為 distributor ,建立 distribution 資料庫, 並配置一個允許使用它作為 distributor 的 publisher。

2.1.1 sp_adddistributor 第一次執行的時候,必須指定password, 這個 password 是 distributor_admin 密碼。 在 publisher 連線 distributor 的時候,也必須指定這個 distributor_admin 的密碼,用來通訊。下面這個例子其實還需要為 sp_adddistributor 引數 @password 賦值.

2.1.2 三大要素: distributor 所用到的 Instance , 以 serverName\instanceName 命名; distributor 用到的資料庫 distribution (名字可以更改); Snapshot 用到的儲存路徑.

-- This script uses sqlcmd scripting variables. They are in the form
-- $(MyVariable). For information about how to use scripting variables
-- on the command line and in SQL Server Management Studio, see the
-- "Executing Replication Scripts" section in the topic
-- "Programming Replication Using System Stored Procedures"
.
-- Install the Distributor and the distribution database.
DECLARE @distributor AS sysname;
DECLARE @distributionDB AS sysname;
DECLARE @publisher AS sysname;
DECLARE @directory AS nvarchar(500);
DECLARE @publicationDB AS sysname;
-- Specify the Distributor name.
SET @distributor = $(DistPubServer);
-- Specify the distribution database.
SET @distributionDB = N'distribution';
-- Specify the Publisher name.
SET @publisher = $(DistPubServer);
-- Specify the replication working directory.
SET @directory = N'\\' + $(DistPubServer) + '\repldata';
-- Specify the publication database.
SET @publicationDB = N'AdventureWorks2008R2';
-- Install the server MYDISTPUB as a Distributor using the defaults,
-- including autogenerating the distributor password.
USE master
EXEC sp_adddistributor @distributor = @distributor;
-- Create a new distribution database using the defaults, including
-- using Windows Authentication.
USE master
EXEC sp_adddistributiondb @database = @distributionDB,
@security_mode = 1;
GO
-- Create a Publisher and enable AdventureWorks2008R2 for replication.
-- Add MYDISTPUB as a publisher with MYDISTPUB as a local distributor
-- and use Windows Authentication.
DECLARE @distributionDB AS sysname;
DECLARE @publisher AS sysname;
-- Specify the distribution database.
SET @distributionDB = N'distribution';
-- Specify the Publisher name.
SET @publisher = $(DistPubServer);
USE [distribution]
EXEC sp_adddistpublisher @publisher=@publisher,
@distribution_db=@distributionDB,
@security_mode = 1;
GO

2.2 publication script , article script

2.2.1 首先要做的兩點,就是:一啟動 publisher 的角色;二配置要使用的 distributor . 這裡使用到的儲存過程 sp_replicationdboption .

2.2.2 在第一步裡指定的 replication database, 執行 sp_addpublication 來新增 publication.

-- Create a new transactional publication with the required properties.
EXEC sp_addpublication
@publication = @publication,
@status = N'active',
@allow_push = N'true',
@allow_pull = N'true',
@independent_agent = N'true';
-- Create a new snapshot job for the publication, using a default schedule.
EXEC sp_addpublication_snapshot
@publication = @publication,
@job_login = @login,
@job_password = @password,
-- Explicitly specify the use of Windows Integrated Authentication (default)
-- when connecting to the Publisher.
@publisher_security_mode = 1;
GO

2.2.3 新增 article

DECLARE @publication AS sysname;
DECLARE @table AS sysname;
DECLARE @filterclause AS nvarchar(500);
DECLARE @filtername AS nvarchar(386);
DECLARE @schemaowner AS sysname;
SET @publication = N'AdvWorksProductTran';
SET @table = N'Product';
SET @filterclause = N'[DiscontinuedDate] IS NULL';
SET @filtername = N'filter_out_discontinued';
SET @schemaowner = N'Production';
-- Add a horizontally and vertically filtered article for the Product table.
-- Manually set @schema_option to ensure that the Production schema
-- is generated at the Subscriber (0x8000000).
EXEC sp_addarticle
@publication = @publication,
@article = @table,
@source_object = @table,
@source_owner = @schemaowner,
@schema_option = 0x80030F3,
@vertical_partition = N'true',
@type = N'logbased',
@filter_clause = @filterclause;
-- (Optional) Manually call the stored procedure to create the
-- horizontal filtering stored procedure. Since the type is
-- 'logbased', this stored procedures is executed automatically.
EXEC sp_articlefilter
@publication = @publication,
@article = @table,
@filter_clause = @filterclause,
@filter_name = @filtername;
-- Add all columns to the article.
EXEC sp_articlecolumn
@publication = @publication,
@article = @table;
-- Remove the DaysToManufacture column from the article
EXEC sp_articlecolumn
@publication = @publication,
@article = @table,
@column = N'DaysToManufacture',
@operation = N'drop';
-- (Optional) Manually call the stored procedure to create the
-- vertical filtering view. Since the type is 'logbased',
-- this stored procedures is executed automatically.
EXEC sp_articleview
@publication = @publication,
@article = @table,
@filter_clause = @filterclause;
GO

2.3 subscription script 以 push subscription 為例子. 所有的操作都在publisher, publication 裡面執行。

2.3.1 判斷 publication 是不是可以被 push 或者 pull
Sp_helppublication
2.3.3 新增 push subscription
Sp_addsubscription
2.3.4 新增 push distributor agent
Sp_addpushsubscription_agent
預設是一天執行一次 snapshot push over ,那麼怎麼去修改這個同步間隔呢?
Sp_add_schedule

  1. 監控健康指標
    3.1 Replication Monitor

  2. 移除 replication , 察看 distribution 資料庫元資料的更改

4.1 先移除 subscriber 和 subscription
Sp_dropsubscription( publication database), sp_subscription_cleanup(subscriber database)

4.2 再移除 publisher 和 publication

4.3 再移除 distributor
4.4 細節解說

To disable publishing and distribution
Stop all replication-related jobs. For a list of job names, see the “Agent Security Under SQL Server Agent” section of Replication Agent Security Model.
At each Subscriber on the subscription database, execute sp_removedbreplication to remove replication objects from the database. This stored procedure will not remove replication jobs at the Distributor.
At the Publisher on the publication database, execute sp_removedbreplication to remove replication objects from the database.
If the Publisher uses a remote Distributor, execute sp_dropdistributor.
At the Distributor, execute sp_dropdistpublisher. This stored procedure should be run once for each Publisher registered at the Distributor.
At the Distributor, execute sp_dropdistributiondb to delete the distribution database. This stored procedure should be run once for each distribution database at the Distributor. This also removes any Queue Reader Agent jobs associated with the distribution database.
At the Distributor, execute sp_dropdistributor to remove the Distributor designation from the server.

當Publisher, Distributor, Subscriber都配置好以後,我們可以通過下面的指令碼來檢視各個伺服器充當的角色,以及配置的屬性:

  1. 檢視伺服器的角色:
select server_id,name ,is_remote_login_enabled,is_system,is_publisher,is_subscriber,is_distributor,is_nonsql_subscriber from sys.servers ;
select name,is_published,is_subscribed,is_merge_published,is_distributor from sys.databases where name in( 'siebeldb','distribution')

配置原理詳細解析:

**

1. Distributor :

** Distributor在每一個replication環境中都必須存在,它的作用是儲存snapshot replication, 在publisher, subscriber之間通訊,從publisher接收replication,並分發到各個subscriber上。在配置distributor的時候,特別需要注意的兩件事就是配置儲存snapshot replication檔案的資料夾,第二就是指定是否是遠端distributor,一般來說都會用一個專門的server來做distributor,來隔離與業務系統的資源利用衝突。

Step 1 指定一個server為distributor角色

     sp_adddistributor [ @distributor= ] 'distributor'   
[ , [ @heartbeat_interval= ] heartbeat_interval ]
[ , [ @password= ] 'password' ]
[ , [ @from_scripting= ] from_scripting ]

[ @distributor=] ‘distributor’ Is the distribution server name. distributor is sysname, with no default. This parameter is only used if setting up a remote Distributor. It adds entries for the Distributor properties in the msdb..MSdistributor table.

如果distributor對於publisher來說是臺遠端伺服器,不是本機instance上的伺服器,那麼我們就需要配置@distributor這個引數。相關屬性的值也會被記錄在MSDB..Msdistributor表裡面。特別需要注意的是,這個命令是執行在distributor上面的,而不是用來給publisher新增一個distributor。這個命令會將本伺服器標示為distributor,並且在MSDB..Msdistributor裡面新增一個distributor的配置資訊,如果是單獨的一臺伺服器,那麼就會給這個伺服器貼一個專門是distributor的標籤。既然已經涉及到伺服器層面,這就意味著整個instance就只能配置一臺資料庫專用來做distribution.

[ @heartbeat_interval=] heartbeat_interval
Is the maximum number of minutes that an agent can go without logging a progress message. heartbeat_interval is int, with a default of 10 minutes. A SQL Server Agent job is created that runs on this interval to check the status of the replication agents that are running.

這裡的心跳設定用來檢查replication各個代理之間通訊的狀況,預設是10分鐘。當新加一個distributor之後會自動建立一個Job來實現心跳的功能。這個屬性會在MSDB..Msdistributor表裡面記錄下來。

[ @password=] ‘password’]
Is the password of the distributor_admin login. password is sysname, with a default of NULL. If NULL or an empty string, password is reset to a random value. The password must be configured when the first remote distributor is added. distributor_admin login and password are stored for linked server entry used for a distributor RPC connection, including local connections. If distributor is local, the password for distributor_admin is set to a new value. For Publishers with a remote Distributor, the same value for password must be specified when executing sp_adddistributor at both the Publisher and Distributor. sp_changedistributor_password can be used to change the Distributor password.

如果Distributor是建立在遠端伺服器上的,那麼我們需要為distributor_admin這個使用者設定一個密碼。這個密碼在publisher配置distributor的時候,也需要指定。

[ @from_scripting= ] from_scripting
Identified for informational purposes only. Not supported. Future compatibility is not guaranteed.
返回值:0-成功;1-失敗

上面的指令碼還只是用來配置一個角色,但是這個角色對應的資料庫還沒有真正建立起來,下面的指令碼就是用來建立distributor資料庫的,而且事先我們不需要這個資料庫存在。

這裡要思考的問題是:1同一個instance上面可以建立多少個distribution資料庫?2同一個distribution資料庫可以支撐多少個publisher?

Step 2 建立一個distribution資料庫

下面這個指令碼是執行在distributor上的,為distributor建立一個distribution資料庫,這個資料庫的名字當然是可以任意指定的。前提是必須先執行sp_adddistributor配置distributor.

sp_adddistributiondb [ @database= ] 'database'   
    [ , [ @data_folder= ] 'data_folder' ]   
    [ , [ @data_file= ] 'data_file' ]   
    [ , [ @data_file_size= ] data_file_size ]   
    [ , [ @log_folder= ] 'log_folder' ]   
    [ , [ @log_file= ] 'log_file' ]   
    [ , [ @log_file_size= ] log_file_size ]   
    [ , [ @min_distretention= ] min_distretention ]   
    [ , [ @max_distretention= ] max_distretention ]   
    [ , [ @history_retention= ] history_retention ]   
    [ , [ @security_mode= ] security_mode ]   
    [ , [ @login= ] 'login' ]   
    [ , [ @password= ] 'password' ]   
    [ , [ @createmode= ] createmode ]  
    [ , [ @from_scripting = ] from_scripting ]  

[ @min_distretention=] min_distretention
Is the minimum retention period, in hours, before transactions are deleted from the distribution database. min_distretention is int, with a default of 0 hours.
[ @max_distretention=] max_distretention
Is the maximum retention period, in hours, before transactions are deleted. max_distretention is int, with a default of 72 hours. Subscriptions that have not received replicated commands that are older than the maximum distribution retention period are marked as inactive and need to be reinitialized. RAISERROR 21011 is issued for each inactive subscription. A value of 0 means that replicated transactions are not stored in the distribution database.

@min_distretention, @max_distretention, 指的是為重複事務保留的最小,最大時間長。如果某一個subscriber連最大值之前的重複日誌都沒有接收的話,這個subscriber就被標識為inactive,需要重新reinitialized.

[ @history_retention=] history_retention
Is the number of hours to retain history. history_retention is int, with a default of 48 hours.
[ @security_mode=] security_mode
Is the security mode to use when connecting to the Distributor. security_mode is int, with a default of 1. 0 specifies SQL Server Authentication; 1specifies Windows Integrated Authentication.
指定為0 ,表示採用的安全認證方式是SQL SERVER帳戶認證;如果為1,說明採用的是Windows Server認證方式。值得思考的是,我們怎麼可以指定這個資料庫是既可以用Windows認證也可以用SQL Server帳戶認證?

[ @login=] ‘login’
Is the login name used when connecting to the Distributor to create the distribution database. This is required if security_mode is set to 0. login issysname, with a default of NULL.
只有當Security_Mode指定為0的時候,需指定這個引數值。

[ @password=] ‘password’
Is the password used when connecting to the Distributor. This is required if security_mode is set to 0. password is sysname, with a default of NULL.

[ @createmode=] createmode
createmode is int, with a default of 1, and can be one of the following values.
這個引數預設是1,建立資料庫或者使用現有的資料庫,然後在這些資料庫上呼叫instdist.sql來建立一些replication的物件,包括原資料表,儲存過程,試圖等。

雖說我們可以在配置這個distributor對應的資料庫時候,直接建立資料庫,但是我們還是傾向於先常規的建立一個數據庫,指定一些特別的引數,然後配置這個資料庫為distributor database.

當然我們要查詢是不是distributor搭建成功,來決定是否需要配置其它的專案:

exec sp_get_distributor ;

返回一個數據集;
- Distribution db installed: distribution資料庫是不是建立完成
- Is distribution publisher: distribution, publisher是不是在同一個instance上面
- Has remote distribution publisher:是否有遠端伺服器資料庫作為Publisher存在

搭建完成distributor的時候我們需要再次檢查屬性配置或者我們新接手了一個repliaction環境需要熟悉這些配置,我們可以用下面的T-SQL指令碼:
- 返回distributor, distribution資料庫, working directory的配置資訊: sp_helpdistributor ;
- 返回指定distribution資料庫的資訊: sp_helpdistributiondb

這兩個指令碼可以返回很多有用的資訊,比如snapshot file location(working directory), history cleanup agent job , distribution cleanup agent job, 用來給publisher配置distributor的server name, login name等。

如果需要更改這些屬性,可以用下面的指令碼來執行:
1. At the Distributor, execute sp_changedistributor_propertyto modify Distributor properties.
2. At the Distributor, execute sp_changedistributiondbto modify distribution database properties.
3. At the Distributor, execute sp_changedistributor_passwordto change the Distributor password.
4. At the Distributor, execute sp_changedistpublisherto change the properties of a Publisher using the Distributor.

Step 3 指定一個publisher為distributor支援的 publisher

sp_adddistpublisher [ @publisher= ] 'publisher'   
        , [ @distribution_db= ] 'distribution_db'   
    [ , [ @security_mode= ] security_mode ]   
    [ , [ @login= ] 'login' ]   
    [ , [ @password= ] 'password' ]   
    [ , [ @working_directory= ] 'working_directory' ]   
    [ , [ @trusted= ] 'trusted' ]   
    [ , [ @encrypted_password= ] encrypted_password ]   
    [ , [ @thirdparty_flag = ] thirdparty_flag ]  
    [ , [ @publisher_type = ] 'publisher_type' ]  

這個指令碼可以在distributor角色伺服器的任何資料庫上執行,因為distributing replication(分發副本)這個操作是伺服器級別的,所以這個指令碼一系列操作的本質也是作用在伺服器上,因此在哪個資料內執行這個命令就無所謂了。

  1. @publisher這個引數尤其要注意,暫不敢確定到底是Publisher的instance名稱還是其它
  2. @thirdparty_flag, @publisher_type兩個引數用來指定publisher是不是非SQL SERVER資料庫
  3. @working_directory,就是snapshot replication存在的地方

Step 4 為publisher配置一個可用的distributor(僅用在分散式replication中)

指定一個被distributor支援的publisher,和為publibsher配置一個可用的distributor是一個連通的過程,相當於企業之間互相簽訂合同一樣,雙方各執一份。在publisher上配置一個distributor的命令和在distributor上配置一個distributor一樣:

sp_adddistributor [ @distributor= ] 'distributor'   
    [ , [ @heartbeat_interval= ] heartbeat_interval ]   
    [ , [ @password= ] 'password' ]   
[ , [ @from_scripting= ] from_scripting ]  

這裡password就起到認證授權的作用了。

因為每增加一個distributor都會往sys.servers表裡寫入一個象徵性的伺服器名一樣,這裡面的伺服器名帶著各自的instance名稱,同時我們會給distributor所在的伺服器定義一個名稱,比如repl_distributor。 這個名稱很重要,暫時我們可以理解為是一臺伺服器的名稱,其它伺服器或者客戶端都可以通過這個名稱來連線,實際上是用在replication架構中。

Step 5 配置publisher,distributor, subscriber資料庫的元資料

sp_replicationdboption [ @dbname= ] 'db_name'   
        , [ @optname= ] 'optname'   
        , [ @value= ] 'value'   
    [ , [ @ignore_distributor= ] ignore_distributor ]  
    [ , [ @from_scripting = ] from_scripting ]  

@optname,可以是:
- Merge publish: 指定資料庫可以用作merge publication
- Publish:除了merge publish之外的publication
- Subscriber:指定資料庫為subscription資料庫
- Sync with backup
@value: false, 丟棄某個資料庫的角色;true,設定某個資料庫的角色
@ignore_distributor: false,可以不連線distributor來更新資訊,比如若想丟棄publication資料庫角色,而distributor又連不通,就需要false.

**

2 Publisher :

** 通過publication,我們可以將publisher資料庫裡的資料以及資料庫物件釋出到其它伺服器的指定資料庫裡面,有些物件在merge publication中不適用,比如stored procedures –Execution(Transact-SQL, CLR), Indexed Views as Tables,除此之外,其它物件都可以在三種publication中使用,這些物件可以是 :

Tables, Partitioned Tables, Stored Procedures – Definition (Transact-SQL and CLR), Views, Indexed Views, User-Defined Types (CLR), User-Defined Functions (Transact-SQL and CLR), Alias Data Types, Full text indexes, Schema Objects (constraints, indexes, user DML triggers, extended properties, and collation).

在沒有通過查詢MSDN來獲取publish細節之前,我們先自我假設下,正確搭建一個Publisher來publish一些Publication, 大概需要哪些步驟?
- 正確搭建一個distributor
- 在distributor上增加一個publisher的認證:sp_adddistpublisher
- 在publisher上指定我們要做publish的資料庫
- 在publisher上配置我們要使用的distributor
- 建立一份publication
- 釋出publication

這是replication架構的前半部分配置,之後還需要配置subscriber和subscription。最後需要配置的是讀寫分離的邏輯實現,概念參見《構建高效能Web站點》郭欣(著),採用了HAProxy機制,對讀寫SQL進行路由分離,寫的SQL都放到publisher伺服器上,而讀SQL都轉到subscriber伺服器上,對subscriber做Network Load Balance.

步驟一寫出來就知道自己往什麼方向著手了,建立一份publication是有講究的,怎麼建立,哪些物件是可以被published的,都有哪些方式,怎麼做全量,怎麼做增量,publication的定義都儲存在哪裡? Publication的pipeline,過程控制的點,頻率怎麼控制,延遲如何管控,在本節都需要詳細地闡述。

Publisher可以是和distributor在同一個instance上面,也可以是遠端伺服器上的某一個instance。搭建本地publisher和遠端publisher的區別在哪裡?

首先我們先來看下本地Publisher怎麼搭建:
- 先搭建一個distributor,配置distributor伺服器屬性,建立distribution資料庫
- 在distributor上指定一個publisher的認證sp_adddistpublisher
- 在distributor上指定一個數據庫為publication資料庫,設定某一種特定的publication方式,snapshot replication, transaction replication,merge replication

接著再分析下遠端Publisher怎麼搭建:
- 先搭建一個distributor,配置distributor伺服器屬性,建立distribution資料庫
- 在distributor上指定一個publisher的認證sp_adddistpublisher
- 在publisher上配置一個distributor,指定一個數據庫為publication資料庫,設定某一種特定的publication方式,snapshot replication, transaction replication,merge replication

Distributor和publisher其實就類似內容生產商與分銷商,必須一一簽訂合同。本地關係就簡單些,遠端關係就雙方人手一份合同,有趣的是授權認證的方式,如果雙方是通過私人掮客簽訂合同的,那麼需要同一個掮客來回搭線,類似於security model為0,使用SQL SERVER 帳戶密碼;如果雙方是通過中介公司簽訂合同的,那麼同一個公司的任何業務員都能辦理這樁事,所以security model可以設定為1,使用Windows帳戶認證。

假如我現在已經搭好了distributor,也指定了publisher,無論是本地的還是遠端的,那麼這些元資料儲存在哪裡? 既然distributor,publisher都簽訂了合同,那麼雙方都應該有儲存,這份儲存就是我們要找的東西。

  • GUI方式: SSMS – Replication-Replication Monitor ; SQL Command prompt:sqlmonitor.exe
  • T-SQL方式:
    sp_replmonitorhelppublisher
    sp_replmonitorhelppublisher [ [ @publisher = ] ‘publisher’ ]
    [ , [ @refreshpolicy = ] refreshpolicy ]
    @publisher可以指定一個具體的伺服器名,也可以不設定,返回包括所有的publisher。 返回的結果集要注意的就是status欄位,它 有6個可能值,意思分別是: 1: started; 2:succeeded; 3:In progress; 4:Idle ;5:Retrying ;6:Failed .
    exec sp_helpdistributor

既然我們說了是雙方合同,那麼publisher上也應該有副本存在,sp_helpdistributor就可以幫我們查詢到使用的distributor資訊。

關於publication:

use distribution
go
exec sp_replmonitorhelppublication

上面這個指令碼只能用來看哪些Publication 存在,以及對應的Job,但是publication具體定義看不到.

上面的說明討論都還只是第一步,還沒有進入到建立publication階段,所以稱之為準備階段。接下來就討論publication階段了。
不同的publication使用的命令方式不同,總體上分為兩種: snapshot或者transactional publication;merge publication. 在建立snapshot, transactional publication的時候我們使用sp_addpublication.

sp_addpublication [ @publication = ] 'publication'  
    [ , [ @taskid = ] tasked ]  
    [ , [ @restricted = ] 'restricted' ]  
    [ , [ @sync_method = ] 'sync_method' ]  
    [ , [ @repl_freq = ] 'repl_freq' ]  
    [ , [ @description = ] 'description' ]  
    [ , [ @status = ] 'status' ]  
    [ , [ @independent_agent = ] 'independent_agent' ]  
    [ , [ @immediate_sync = ] 'immediate_sync' ]  
    [ , [ @enabled_for_internet = ] 'enabled_for_internet' ]  
    [ , [ @allow_push = ] 'allow_push'  
    [ , [ @allow_pull = ] 'allow_pull' ]  
    [ , [ @allow_anonymous = ] 'allow_anonymous' ]  
    [ , [ @allow_sync_tran = ] 'allow_sync_tran' ]  
    [ , [ @autogen_sync_procs = ] 'autogen_sync_procs' ]  
    [ , [ @retention = ] retention ]  
    [ , [ @allow_queued_tran= ] 'allow_queued_updating' ]  
    [ , [ @snapshot_in_defaultfolder= ] 'snapshot_in_default_folder' ]  
    [ , [ @alt_snapshot_folder= ] 'alternate_snapshot_folder' ]  
    [ , [ @pre_snapshot_script= ] 'pre_snapshot_script' ]  
    [ , [ @post_snapshot_script= ] 'post_snapshot_script' ]  
    [ , [ @compress_snapshot= ] 'compress_snapshot' ]  
    [ , [ @ftp_address = ] 'ftp_address' ]  
    [ , [ @ftp_port= ] ftp_port ]  
    [ , [ @ftp_subdirectory = ] 'ftp_subdirectory' ]  
    [ , [ @ftp_login = ] 'ftp_login' ]  
    [ , [ @ftp_password = ] 'ftp_password' ]  
    [ , [ @allow_dts = ] 'allow_dts' ]  
    [ , [ @allow_subscription_copy = ] 'allow_subscription_copy' ]  
    [ , [ @conflict_policy = ] 'conflict_policy' ]  
    [ , [ @centralized_conflicts = ] 'centralized_conflicts' ]   
    [ , [ @conflict_retention = ] conflict_retention ]  
    [ , [ @queue_type = ] 'queue_type' ]  
    [ , [ @add_to_active_directory = ] 'add_to_active_directory' ]  
    [ , [ @logreader_job_name = ] 'logreader_agent_name' ]  
    [ , [ @qreader_job_name = ] 'queue_reader_agent_name' ]  
    [ , [ @publisher = ] 'publisher' ]   
    [ , [ @allow_initialize_from_backup = ] 'allow_initialize_from_backup' ]  
    [ , [ @replicate_ddl = ] replicate_ddl ]  
    [ , [ @enabled_for_p2p = ] 'enabled_for_p2p' ]  
    [ , [ @publish_local_changes_only = ] 'publish_local_changes_only' ]  
    [ , [ @enabled_for_het_sub = ] 'enabled_for_het_sub' ]  
    [ , [ @p2p_conflictdetection = ] 'p2p_conflictdetection' ]  
    [ , [ @p2p_originator_id = ] p2p_originator_id  
    [ , [ @p2p_continue_onconflict = ] 'p2p_continue_onconflict'  
    [ , [ @allow_partition_switch = ] 'allow_partition_switch'  
    [ , [ @replicate_partition_switch = ]'replicate_partition_switch'  

定義好一個publication,就要為publication增加article的定義,然後建立一個publication的snapshot,執行完這個snapshot的生成,接著就可以做transactional的增量了。
所以這裡的問題就在於publication是否定為Transactional還是Snapshot了。不論是否定義publication為Transactional還是Snapshot,我們都需要做的一步就是生成這份Publication的Snapshot.

  • Sp_addpublication來定一個publication
    怎麼控制這個publication是snapshot, transactional, merge publication? 首先在增加publication之前,我們應該先指定一個釋出資料庫 ,使用sp_repliactiondboption來啟用某一個數據庫的釋出功能。

如果我們需要建立的是transactional replication,我們還需要建立一個logReader Agent(Job).
執行sp_addlogreader_agent來新增這個Agent Job,執行sp_helplogreader_agent可以查詢到我們新建的這個Agent job. 每一個publication database只能有一個同賬戶的log reader agent job, 如果是非sql server資料庫的publiaction database,那麼必須設定特定賬戶使用者及密碼,而且連線publisher的授權認證模式也必須是0,@publisher_security_mode = 0.

接下來我們新增publication. 執行sp_addpublication, 設定是否可以被pull, push, 設定@repl_freq,為snapshot replication設定snapshot, 為transactional replication設定continuous. Transactional replication是預設值

這裡摘抄MSDN上的一個小例子:

-- To avoid storing the login and password in the script file, the values 
-- are passed into SQLCMD as scripting variables. For information about 
-- how to use scripting variables on the command line and in SQL Server
-- Management Studio, see the "Executing Replication Scripts" section in
-- the topic "Programming Replication Using System Stored Procedures".
DECLARE @publicationDB AS sysname;
DECLARE @publication AS sysname;
DECLARE @login AS sysname;
DECLARE @password AS sysname;
SET @publicationDB = N'AdventureWorks'; 
SET @publication = N'AdvWorksProductTran'; 
-- Windows account used to run the Log Reader and Snapshot Agents.
SET @login = $(Login); 
-- This should be passed at runtime.
SET @password = $(Password); 
-- Enable transactional or snapshot replication on the publication database.
EXEC sp_replicationdboption 
  @dbname=@publicationDB, 
  @optname=N'publish',
  @value = N'true';
-- Execute sp_addlogreader_agent to create the agent job. 
EXEC sp_addlogreader_agent 
  @job_login = @login, 
  @job_password = @password,
  -- Explicitly specify the use of Windows Integrated Authentication (default) 
  -- when connecting to the Publisher.
  @publisher_security_mode = 1;
-- Create a new transactional publication with the required properties. 
EXEC sp_addpublication 
  @publication = @publication, 
  @status = N'active',
  @allow_push = N'true',
  @allow_pull = N'true',
  @independent_agent = N'true';
-- Create a new snapshot job for the publication, using a default schedule.
EXEC sp_addpublication_snapshot 
  @publication = @publication, 
  @job_login = @login, 
  @job_password = @password,
  -- Explicitly specify the use of Windows Integrated Authentication (default) 
  -- when connecting to the Publisher.
  @publisher_security_mode = 1;
GO
  • Sp_addpublication_snpashot來定義一個publication的snapshot
    為什麼要定義這個publication的snapshot,既然可以生成snapshot,為什麼還需要定義它,而不直接從publication中生成snapshot? 連著上面的分析,可知預設情況下,publication是transactional級別的,所以並沒有一個全量的snapshot給到我們新建的transactional publication, 所以這裡要為transactional publication新建一個snapshot. 其二,無論publication定義為哪種publication,都只是定義,沒有實際執行的執行者。

這個地方隱藏的一點就是,當執行完這個命令之後,就新建了一個snapshot agent job.
這個snapshot的agent job建立,必須是在publisher database上進行,當我們為某一個publication建立一個snapshot agentj job的時候,publisher通過與distributor通訊,把這個新建的agent job註冊到了distributor。 如果是在非Publisher資料庫上執行,則會出現下面的錯誤:
Msg 18757, Level 16, State 1, Procedure sp_MSrepl_addpublication_snapshot, Line 76
Unable to execute procedure. The database is not published. Execute the procedure in a database that is published for replication.

  • Sp_addarticle來往publication裡面新增需要複製的物件和資料
    這麼說來,publication與article之間是一對多的關係。而article是肯定不能被包含在不同的publication之間的,如果被包含在不同的publication之間,同步邏輯該怎麼寫?

我們以MSDN上的一個例子來闡述:
https://msdn.microsoft.com/en-us/library/ms173857.aspx
為sp_addarticle指定的引數主要有:
@publication: 一個數據庫可能有多個publication,在這裡我們要指定某一個具體的資料庫裡已有的publication;
@article: 指定一個 article名稱;
@source_object:來指定要同步的物件
@destination_table: 如果target table/stored procedure不是同一個名字,就需要指定;
@type有很多種,比如logbased,同步表的時候就要指定logbased了;
@ins_cmd, @del_cmd,@upd_cmd就是用來更改同步邏輯的。詳細參考:Specify How Changes Are Propagated for Transactional Articles ( https://msdn.microsoft.com/en-us/library/ms152489.aspx).

DECLARE @publication    AS sysname;
DECLARE @table AS sysname;
DECLARE @filterclause AS nvarchar(500);
DECLARE @filtername AS nvarchar(386);
DECLARE @schemaowner AS sysname;
SET @publication = N'AdvWorksProductTran'; 
SET @table = N'Product';
SET @filterclause = N'[DiscontinuedDate] IS NULL'; 
SET @filtername = N'filter_out_discontinued';
SET @schemaowner = N'Production';
-- Add a horizontally and vertically filtered article for the Product table.
-- Manually set @schema_option to ensure that the Production schema 
-- is generated at the Subscriber (0x8000000).
EXEC sp_addarticle 
  @publication = @publication, 
  @article = @table, 
  @source_object = @table,
  @source_owner = @schemaowner, 
  @schema_option = 0x80030F3,
  @vertical_partition = N'true', 
  @type = N'logbased',
  @filter_clause = @filterclause;
-- (Optional) Manually call the stored procedure to create the 
-- horizontal filtering stored procedure. Since the type is 
-- 'logbased', this stored procedures is executed automatically.
EXEC sp_articlefilter 
  @publication = @publication, 
  @article = @table, 
  @filter_clause = @filterclause, 
  @filter_name = @filtername;
-- Add all columns to the article.
EXEC sp_articlecolumn 
  @publication = @publication, 
  @article = @table;
-- Remove the DaysToManufacture column from the article
EXEC sp_articlecolumn 
  @publication = @publication, 
  @article = @table, 
  @column = N'DaysToManufacture', 
  @operation = N'drop';
-- (Optional) Manually call the stored procedure to create the 
-- vertical filtering view. Since the type is 'logbased', 
-- this stored procedures is executed automatically.
EXEC sp_articleview 
  @publication = @publication, 
  @article = @table,
  @filter_clause = @filterclause;
GO

Msg 156, Level 15, State 1: Incorrect syntax near the keyword ‘from’.
Msg 21745, Level 16, State 1, Procedure sp_MSrepl_articleview, Line 301
Cannot generate a filter view or procedure. Verify that the value specified for the @filter_clause parameter of sp_addarticle can be added to the WHERE clause of a SELECT statement to produce a valid query.
Msg 20027, Level 11, State 1, Procedure sp_MSrepl_articlecolumn, Line 181
The article ‘region’ does not exist.
如果沒有使用任何的條件篩選,我們就不要在sp_addarticle裡面指定filter,要不然就出現上面的錯誤。

  • Sp_startpubliaction_snapshot來生成一份publication snapshot
    這份publication snapshot是由什麼來生成的,如果是snapshot replication,那麼可以理解每次replication都是全量抽取的,如果是transactional repliaction,則這份snapshot應該只生成一次。
    由於snapshot生成一次耗時,耗網路寬頻,如果基於資料庫作snapshot還要鎖表,不適合用來做日常的同步更新,這裡我們要設定snapshot Agent job只跑一次。

在執行這段指令碼的時候,特別要注意 job的執行者對working directory有可讀可寫許可權,如果沒有,我們可以修改這working directory :

exec sp_changedistpublisher
@publisher = 'VM-B9CB-CD02\MSSQLSERVER2014',
@property = 'working_directory',
@value = 'E:\Data_BU\snapshot' ;
--D:\data\data_srv\dbagroup\SQL2014\MSSQL12.MSSQLSERVER2014\MSSQL\ReplData

上面的指令碼就是用來改寫working directory.

  • Transactional Publication, Snapshot Publication是怎麼驅動replication的
    我們知道replication,可以用push,pull的方式來進行,那麼在publisher伺服器上我們定義好publication, 新增完我們需要同步的物件與資料, 到這裡配置Publication的工作就結束了
    當subscription也配置好之後,我們就可以啟動相應的Agent Job來啟用replication.

**

3 Subscriber:

**從訂閱者的角度來說,主要做的事情就是pull publication,就是主動拉取publication. 那麼Publisher要推publication該怎麼配置? 一份subscription把publisher與subscriber連線起來,首先在distributor上肯定是定義一些subscribers,subscriber上是不是也需要授權distributor可以訪問? 然後為每個subscriber配置一些subscription,在這個步驟中應該可以指定這份subscription是pull還是push形式,頻率有多少。
- Synchronization agent : 同步代理Job在pull subscription時候,執行在subscriber伺服器上,在push subcription的時候,執行在distributor伺服器上:

不管哪種subscription方式,總有一樣事情是先要在publisher上驗證的,那就是要subscribe的publication, 它是不是支援pull或者push : 在publisher 上,執行 exec sp_helppublication來確定,需要修改這份publication使其支援push, pull,那麼需要執行sp_changepublication

Pull subscription: 在subscriber上,執行sp_addpullsubscription. 這一步僅僅是定義subscription,要完成同步,還需要一個自動化的Job,這個Job就需要sp_addpullscription_agent來定義了,這個時候可以定義Job的同步頻率。表面上看pull subscription是subscriber單方面的動作,但從完整性可追溯性上來看,還需要在publisher中儲存一份他倆之間的“業務關係”,sp_addsubscription。

-- This script uses sqlcmd scripting variables. They are in the form
-- $(MyVariable). For information about how to use scripting variables  
-- on the command line and in SQL Server Management Studio, see the 
-- "Executing Replication Scripts" section in the topic
-- "Programming Replication Using System Stored Procedures".
-- Execute this batch at the Subscriber.
DECLARE @publication AS sysname;
DECLARE @publisher AS sysname;
DECLARE @publicationDB AS sysname;
SET @publication = N'AdvWorksProductTran';
SET @publisher = $(PubServer);
SET @publicationDB = N'AdventureWorks2012';
-- At the subscription database, create a pull subscription 
-- to a transactional publication.
USE [AdventureWorks2012Replica]
EXEC sp_addpullsubscription 
  @publisher = @publisher, 
  @publication = @publication, 
  @publisher_db = @publicationDB;
-- Add an agent job to synchronize the pull subscription.
EXEC sp_addpullsubscription_agent 
  @publisher = @publisher, 
  @publisher_db = @publicationDB, 
  @publication = @publication, 
  @distributor = @publisher, 
  @job_login = $(Login), 
  @job_password = $(Password);
GO

這個地方還要補一個 sp_addsubscription來在publisher上註冊下這份subscription.

Push Subscription:在publisher上,執行sp_addsubscription, sp_addpushsubscription_agent,定義一份push subscription, 並且在distributor上增加一個同步的Job用來將publication推送到subscriber上面。

-

- This script uses sqlcmd scripting variables. They are in the form
-- $(MyVariable). For information about how to use scripting variables  
-- on the command line and in SQL Server Management Studio, see the 
-- "Executing Replication Scripts" section in the topic
-- "Programming Replication Using System Stored Procedures".
DECLARE @publication AS sysname;
DECLARE @subscriber AS sysname;
DECLARE @subscriptionDB AS sysname;
SET @publication = N'AdvWorksProductTran';
SET @subscriber = $(SubServer);
SET @subscriptionDB = N'AdventureWorks2012Replica';
--Add a push subscription to a transactional publication.
USE [AdventureWorks2012]
EXEC sp_addsubscription 
  @publication = @publication, 
  @subscriber = @subscriber, 
  @destination_db = @subscriptionDB, 
  @subscription_type = N'push';
--Add an agent job to synchronize the push subscription.
EXEC sp_addpushsubscription_agent 
  @publication = @publication, 
  @subscriber = @subscriber, 
  @subscriber_db = @subscriptionDB,