auth:chaoqun.guo create by :2020
【0】環境信息
【0.1】拓撲架構環境
角色 |
使用值 |
系統環境 |
Winserver2016+sqlserver2016 |
發布服務器 |
192.168.175.145,服務器名稱:WIN-ST1AC985Q23 |
分發服務器 |
192.168.175.145,服務器名稱:WIN-ST1AC985Q23 |
訂閱服務器 |
192.168.175.146,服務器名稱:WIN-UQHLGQ8DI5E |
發布數據庫repl |
訂閱數據庫:repl |
數據庫賬戶 |
Repl/a123456! 權限:sysadmin |
本文針對復制類型 |
快照復制,事務日志復制 |
【0.2】實例名與服務器名檢查
檢查sql server數據庫實例名與服務器名是否一樣
IF SERVERPROPERTY('SERVERNAME')<>@@SERVERNAME Print '服務器名和數據庫實例名不同!請修改操作后重啟!' --IF SERVERPROPERTY('SERVERNAME')<>@@SERVERNAME --BEGIN -- DECLARE @server SYSNAME -- SET @server=@@SERVERNAME -- EXEC sp_dropserver @server=@server -- SET @server=CAST(SERVERPROPERTY('SERVERNAME') AS SYSNAME) -- EXEC sp_addserver @server=@server,@local='LOCAL' --END
如果不一樣,請把注釋放開,讓后運行,之后重啟服務器
【1】前置環境配置
【1.1】修改hosts(配置DNS)
所有訂閱發布機器都要配置:C:\Windows\System32\drivers\etc\hosts。也可以使用數據庫客戶端別名,這里就不介紹別名了,因為沒有這個方便。
【1.2】修改防火牆(網絡連通性)
用命令配置吧,比較快,手動用界面配置防火牆入站規則,給對方IP開通數據庫實例端口就好了,我們這里的實例端口是默認的1433;
打開cmd=>,然后運行下面的命令(這里為了省事我直接給局域網所有機器都開通了,要指定IP的話直接修改下面的IP地址即可)
netsh advfirewall firewall add rule name="mssql" dir=in action=allow remoteip="192.168.175.0/24" protocol=TCP localport="1433"
然后可以互相telnet 對方ip 1433,看看是否能訪問對方1433端口,沒問題就證明端口通了,連通測試這一步放到【1.3】下一步測試也可以。
【1.3】建立復制賬戶,測試連通性
所有發布訂閱機器都建立該登錄名和密碼;給予了系統管理員權限;
USE [master]
GO
CREATE LOGIN [repl] WITH PASSWORD=N'a123456!'
GO
ALTER SERVER ROLE [sysadmin] ADD MEMBER [repl]
GO
在兩台機器上互相連接對方主機名:如下,可以連通就證明網絡已經搞定了,賬戶名密碼也是確認無誤可以使用了。
【1.4】構建快照共享文件夾
(1)修改發布端(192.168.175.145)agent啟動賬戶為 localsystem,這個賬戶擁有本地系統訪問權限。
否則需要手動給共享目錄添加NT Service\SQLSERVERAGENT 的讀寫權限(也不一定是這個賬戶,看這里顯示的是什么)
(2)新建共享文件夾
自己新建一個共享文件夾,用於存放發布快照;然后把共享開啟就OK了。
如果想要使用推送訂閱,那么發布、訂閱服務器這里的登錄身份均自己新建一個windows賬戶,且該賬戶可以訪問unc路徑。(是在不行就給把該賬戶加入管理員組)
然后把這個文件夾的共享權限給予這個賬戶;
【2】分發、發布、訂閱配置
【2.1】配置分發服務器
我們在主庫,192.168.175.145 配置分發服務器;
如果你設置快照文件夾路徑為:C:\repl_share,即使你的發布服務器本身就是分發服務器,如果訂閱服務器是另外一台機器,那么在請求(Pull)訂閱(如果是推送(Push)訂閱就沒有這個限制)模式下訂閱代理是無法訪問到這個快照文件的;除非你發布服務器、分發服務器和訂閱服務器都是同一台機器;你應該設置快照文件夾路徑為:
主機名\共享文件夾,如上圖;然后繼續下一步;
這里是配置分發數據庫的名稱和文件存放位置,這里我用的虛擬機,我就隨便放了;
但請注意,務必要給這個文件夾添加 sql server agent啟動賬戶讀取權限
好,如上圖,這就配置完成了;繼續點下一步,如下圖就會出現所有的配置信息。可以查閱一下,然后點擊完成,成功。
【2.2】配置發布服務器
選擇發布數據庫
選擇發布類型
選擇發布數據庫對象,以及發布項目屬性,這里我們把非聚集索引也添加到了發布中去,如下圖
做數據篩選,這里我們沒有做任何篩選,但其實是可以寫sql針對某一部分數據篩選的,比如只同步id>500的數據…..等等
繼續下一步,我們勾選上立即初始化快照
下一步,我們點擊配置快照代理
用我們之前配置好的數據庫賬戶填充上圖。配置完后如下圖,勾選上使用快照代理的安全設置,然后下一步
然后勾上創建發布,點擊下一步
給發布取個名字,比如我這里就是repl_test1,然后點擊完成;這就配置好了數據庫發布;
【2.3】配置訂閱服務器
然后我們跑到訂閱服務器上來操作,即192.168.175.146,忘記了的看最前面的拓撲架構表信息
然后我們輸入IP,遭到我們的發布服務器
然后我們就下一步,選擇請求訂閱
然后繼續下一步,我們現在沒有的話,我們可以新建訂閱數據庫
然后確認,然后下一步,點擊右邊的點
然后進行配置:
配置完后:
下一步,下一步
下一步,完成
最終沒有問題,完成
【3】核驗與監視
【3.1】數據庫查看
我們發布的3個表都已經復制過來了。如下圖;數量也是對的
【3.2】復制監視器
我們這里可以看發布、訂閱、代理等信息
(1)發布服務器查看
在這里,可以雙擊訂閱監視列表數據,然后雙擊進去可以查看該行訂閱的同步情況;
注意,這里的代理也是發布服務器的代理哦;
(2)具體發布對應的信息查看
我們可以選中具體發布名稱,然后就可以查看到和它相關的所有訂閱,代理情況,發生的警告等等
【3.3】系統存儲過程監視
分發服務器上運行 |
|
Use distribution; exec sp_replmonitorhelppublisher |
為與分發服務器關聯的一個或多個發布服務器返回當前狀態信息。 在分發服務器的分發數據庫上執行此存儲過程,用於監視復制。 |
Use distribution; exec sp_replmonitorhelppublication |
返回發布服務器上一個或多個發布的當前狀態信息。 在分發服務器的分發數據庫上執行此存儲過程,用於監視復制 |
Use distribution; exec sp_replmonitorhelpsubscription Use distribution; exec sp_replmonitorhelpsubscription null,'repl',@publication_type=0 |
返回發布服務器上屬於一個或多個發布的訂閱的當前狀態信息,並為每個返回的訂閱返回一行。 在分發服務器的分發數據庫上執行此存儲過程,用於監視復制。 |
【3.4】表:查看復制表監視
(1)MSDB
select * from msdb..MSagentparameterlist --代理配置參數列表
select * from msdb..MSagent_parameters --代理配置文件對於當前配置參數
select * from msdb..MSagent_profiles --代理配置文件信息
select * from msdb..MSdistpublishers --發布服務器信息
select * from msdb..MSdistributiondbs --分發數據庫及配置
select * from msdb..MSdistributor --心跳
select * from msdb..MSreplmonthresholdmetrics --報警選項閾值
select * from msdb..sysreplicationalerts --復制報警信息
(2)分發數據庫 distribution
select * from distribution..MSarticles --復制:發布的數據庫對象
select * from distribution..MSrepl_commands --復制:復制的命令行
select * from distribution..MSrepl_errors --復制:復制錯誤
select * from distribution..MSrepl_transactions --復制:事物的歷史紀錄
select * from distribution..MSreplication_monitordata --復制監視器參數/刷新時間/刷新信息
select * from distribution..MSdistribution_agents --分發代理:客戶端
select * from distribution..MSdistribution_history --分發代理:歷史紀錄
select * from distribution..MSlogreader_agents --日志代理:客戶端
select * from distribution..MSlogreader_history --日志代理:歷史紀錄
select * from distribution..MSsnapshot_agents --快照代理:與本地分發服務器關聯的每個
select * from distribution..MSsnapshot_history --快照代理:歷史記錄
select * from distribution..MSsubscriber_info --訂閱服務器:信息
select * from distribution..MSsubscriber_schedule --訂閱服務器:代理運行計划
select * from distribution..MSsubscriptions --訂閱:每個數據庫對象一行
select * from distribution..MSpublication_access --賬戶:有權利訪問發布訂閱的
select * from distribution..MSpublications --發布:每個發布一行
select * from distribution..MSpublicationthresholds --發布:告警法制
select * from distribution..MSpublisher_databases --發布服務器:發布數據庫信息和實例引擎版本
(3)發布數據庫
select * from repl..sysarticles --該數據庫:參與復制的表
select * from repl..syspublications --該數據庫:參與的發布
select * from repl..syssubscriptions --該數據庫:被訂閱的表對於的訂閱信息
select * from repl..systranschemas --該數據庫:參與復制的表
select * from repl..sysarticleupdates --該數據庫:參與復制的表
select * from repl..sysarticleupdates --該數據庫:參與復制的表
(4)訂閱數據庫
select * from repl..MSreplication_objects --該數據庫:復制的對象信息
select * from repl..MSreplication_subscriptions --該數據庫:訂閱信息
【4】優化
【優化概述】(必看)
1.硬件、數據庫設計:
-
使用SSD磁盤,有錢的可以使用PCI-e卡,SSD做RAID10,所有節點部署在內網。
-
更改事務隔離級別為READ_COMMITTED_SNAPSHOT。說實話,SQL Server默認事務隔離級別是讀已提交,但是沒有多版本的概念,需要設置為READ_COMMITTED_SNAPSHOT才是我們理解上的讀已提交。如果不設置這個,照樣會讀寫互相阻塞。
-
在創建訂閱之前,先將目標數據庫的恢復模式改成簡單,能夠減少日志
2.發布、訂閱設計:
-
僅發布需要的數據,對於將日志寫入數據庫而且還要同步復制的,DBA可直接拒絕。
-
表中存在大量非聚集索引,發布時可以不勾選復制非聚集索引選項。經過測試,雖然數據庫引擎是在應用完快照最后創建索引的,但創建時間很長,有時甚至會出錯。可以在后期手工建立。我們采用導出腳本方式,然后只保留非聚集索引的腳本在訂閱庫中建立。
-
如果資源允許,單獨建立一個分發服務器。發布和分發服務器在一個服務器上會增加性能損耗,尤其是分發服務器下面有多個訂閱服務器時。
-
分發庫默認是distribution庫,會有專門的作業對該庫進行清理,名字就叫"分發清除:distribution"。但這個進程清除分發庫的效率太低了,會導致分發庫積累大量數據,需要修改運行間隔和每次清楚的數據量。詳見之前的隨筆:distribution庫過大的問題
-
合理使用訂閱方式,如果選擇推送訂閱,勢必加大分發服務器的壓力,但延遲低 ;如果選擇請求訂閱,代理服務是在訂閱服務器上,減少了分發服務器壓力,但延遲會增加。
-
快照代理的生成。對於生成幾百GB數據庫的快照,采用SSD盤可能在10分鍾左右。但會造成很高的性能損耗,要在業務非高峰期生成快照。快照代理文件也要放在SSD盤上,如果資源允許,單獨一個驅動盤也可以。
-
如果已經有備份了,那么可以通過備份直接來初始化訂閱,省去了生成快照和應用快照的步驟。
-
新發布新的表對象,對於發布庫很大的情況下重新初始化是不實際的,可以增量發布,詳見sqlserver同步后在不重新初始化快照的情況下新增表
-
對於已發布的表有批處理更新,一種方法是將批量更新分成若干小批量執行,減小事務處理的數據量;另一種方法是通過存儲過程執行更改,並將存儲過程發布。推薦第一種
-
將項目分布在多個發不上,這樣相當於變向的實現了多線程並行發布,當然也可以通過參數實現並行,下面會講到
3.參數優化:
-
降低復制代理的詳細級別,在初始測試、監視或調試期間除外。 減小分發代理或合並代理的 –HistoryVerboseLevel 參數和 –OutputVerboseLevel 參數。這樣可以減少為跟蹤代理歷史記錄和輸出而插入的新行數。相反,具有相同狀態的以前的歷史記錄消息將更新為新的歷史記錄信息。提高測試、監視和調試的詳細級別,這樣就可以獲得有關代理活動的盡可能多的信息。在系統開銷不是很大的情況下,建議使用默認值1,本身這點對性能消耗可以忽略。
-
增大快照代理的BcpBatchSize參數,-BcpBatch參數表示一個批事務的行數。
-
將快照代理的- MaxNetworkOptimization設置為1,減少將不必要的信息發送到訂閱服務器上。
-
使用快照代理、分發代理的 –MaxBcpThreads 參數(指定的線程數不應超過計算機上的處理器數)。此參數指定創建和應用快照時可以並行執行的大容量復制操作的數目。
-
為分發代理使用 –SubscriptionStreams 參數。 –SubscriptionStreams 參數可以顯著提高聚合復制吞吐量。它使到一台訂閱服務器的多個連接可以並行應用批量更改,同時在使用單線程時保持多個事務特征的存在。如果有一個連接無法執行或提交,則所有連接將中止當前批處理,而且代理將用單獨的流重試失敗的批處理。在重試階段完成之前,訂閱服務器上會存在臨時事務不一致。失敗的批處理成功提交后,訂閱服務器將恢復到事務一致狀態。官方文檔有這個參數,但增加這個參數報錯。
-
增大分發代理的 -CommitBatchSize 和CommitBatchThreshold參數的值。 提交一組事務的開銷是固定的;通過不經常提交大量事務,就可以將開銷分散在大量數據上。但是,增大此參數的優勢因應用更改的開銷由其他因素(例如包含日志的最大磁盤 I/O)限制而降低。另外,需要考慮以下權衡問題:任何導致分發代理重新開始的失敗必須回滾並重新應用大量事務。對於不可靠的網絡,越小的值導致失敗的幾率越小,如果導致失敗,將回滾並重新應用較少量事務。
-
增大日志讀取器代理的 -ReadBatchSize 參數的值。-ReadBatchSize 表示日志讀取器代理和分發代理支持事務讀取和提交操作的批大小。批大小的默認值為 500 個事務。日志讀取器代理從日志中讀取特定數量的事務,而不管這些事務是否標記為復制。將大量事務寫入發布數據庫,而其中只有一小部分標記為復制時,則應使用 -ReadBatchSize 參數增加日志讀取器代理的讀取批大小。此參數不適用於 Oracle 發布服務器。
-
為日志讀取器代理使用 –MaxCmdsInTran 參數。–MaxCmdsInTran 參數指定日志讀取器向分發數據庫寫入命令時組成一個事務的語句的最大數量。使用此參數能夠使日志讀取器代理和分發代理在訂閱服務器上應用命令時將發布服務器上的大事務(由許多命令組成)分成若干個較小的事務。指定此參數可以減少分發服務器的爭用問題並縮短發布服務器與訂閱服務器之間的滯后時間。由於初始事務是以較小的單元應用的,訂閱服務器可以在初始事務結束之前訪問一個較大的邏輯發布服務器事務的行,因而會破壞事務的原子性。默認值為 0,這將保持發布服務器的事務邊界。官方文檔有該參數,但實際設置里面沒有。
-
減小日志讀取器代理和分發代理的 -PollingInterval 參數的值。 -PollingInterval 參數指定為要復制的事務查詢已發布數據庫的事務日志的頻率。默認值為 5 秒。如果減小此值,日志的輪詢將更加頻繁,這會使事務從發布數據庫傳遞到分發數據庫的滯后時間較低。但是,應該對較低滯后時間的需要和因頻繁輪詢導致的服務器上增加的負荷之間進行平衡。
【4.0】官網使用參考
【4.1】快照初始化優化
--(0)相關DMV
select * from msdb.dbo.MSagent_profiles --查看代理文件
select * from msdb..MSagentparameterlist --查看不同代理的默認參數及相關值
select * from msdb..msagent_parameters --查看當前所有代理文件的參數值
--(1)創建一個新的代理文件
--查看最大ID是多少,沒有設置的話,默認是16 select max(profile_id) from msdb.dbo.MSagent_profiles
--默認最大是16,我們新建的文件id就給17好了
sp_add_agent_profile @profile_id= 17
, @profile_name= '優化快照代理'
, @agent_type= 1 --快照代理
, @profile_type= 1
, @description= '自定義修改配置參數,優化快照代理'
, @default= default
--(2)修改新增配置文件的配置參數
/*
修改配置文件,這里新增了
MaxBcpThreads(最大bcp使用線程),MaxNetworkOptimization(網絡自動優化)參數,
修改了BcpBatchSize(bcp一次性操作中的最大行數),HistoryVerboseLevel參數,
對於性能提高最大的參數就是MaxBcpThreads,其他參數調整對性能調高不大,但MaxNetworkOptimization參數一定要調整到1,可以減少傳輸到訂閱服務器上不必要的操作。
*/
USE msdb
EXEC sp_add_agent_parameter @profile_id = 17,
@parameter_name = 'MaxBcpThreads', @parameter_value = 4 --多現場會占用較多資源,開這個要合理,慎重
EXEC sp_add_agent_parameter @profile_id = 17,
@parameter_name = 'MaxNetworkOptimization', @parameter_value = 1
EXEC sp_change_agent_parameter @profile_id = 17,
@parameter_name = 'BcpBatchSize', @parameter_value = 200000 --2016默認已經為10W
EXEC sp_change_agent_parameter @profile_id = 17,
@parameter_name = 'HistoryVerboseLevel', @parameter_value = 1 -- 1(性能較好):如果更新狀態與上一次相同,則更新上一歷史消息,否則新建 --2:默認,每次操作都記錄成一條新的信息
【4.2】修改數據同步過程優化(日志代理與分發代理)
*(1)日志代理
--新建日志讀取代理配置文件 sp_add_agent_profile @profile_id= 20 , @profile_name= '優化日志代理' , @agent_type= 2 --日志代理 , @profile_type= 1 , @description= '自定義修改配置參數,優化日志代理' , @default= default -- 查詢該代理的profile_id SELECT * FROM msdb.dbo .MSagent_profiles WHERE agent_type =2 EXEC sp_change_agent_parameter @profile_id = 20, @parameter_name = 'ReadBatchSize', @parameter_value = 2000 EXEC sp_change_agent_parameter @profile_id = 20, @parameter_name = 'PollingInterval', @parameter_value = 1
(2)分發代理
新建分發參數配置文件,命名為"分發代理參數優化參數"
--新建日志讀取代理配置文件
sp_add_agent_profile @profile_id= 18 , @profile_name= '優化分發代理' , @agent_type= 3 --分發代理 , @profile_type= 1 , @description= '自定義修改配置參數,優化分發代理' , @default= default EXEC sp_change_agent_parameter @profile_id = 18, @parameter_name = 'PollingInterval', @parameter_value = 1 EXEC sp_change_agent_parameter @profile_id = 18, @parameter_name = 'CommitBatchSize', @parameter_value = 1000 EXEC sp_change_agent_parameter @profile_id = 18, @parameter_name = 'CommitBatchThreshold', @parameter_value = 10000
【4.3】不重新初始化新增數據庫對象
immediate_sync:指定每次運行快照代理時是否為發布創建同步文件。 immediate_synchronization 的數據類型為 nvarchar(5),默認值為 FALSE。
如果為 True,表示每次運行快照代理時都創建或重新創建同步文件。 如果快照代理在訂閱創建前完成,則訂閱服務器可以立即獲得同步文件。 新訂閱將獲取最近一次執行快照代理所生成的最新同步文件。 independent_agent 必須為 true,以便於 immediate_synchronization 為 true。 如果為 False,則僅當有新訂閱時,才創建同步文件。
當以增量方式向現有發布添加新項目時,必須為每個訂閱調用 sp_addsubscription。 訂閱后訂閱服務器無法接收同步文件,直到啟動並完成快照代理為止。
allow_anonymous:指定是否可為給定發布創建匿名訂閱。 allow_anonymous 的數據類型為 nvarchar(5),默認值為 FALSE。
如果為 True,則 immediate_synchronization 也必須設置為 True。 如果為 False,則表示不允許對該發布創建匿名訂閱。
從定義中看出來,immediate_sync為false時,新的項目(表、存儲過程等)可以以增量方式發布,而allow_anonymous必須為false,immediate_sync才能為false。
--查閱發布對應的這2個參數當前值 select * from distribution..MSpublications
use msterdb ; go EXEC sp_changepublication @publication = 'repl_master', @property = 'allow_anonymous' ,@value = 'false' GO EXEC sp_changepublication @publication = 'repl_master', @property = 'immediate_sync' ,@value = 'false' GO
修改前:更新發布,項目中新增表之后,啟動快照代理=》如下圖,發現所有發布表全部初始化了
修改后:更新發布,項目中新增表之后,啟動快照代理=》如下圖,發現只有 test5表更新過去了
【4.4】使用T-SQL,不初始化 增刪表
-- 若提前“禁止架構更改”,新增的列不會自動添加大發布,此時應使用 sp_articlecolumn 添加列 EXEC sp_changepublication @publication = N'publication', @property = N'replicate_ddl', @value = 0 --【移除和添加發布而不初始化所有項目,但是添加的項目須初始化】 -- 禁止匿名訪問 Exec sp_changepublication 'publication','allow_anonymous',false GO -- 禁止立即更新 Exec sp_changepublication 'publication','immediate_sync',false GO -- 終止單個項目復制(該表在發布可正常操作,訂閱應禁止操作) Exec sp_dropsubscription @publication = N'publication', @article = N'article', @subscriber = N'subscriber', @destination_db = N'destination_db' GO -- 從發布中刪除項目(界面操作將會重新初始化所以項目) Exec sp_droparticle @publication = N'publication', @article = N'article' GO -- 添加項目到發布中(@schema_option 參考個人要求更改) Exec sp_addarticle @publication = 'publication', @article = N'article', @source_object = N'article', @source_owner = N'dbo',@schema_option = 0x0000000008037CDF GO -- 添加未發布的列(對已發布中的表添加多一列,一般不用) Exec sp_articlecolumn @publication = 'publication' ,@article = N'article',@column = N'column',@operation = N'add' GO -- 進行行篩選(用於篩選發布) Exec sp_articlefilter @publication = N'publication', @article = N'article', @filter_name = N'FLTR_article_1__1', @filter_clause = N'id % 2 = 0' GO -- 進行行篩選(用於篩選發布) Exec sp_articleview @publication = N'publication', @article = N'article', @view_name = N'SYNC_article_1__1', @filter_clause = N'id % 2 = 0' GO -- 刷新訂閱以添加項目 Exec sp_refreshsubscriptions 'publication' GO -- 啟動快照代理(初始化新增的項目) Exec sp_startpublication_snapshot 'publication' GO
不初始化,刪除表案例
不初始化,刪除表案例:(注意,這樣會導致新建訂閱時無法應用現有的快照連接發布,必須重新運行快照代理后,才可以,如下圖)
這種辦法,不會阻塞,不需要發布的項目全表初始化;(當然,直接用界面操作也是沒有問題的)
select * from distribution..mspublications -- 查看 publication select * from distribution..mssubscriber_info -- 查看 subscriber select * from distribution..MSsubscriptions -- 查看 destination_db select * from distribution..MSarticles -- 查看所有發布的項目(即表) -- 終止單個項目復制(該表在發布可正常操作,訂閱應禁止操作) Exec sp_dropsubscription @publication = N'publication', @article = N'article', @subscriber = N'subscriber', @destination_db = N'destination_db' GO -- 從發布中刪除項目(界面操作將會重新初始化所以項目) Exec sp_droparticle @publication = N'publication', @article = N'article' GO --主從都要 drop table article
【4.5】解決大事務引起的發布訂閱效率問題
(1)大事務引起的問題
在 SQLServer 復制中,當在發布數據庫執行1個大事務時,如一次性操作十萬行或百萬行以上的數據。當操作數據在發布數據庫執行完成后 ,日志讀取器代理將掃描事務日志,一次性傳遞到分發數據庫中。
若上個事務未傳遞完成,連續執行多個事務,日志讀取器代理將掃描日志中多個事務同時傳遞到分發數據庫中,默認最大掃描500個事務。如果執行多次上百萬或千萬的數據將堵塞很久。
(2)解決
日志讀取器代理可配置將大事務划分為多個小事務進行傳遞到分發數據庫中,分發隊列則按照小事務分發到訂閱數據庫中,這樣數據就很快同步!
在沒改代理參數之前,本人執行1次插入30萬的數據到發布表中。插入完成后,監控發布到分發的記錄如下:
可以看到,這1個事務的命令都得一次傳遞完才能分發,而分發又消耗時間,這里等待太久影響事務的實時性。如果還有其他事務,默認500(參考參數:-ReadBatchSize),也將一起傳遞,不過耗時較長。
現在更改參數,掃描到 1000 左右的命令就即時分發,需要設置如下參數:
-MaxCmdsInTran number_of_commands
注:該參數只能添加到日志讀取器代理中,在代理配置文件沒有此參數的設置。
添加后重啟日志讀取器代理。再次插入 30 萬的數據,到監視器查看。
可以看到,命令達到 1000 左右就進行分發了,此時查看訂閱數據庫,數據也同步過來了,這樣就省去了較多掃描命令的時間。
更詳細查看每個事務的命令數,如下:
SELECT top 10 A.xact_seqno,A.entry_time,COUNT(*) AS cmds
FROM distribution.dbo.MSrepl_transactions A(NOLOCK)
INNER JOIN distribution.dbo.MSrepl_commands B(NOLOCK)
ON A.xact_seqno=B.xact_seqno
GROUP BY A.xact_seqno,A.entry_time
ORDER BY cmds DESC
這個參數雖好,但是也可能引起數據的一致性。如:在發布更新了一批數據,但是訂閱查詢時卻有不同。分發事務遇到沖突或者死鎖,也導致這部分的數據不一致。
【5】基本原理
【5.0】事務復制的原理
(1)當publication database的article發生更新時, 會產生相應的日志,Log reader會讀取這些日志信息,將他們寫入到Distribution 數據庫的msrepl_transactions和msrepl_commands中。
(2)Msrepl_transactions中的每一條記錄都有一個唯一標識xact_seqno,xact_seqno對應日志中的LSN。 所以可以通過xact_seqno推斷出他們在publication database中的生成順序,編號大的生成時間就晚,編號小的生成時間就早。
(3)Distributionagent包含兩個子進程,reader和writer。 Reader負責從Distribution 數據庫中讀取數據,Writer負責將reader讀取的數據寫入到訂閱數據庫。
(4)Reader是通過sp_MSget_repl_commands來讀取Distribution數據庫中(讀取Msrepl_transactions表和Msrepl_Commands表)的數據。
(5)大致邏輯是:Reader讀取subscription database的MSreplication_subscriptions表的transaction_timestamp列,獲得更新的上一次LSN編號,然后讀取分發數據庫中LSN大於這個編號的數據。
Writer將讀取到的數據寫入訂閱,並更新MSreplication_subscriptions表的transaction_timestamp列。然后Reader會繼續用新的LSN來讀取后續的數據,再傳遞給Writer,如此往復。
注意:如果我們手工更新transaction_timestamp列,將這個值設置為當前正在執行的大事務的LSN,那么distribution agent就會不讀取這個大事務,而是將其跳過了。
【5.1】發布訂閱的角色與概念
復制使用出版業術語表示復制拓撲中的組件,其中包括發布服務器、分發服務器、訂閱服務器、發布、項目和訂閱。 可借助雜志的概念來幫助理解 Microsoft SQL Server 復制:
-
雜志出版商(發布服務器)生產一種或多種刊物(發布) publisher
-
刊物(發布)包含文章(項目)articles
-
出版商(發布服務器)可以直接發行(分發)雜志,也可以使用發行商(分發服務器) distributor
-
訂閱者(訂閱服務器)接收訂閱的刊物(發布) subscriber
雖然雜志術語有助於理解復制,但重要的是要注意到 SQL Server 復制包含有這套術語未予以表述的功能,尤其是訂閱服務器進行更新的功能以及發布服務器將增量更改發送到發布中的項目的功能。
"復制拓撲" 定義了服務器和數據副本間的關系,並闡明了決定數據如何在服務器之間流動的邏輯。 有若干復制進程(稱為"代理" )負責在發布服務器和訂閱服務器之間復制和移動數據。 下圖為復制中所涉及的組件和進程的概述。
復制組件和數據流
發布者publisher
發布服務器是一種數據庫實例,它通過復制向其他位置提供數據。 發布服務器可以有一個或多個發布,每個發布定義一組要復制的具有邏輯關系的對象和數據。
分發服務器distributor
分發服務器也是一種數據庫實例,它起着存儲區的作用,用於復制與一個或多個發布服務器相關聯的特定數據。 每個發布服務器都與分發服務器中的單個數據庫(稱作分發數據庫)相關聯。 分發數據庫存儲復制狀態數據和有關發布的元數據,並且在某些情況下為從發布服務器向訂閱服務器移動的數據起着排隊的作用。 在很多情況下,一個數據庫服務器實例充當發布服務器和分發服務器兩個角色。 這稱為"本地分發服務器" 。 當發布服務器和分發服務器按各自的數據庫服務器實例配置時,把分發服務器稱為"遠程分發服務器" 。
訂閱服務器subscriber
訂閱服務器是接收復制數據的數據庫實例。 訂閱服務器可以接收來自多個發布服務器和發布的數據。 根據所選的復制類型,訂閱服務器還可以將數據更改傳遞回發布服務器或者將數據重新發布到其他訂閱服務器。
項目articles
項目用於標識發布中包含的數據庫對象。 一次發布可以包含不同類型的項目,包括表、視圖、存儲過程和其他對象。 當把表作為項目發布時,可以用篩選器限制發送到訂閱服務器的數據的列和行。
發布publication
發布是一個數據庫中的一個或多個項目的集合。 將多個項目分組成一個發布,使得更便於指定一組作為一個單元復制的、具有邏輯關系的數據庫對象和數據。
訂閱subscrible
訂閱是把發布副本傳遞到訂閱服務器的請求。 訂閱定義將接收的發布和接收的時間、地點。 有兩種類型的訂閱:推送訂閱和請求訂閱。
有關推送訂閱和請求訂閱的詳細信息,請參閱訂閱發布。
【5.2】復制類型與訂閱類型
類型 |
說明 |
在發布服務器上進行的更改會在發生時(幾乎實時)傳遞給訂閱服務器。 數據更改將按照其在發布服務器上發生的順序和事務邊界應用於訂閱服務器。 |
|
可以在發布服務器和訂閱服務器上更改數據,並且可以通過觸發器進行跟蹤。 訂閱服務器在連接到網絡時將與發布服務器進行同步,並交換自上次同步以來發布服務器和訂閱服務器之間發生更改的所有行。 |
|
將來自發布服務器的快照應用於訂閱服務器,這完全按照數據在特定時刻的狀態分發數據,而不監視數據是否更新。 發生同步時,將生成完整的快照並將其發送到訂閱服務器。 |
|
對等復制建立在事務復制的基礎之上,以事務方式近乎實時地在多個服務器實例之間傳播一致的更改。 |
|
雙向事務復制是一種特定的事務復制拓撲,它允許兩台服務器相互交換更改:每台服務器均發布數據,然后從另一台服務器訂閱包含相同數據的發布。 |
|
以事務復制為基礎而構建,在訂閱服務器上針對可更新訂閱更新了數據時,會首先傳播到發布服務器,然后傳播到其他訂閱服務器。 |
訂閱 |
特征 |
使用時間 |
推送訂閱 |
對於推送訂閱,發布服務器將更改傳播到訂閱服務器,而無需訂閱服務器發出請求。 更改可以按需、連續地或按照計划推送到訂閱服務器。 分發代理或合並代理在分發服務器上運行。 |
通常,數據將連續同步或按照經常重復執行的計划同步。 |
請求訂閱 |
對於請求訂閱,訂閱服務器請求在發布服務器上所做的更改。 請求訂閱允許訂閱服務器上的用戶確定同步數據更改的時間。 分發代理或合並代理在訂閱服務器上運行。 |
數據通常按需或按計划同步,而非連續同步。 發布具有大量訂閱服務器,並且/或在分發服務器上運行所有代理會消耗大量資源。 通常與合並復制一起使用。 |
【5.3】復制代理
我們右擊發布可以看到許多代理,如下圖,那么他們到底是什么呢?
(1)快照代理
快照代理通常與各種類型的復制一起使用。 快照代理准備已發布表的架構和初始數據文件以及其他對象、存儲快照文件並記錄分發數據庫中的同步信息。 快照代理在分發服務器上運行。 有關詳細信息,請參閱 Replication Snapshot Agent。
(2)日志讀取器代理
日志讀取器代理與事務復制一起使用。 它將發布服務器上的事務日志中標記為復制的事務移至分發數據庫中。 使用事務復制發布的每個數據庫都有自己的日志讀取器代理,該代理運行於分發服務器上並與發布服務器連接(分發服務器與發布服務器可以是同一台計算機)。 有關詳細信息,請參閱 Replication Log Reader Agent。
(3)分發代理
分發代理與快照復制和事務復制一起使用。 它將初始快照應用於訂閱服務器,並將分發數據庫中保存的事務移至訂閱服務器。 分發代理既可以運行於分發服務器(對於推送訂閱),也可運行於訂閱服務器(對於請求訂閱)。 有關詳細信息,請參閱 Replication Distribution Agent。
(4)合並代理
合並代理與合並復制一起使用。 它將初始快照應用於訂閱服務器,並移動和協調所發生的增量數據更改。 每個合並訂閱都有自己的合並代理,該代理同時連接到發布服務器和訂閱服務器並對它們進行更新。 合並代理既可以運行於分發服務器(對於推送訂閱),也可以運行於訂閱服務器(對於請求訂閱)。 默認情況下,合並代理將訂閱服務器上的更改上載到發布服務器,然后將發布服務器上的更改下載到訂閱服務器。 有關詳細信息,請參閱 Replication Merge Agent。
(5)隊列讀取器代理
隊列讀取器代理與包含排隊更新選項的事務復制一起使用。 該代理運行於分發服務器,並將訂閱服務器上所做更改移回至發布服務器。 與分發代理和合並代理不同,只有一個隊列讀取器代理的實例為給定分發數據庫的所有發布服務器和發布提供服務。 有關隊列讀取器代理的詳細信息,請參閱 Replication Queue Reader Agent。 有關可更新訂閱的詳細信息,請參閱 Updatable Subscriptions for Transactional Replication。
(6)復制維護作業
創建復制之后,會在很代理中創建很多作業。復制包含許多執行計划維護和按需維護的維護作業。
【5.4】架構更改的注意事項
架構更改的注意事項
復制架構更改時,請牢記下列注意事項:
一般注意事項
-
架構更改需遵守 Transact-SQL規定的所有限制。 例如,ALTER TABLE 不允許對主鍵列執行 ALTER 語句。
-
僅對初始快照執行數據類型映射。 架構更改不會映射到以前版本的數據類型。 例如,如果在 ALTER TABLE ADD datetime2 column 中使用 SQL Server 2012 (11.x)語句,則不會將數據類型轉換為 ssVersion2005 訂閱服務器的 SQL Server 2005 (9.x) 。 在某些情況下,架構更改在發布服務器上受到阻止。
-
如果發布被設置為允許傳播架構更改,則不論為發布中的項目設置的相關架構選項是什么,都會傳播架構更改。 例如,如果選擇不復制某個表項目的外鍵約束,但隨后又發出 ALTER TABLE 命令,將外鍵添加到發布服務器中的表中,那么外鍵將被添加到訂閱服務器中的表中。 若要防止出現這種情況,請在發出 ALTER TABLE 命令之前禁用架構更改的傳播。
-
架構更改只應在發布服務器中進行,不應在訂閱服務器中(包括重新發布訂閱服務器)上進行。 合並復制禁止在訂閱服務器中進行架構更改。 事務復制雖然不禁止更改,但更改可能會導致復制失敗。
-
傳播到重新發布訂閱服務器的更改默認情況下會傳播到它的訂閱服務器。
-
如果架構更改引用存在於發布服務器中而不存在於訂閱服務器中的對象或約束,則架構更改將在發布服務器中成功,但在訂閱服務器上失敗。
-
添加外鍵時引用的訂閱服務器中的所有對象必須與發布服務器中的相應對象具有相同的名稱和所有者。
-
不會復制顯式添加、刪除或更改索引,並且涉及顯式索引的任何更改都需要在每個副本集上單獨運行。 支持為約束(如主鍵約束)隱式創建的索引。
-
不支持更改或刪除由復制管理的標識列。 有關自動管理標識列的詳細信息,請參閱復制標識列。
-
不支持包含不確定性函數的架構更改,因為它們可能會導致發布服務器和訂閱服務器中的數據不同(稱為無法收斂)。 例如,如果在發布服務器發出以下命令: ALTER TABLE SalesOrderDetail ADD OrderDate DATETIME DEFAULT GETDATE(),則將此命令復制到訂閱服務器並執行時,會得到不同的值。 有關不確定性函數的詳細信息,請參閱 Deterministic and Nondeterministic Functions。
-
建議顯式命名約束。 如果不顯式命名約束, SQL Server 將為約束生成名稱,並且這些名稱在發布服務器和每個訂閱服務器中都不同。 這在復制架構更改時會引發問題。 例如,如果在發布服務器中刪除一列並刪除了一個相關約束,則復制將嘗試在訂閱服務器中刪除該約束。 由於約束名稱不同,因此在訂閱服務器上的刪除將失敗。 如果由於約束命名問題而導致同步失敗,可以在訂閱服務器中手動刪除約束然后重新運行合並代理。
-
如果為復制發布了一個表,並且已生成了發布快照,則無法將該表中的列更改為 XML 數據類型。若要更改列,必須先刪除復制。
-
對已發布的表執行 DDL 時,"未提交讀"不是受支持的隔離級別。
-
不應使用SET CONTEXT_INFO 來修改已對發布的對象執行架構更改的事務的上下文。
【6】業務場景
【6.1】跨機房、跨網段復制
http://www.cnblogs.com/gaizai/p/3328511.html
【6.2】跨機房、跨網段FTP復制
http://www.cnblogs.com/gaizai/p/3337434.html
【6.3】通過備份文件初始化復制
http://www.cnblogs.com/gaizai/p/3309567.html
【注意事項與疑問】
(1)注意事項
1. 在SQL SERVER下實現發布服務器和訂閱服務器的通信正常(即可以互訪),打開1433端口,在防火牆中設置入站規則;
2. 發布服務器與訂閱服務器的SQL Server Agent代理帳號必須設置的一樣,否則不能互訪;
3. 如果你希望在復制的過程中一並復制非聚集索引,可以對發布屬性-項目進行如下設置,修改完之后需要重新生成快照;
4.使用請求訂閱,分發作業是在訂閱服務器上創建的;使用推送訂閱,分發作業是在分發服務器上創建;
5. 分發服務器上的快照文件會給刪除,在所有訂閱服務器應用快照后,復制清理將自動刪除初始快照的關聯bcp文件
6.在分發服務器和訂閱服務器上設置別名的時候,別名應該跟服務器的實例名要一致,不然會報下面的錯誤:
(2)疑問
1. SQL Server 只有在完整日志模式下才能使用復制嘛?
解惑:在簡單模式下一樣可以使用復制;
2. 如果是跨網段(跨機房)的發布與訂閱,有沒辦法實現?需要注意什么?
解惑:可以通過修改host文件、別名的方式搭建復制,請參考:SQL Server跨網段(跨機房)復制
3. 如果說上面的情況可以在host設置,但是如果有端口映射的,host也無法設置吧?
解惑:在SQL Server配置管理器里建立別名,同樣可參考:SQL Server跨網段(跨機房)復制
4. 訂閱的形式可以選擇推送訂閱或者請求訂閱,請求訂閱降低分發服務器處理工作的開銷,這個開銷有多大呢?怎么計算影響?
解惑:只有在有很多訂閱服務器的時候才比較明顯,推送訂閱與請求訂閱更大的區別是在管理方面的不同;
【常見問題】
活動在發布時是否需要在數據庫上停止?
快照生成期間是否鎖定表?
訂閱何時可用?何時可以使用訂閱數據庫?
訂閱何時可用?何時可以使用訂閱數據庫?
如果分發代理或合並代理啟動時快照代理尚未完成,會出現什么情況?
是否應為復制配置編寫腳本?
復制數據庫需要什么樣的恢復模式?
復制為什么要向已復制的表添加一列;如果表並未發布,是否會刪除該列?
如何管理已發布表的約束?
如何管理標識列?
是否可以在不同的發布中發布相同的對象?
多個發布是否可以使用同一個分發數據庫?
如何在分發服務器和發布服務器中查找信息,如已經發布了數據庫中的哪些對象?
復制是否加密數據?
如何在 Internet 上復制數據?
如果刪除連接,復制是否可以繼續?
復制是否可以在低帶寬連接上工作? 它是否使用壓縮?
復制是否可以在低帶寬連接上工作? 它是否使用壓縮?
如果使用 IP 地址連接到服務器,是否可以配置復制?
是否復制登錄名和密碼?
什么是架構,如何復制架構?
如何配置訂閱數據庫上的授權,以使其與發布數據庫上的授權相匹配?
如果重新初始化訂閱,訂閱數據庫中授予的權限會怎樣?
為什么無法對已發布的表運行 TRUNCATE TABLE?
在復制的數據庫上運行大容量插入命令,會產生什么效果?
對於備份和還原,是否存在復制注意事項?
復制是否影響事務日志的大小?
如何在復制的數據庫中重新生成索引或表?
如何在發布數據庫和訂閱數據庫上添加或更改索引?
如何對復制所涉及的數據庫的文件進行移動和重命名?
如何刪除正在復制的表?
如何在已發布的表中添加或刪除列?
如何確定訂閱服務器的數據是否與發布服務器的數據同步?
如何向現有發布添加表?
如何從發布中刪除表?
哪些操作需要重新初始化訂閱?
什么操作會導致快照失效?
如何刪除復制?
如何確定是否存在要復制的事務或行?
分發代理滯后多少? 是否應重新初始化?
分發代理滯后多少? 是否應重新初始化?
復制是否可與日志傳送和數據庫鏡像一起進行?
復制是否可與聚類分析一起進行?
【故障排查】
(0)參考文檔:
https://www.cnblogs.com/gered/p/9831781.html
(1)由於出現操作系統錯誤 3,進程無法讀取文件
解決:
推送訂閱:快照文件夾 給予 sql server代理啟動賬戶訪問權限
請求訂閱:發布服務器與訂閱服務器的SQL Server Agent代理帳號必須設置的一樣,且對快照unc路徑共享文件夾有權限,否則不能互訪;
核心原理
就是訂閱服務器讀取不到快照文件夾位置.這也導致了"訂閱服務器無法重新初始化非immediate_sync發布的訂閱"。
可能的原因較多,1、沒設置共享或者沒共享給跟訂閱服務器共同的賬戶權限;2、IPC連接被關閉,訂閱服務器無法連接到發布服務器共享資源。
解決辦法:
可以將快照文件夾D:\XX復制到訂閱服務器F:\XX
某個訂閱屬性-》快照位置-》"備用文件夾",快照文件夾-》F:\XX。應該就可以了。
1.首先,在創建發布時需要指定一個發布快照位置,並且會提示你訂閱服務器可能無法訪問該目錄(不知你有沒有注意),每次生成快照都會將快照文件放在該目錄下。
2.其次,在創建訂閱時,需要你指定快照位置,一般為發布缺省位置(不知你這次注意沒有)
3.那么,要解決你的問題只有兩種方式
1)第一種:在創建發布和訂閱時指定一個兩個服務器都能訪問的目錄。 (上面案例就是此步遇到障礙)
2)第二種:每次自己將發布快照目錄中的文件通過網絡(或移動設備)拷貝到訂閱指定的快照目錄中。(上面解決辦法就用該種)
(2)訂閱不存在
明明有,卻提示訂閱不存在,且數據同步也是正常的,但是就是查看的時候報錯;
解決:在配置訂閱的時候,選擇發布服務器、訂閱服務器的時候,一定要用主機名,否則會出現這個情況;如下圖:
(3)找不到存儲的過程 sp_MSins_tablename(誤刪訂閱服務器上的訂閱)
我在訂閱服務器,不小心手動刪掉了訂閱,但主庫的訂閱居然沒有被刪掉。
我們再看看主庫,依然有這個
錯誤信息:
解決:在發布數據庫上運行
USE [發布數據庫]
GO
EXEC sp_scriptpublicationcustomprocs '發布'
把結果集拿出來,放到有問題的訂閱端上去執行;刷新一下訂閱段的復制,發現訂閱段的這個又出來了,如下圖
再看主庫復制監視器,我們可以發現,他其實是重新構建了一次,重新初始化了;
(4)無法禁用服務器 xxxx 上的發布與分發
一次只能有一個日志讀取器或日志相關過程
無需理會,好像報這個錯,它也已經禁用刪除發布和分發了。
如果真的要管的話,把代理作業中的 事務日志代理 和分發代理作業停止一下,就好了。
(5)服務器名和主機名不一致
IF SERVERPROPERTY('SERVERNAME')<>@@SERVERNAME Print '服務器名和數據庫實例名不同!請修改操作后重啟!' IF SERVERPROPERTY('SERVERNAME')<>@@SERVERNAME BEGIN DECLARE @server SYSNAME SET @server=@@SERVERNAME EXEC sp_dropserver @server=@server SET @server=CAST(SERVERPROPERTY('SERVERNAME') AS SYSNAME) EXEC sp_addserver @server=@server,@local='LOCAL' END --重啟服務器,重啟后再執行驗證,看2個值是否一樣 IF SERVERPROPERTY('SERVERNAME'),@@SERVERNAME
(6)sql server復制需要實際的服務器名稱才能連接到服務器
(1)情況1:必須要用主機名
(2)情況2:如果要用鏈接服務器來發布訂閱,必須鏈接服務器名和對方IP對應的主機名相同!
(7)強行刪除訂閱發布
--或者暴力卸載 exec sp_removedbreplication dbname
(8)無法作為數據庫主題執行,因為主體dbo不存在
sql server刪除訂閱發布失敗,無法作為數據庫主題執行,因為主體"dbo"不存在、無法模擬這種類型的主體,或您沒有所需要的權限。
【參考文檔】
參考聯機叢書,復制的配置與使用:https://docs.microsoft.com/zh-cn/sql/relational-databases/replication/tutorial-preparing-the-server-for-replication?view=sql-server-2017
大菠蘿博客系列:https://www.cnblogs.com/diabloxl/p/4097373.html
1、概念與搭建
Step5:SQL Server 跨網段(跨機房)FTP復制
Step6:SQL Server 數據變更時間戳(timestamp)在復制中的運用
總結參考使用: http://blog.itpub.net/30126024/viewspace-2639648/
2、優化與使用
SQL Server復制情況下的高可用方案(一)鏡像+復制
SQL Server提高事務復制效率優化(四)修改數據同步過程優化
SQL Server提高事務復制效率優化(三)訂閱初始化優化
SQL Server提高事務復制效率優化(二)快照初始化優化
SQL Server提高事務復制效率優化(一)總體概述
distribution數據庫過大問題
【sql server復制】不重新初始化快照的情況下新增表/存儲過程/函數等
————————————————————————
3、常見故障與問題
https://www.cnblogs.com/gered/p/9042763.html
https://www.cnblogs.com/gered/p/9831781.html
【SQL Server復制】數據庫復制:修改表結構、新增表、新增存儲過程會被復制到訂閱服務器?
4、深入解析與優化
使用復制存儲過程執行解決"事務復制中的表大量更新導致無法及時同步"的問題(轉)
SQL Server 事務復制分發到訂閱同步慢 SqlServer 復制中將大事務分成小事務分發的方法
【推薦優先查看】如何處理SQL Server事務復制中的大事務操作