本篇要講的是資料庫資料的同步方案,關於區域網路,或者兩台資料庫IP可見的同步情況,這裡不給出方案,因為這種情況資料庫本身就提供了有很多種效能卓越的方案,看協助文檔就可以解決。
本文要講的案例是:
有A,B兩台或者更多的資料庫伺服器,分處於不同的網路,資料庫IP不可見,連接埠不可見,現在需要
A中的 t1表 -----> 單向同步到 B中的 t1表
A中的 t2表 <-----> 雙向同步到 B中的 t2表
也就是AB兩資料庫伺服器的單向同步和雙向同步應該怎麼做?
在internet網中必須考慮網路速度,所以應該保證傳輸的資料量盡量小一點再小一點。
雙向同步就是做兩次單向同步而已,我們以從A伺服器上的t1表單向同步到B伺服器的t1表為例子說明同步方案。
我們來看看三種方案,然後比較一下。
方案一:
- 將A站的t1表的資料(DateTable類型)直接傳送到B站的t1表;
- B端修改式插入t1表中,所謂修改式插入就是當不存在就insert當存在就update;
(相當於mysql裡面的:insert into t1 ()values() on duplicate key update 文法)
- 完成。(簡單吧)
點評:這是最直接最粗暴也最安全的方案,但是如果同步的表資料比較多,這種方案肯定是行不通的。不過當資料量比較少時,比如說100條以內,則這種方案也凸現出了它的優點:安全,簡單。所以這種方案也是有用武之地的。
方案二:
- 在同步源一端表中(如案例中的A站t1表)增加
is_sync
is_del
兩個tinyint類型或者bite類型的欄位;
- 當作Insert或者Update操作時,同時將is_sync設定成0,等待同步;
- 當作Delete操作時,將is_del設定成1,is_sync設定成0,而不是物理刪除;
- 在A端查詢所有is_sync=0的資料,傳遞到B端;
- B端接收到資料之後將B表中已經存在的資料作物理增刪改並將成功的結果返回給A;
- A端收到B操作成功的結果,將is_sync=0且在返回成功中的資料設定is_sync=1,另外如果還is_del=1則物理刪除。
點評:這種方案是比較常見但我覺得還不明智的方案,雖然它做到了進行細粒度的同步,但卻添加了很多附加操作,如增刪改操作都要更改is_sync的值,如果正好項目已經做到收尾階段,所有的資料層已經實現了, 再要加同步的話改動就比較大了,所以這種方案優點是同步精度提高,傳輸的資料量減少,但對原本的增刪改代碼影響較大。
與之相似的方案還有增加相同結構的表(稱為它的待同步表),用觸發器將增刪改操作記錄到這種待同步表中,然後按上面的流程實現的同步,那種方案也有同樣的許多附加內容,如新增觸發器和待同步表,也對現行系統造成增加負擔和複雜度的負面影響。
方案三:
看方案三之前先介紹一下Rowversion這種欄位類型,在mysql中是TIMESTAMP類型。
Long Long ago,MSDN說:“每個資料庫都有一個計數器,當對資料庫中包含 rowversion 列的表執行插入或更新操作時,該計數器值就會增加。此計數器是資料庫行版本。這可以追蹤資料庫內的相對時間,而不是時鐘相關聯的實際時間。一個表只能有一個 rowversion 列。每次修改或插入包含 rowversion 列的行時,就會在 rowversion 列中插入經過增量的資料庫行版本值。”
具體的關於Rowversion類型的說明就不詳細寫出來了,讀者可以在msdn上搜一下。總之,這種類型的欄位會更著資料庫的記錄自動改變,不需手工操作,利用這個特性,設計出第三種同步方案。
- 在同步源一端(A中的t1表)表中增加如下三個欄位(以mssql欄位類型為例子)
row_version rowversion, -- 目前的版本
sync_version binary(8), -- 已同步版本
is_del bit default 0, -- 是否刪除
- 當A中t1表進行增加或修改操作時,row_version欄位的值會自動變成目前時間,而sync_version的值不會變,當做刪除操作的時候,需要將is_del設定成1,而不做物理刪除;
- 查詢A中所有row_version!=sync_version的資料,傳送到B端;
- B接收到資料之後做物理增刪改,並將成功的結果返回給A;
- A接收到B返回的結果之後,將sync_version與row_version的值設定成相同,如果其中有is_del=1的則物理刪除;
點評:這種方案我覺得是同步大表的最優方案,它只有在做刪除操作的時候改成邏輯刪除,其他動作不用考慮到同步的問題,對已經存在的系統影響最少,而且也是精確同步,不佔用緊張的網路資源,這種方案是本篇的主角,也是我大力推薦的方案。
在mysql中可以用 TIMESTAMP 類型實現,mysql的表中只要含有TIMESTAMP 欄位(且是無預設值的),則當表有更新或增加時就會改變第一個TIMESTAMP 類型欄位的值為目前時間,這同樣可以應用上述第三套方案。
在實際運用中,要看錶的大小來選擇同步方案,如果表較小則用第一種方案是最好的,如果表較大,則第三種是最佳方案。
鑒於這是一個解決方案的文章,索性把方案說到具體的技術實現層面上來。
案例中的A需要將表資料傳送給B,這個如何?呢?
實際中的情形通常是這兩個網路都不會開放除了網站80之外的其他連接埠給外網調用,而且方案中都需要有一個程式每隔一段時間掃描一次資料庫看是否有需要同步的資料,綜合這些情況,可以很容易想到用win Service+ web Service的方式解決。
而筆者推薦用win service+remoting的方式來做,據測試,使用remoting比web Service方式快7-8倍。不過兩者都有傳送包大小的限制,所以傳送資料的時候最好分批此來傳,一次100或者1000條,以免因為資料包超過大小而同步失敗。
如果熟悉.Net的Remoting(或Webservice)、WinService技術的人,肯定知道winService如何與remoting通訊,看到這裡肯定也知道怎麼實現了。由於這是一篇關於解決方案的文章,所以具體技術方面的基礎知識就不詳述了,望此篇對大家有所協助。有更好的方案歡迎留言交流。