田關偉
(四川民族學院)
數(shù)據(jù)復制是將主節(jié)點服務器上的數(shù)據(jù)及其更新實時同步到一個或多個從節(jié)點服務器.復制功能不僅有利于構建高性能的應用,同時也是高可用性、可擴展性、災難恢復、備份以及數(shù)據(jù)倉庫等工作的基礎.復制功能有很多用途,比較常見的有:(1)數(shù)據(jù)分布:在不同的地理位置分布數(shù)據(jù)備份,或建立數(shù)據(jù)中心;(2)負載均衡:將讀操作分布到多個服務器上,實現(xiàn)對讀密集型應用的優(yōu)化;(3)冗余和故障切換:避免單節(jié)點失敗,當一個節(jié)點失效,可以換到具有相同數(shù)據(jù)副本的節(jié)點;(4)數(shù)據(jù)分析和產生報表:直接用數(shù)據(jù)庫中的數(shù)據(jù)進行數(shù)據(jù)分析或創(chuàng)建報表時會消耗資源,大大降低服務器性能,可以將類似作業(yè)移至具有相同數(shù)據(jù)副本的節(jié)點;(5)調試和審計:可以審查或測試服務器上的查詢,而并不影響業(yè)務的正常進行.
根據(jù)復制發(fā)生的時機,可以將復制分為同步復制(synchronous replication)和異步復制(asynchronous replication)兩種.在同步復制中,當一事務提交時,所有相關站點均實時同步更新,隨著節(jié)點增加,存在大量鎖競爭從而導致死鎖的增加,降低系統(tǒng)的響應速度.在異步復制中,事務在某一站點提交后的某一時刻再復制到其他相關站點,響應時間短,降低了通信量,但不是實時同步,提高了性能,但是可能導致不同節(jié)點之間的數(shù)據(jù)不一致.
MySQL是互聯(lián)網上最流行的開放源代碼的數(shù)據(jù)庫軟件.在MySQL中,復制技術將數(shù)據(jù)從一個數(shù)據(jù)庫服務器(master,主庫)復制到一個或多個數(shù)據(jù)庫服務器(slaver,備庫).在默認情況下這種復制是異步的,備庫不需要一直連接到主庫接收更新.根據(jù)配置,MySQL可以復制所有的數(shù)據(jù)庫、選定的數(shù)據(jù)庫甚至選定在數(shù)據(jù)庫中的表.
MySQL的復制技術是在主庫上保持對所有數(shù)據(jù)庫改變(更新,刪除等)的跟蹤,當主庫改變數(shù)據(jù)庫的結構或內容時,在二進制記錄文件中產生一條記錄.通常情況下,select語句不會被記錄,因為并沒有改變數(shù)據(jù)庫的機構和內容.當一個備庫連接到主庫時,向主庫請求二進制文件的拷貝,然后將二進制文件中記錄的事件在備庫中進行重放,如,創(chuàng)建表、修改表結構,數(shù)據(jù)的插入、刪除、更新等.
MySQl復制功能使用3個線程來完成工作,分別是二進制轉儲線程(Binlog dump thread)、I/O線程(Slave I/O thread)和SQL線程(Slave SQL thread),其中二進制轉儲線程運行在主庫上,I/O線程和SQL線程運行在備庫上.如圖1所示,復制通過三個步驟來完成:
(1)主庫上記錄二進制日志.每次準備提交事務完成數(shù)據(jù)更新前,主庫按照事務提交的順序,將數(shù)據(jù)更新的事件記錄到二進制日志中.
(2)備庫將主庫的二進制日志復制到自己的中繼日志.首先,備庫啟動一個工作線程I/O線程,I/O線程與主庫建立一個連接,然后在主庫上啟動二進制轉儲線程,I/O線程讀取主庫二進制轉儲線程發(fā)送的內容,并將數(shù)據(jù)拷貝到備庫本地,形成中繼日志.主庫上有信息日志,保存?zhèn)鋷斓街鲙斓倪B接狀態(tài)和當前配置信息,記錄日志記錄主機名,登陸認證,以及備庫在主庫二進制日志中已讀取的位置坐標.
(3)備庫讀取中繼日志中的事件并重放到備庫數(shù)據(jù)上.備庫上的SQL線程從本地的中繼日志中讀取事件,并在本地執(zhí)行,從而實現(xiàn)備庫數(shù)據(jù)的更新.
圖1 MySQL復制步驟
在復制過程中,備庫上的兩個線程獨立工作,因此SQL線程盡管語句執(zhí)行的慢,但不會使讀取更新變慢.比如,備庫一段時間沒有運行,當它連接到主庫后會快速的讀取二進制記錄,即使SQL線程會落后于它,如果備庫在獲取到的所有語句執(zhí)行之前停止,I/O線程至少已經獲取了所有內容,以便將語句的安全副本保存在中繼日志中,準備下次備庫運行時執(zhí)行.
為MySQL服務器配置復制非常簡單,主庫和備庫全新安裝后,擁有相同的配置和相同的數(shù)據(jù),現(xiàn)在假設主庫為 server1(IP:192.168.0.1),備庫為 server2(IP:192.168.0.2).
(1)在服務器上創(chuàng)建復制賬號,MySQL在備庫運行的I/O線程會建立一個到主庫的TC/IP連接,因此需要在主庫創(chuàng)建一個用戶,并授予權限.備庫的I/O線程將使用此用戶連接到主庫并讀取其二進制日志:
(2)配置主庫和備庫,在主庫server1上,需要打開二進制日志,并指定一個唯一的服務器ID,在主庫的my.cnf文件中做如下修改:
服務器ID可以設置為1到232-1中的一個整數(shù)值,一般默認情況下服務器的ID為1,應204.107避免使用默認值可能會導致和其他服務器的ID沖突.
在備庫的my.cnf中增加如下配置:
(3)通知備庫連接到主庫并從主庫復制數(shù)據(jù),使用CHANGE MASTER TO語句指示備庫如何連接到主庫并重放其二進制日志中的事件:
MASTER_LOG_POS是日志的偏移量,因為從日志的開頭開始讀取,所以設置為0.在mysql命令行使用START SLAVE開始復制,可以使用SHOW SLAVE STATUSG查看備庫的狀態(tài).
MySQL的復制技術有三種模式,分別是基于語句的復制(SBR),基于行的復制(RBR),混合復制模式(MBR).
(1)基于語句的復制基于語句的復制,主庫記錄造成數(shù)據(jù)更改的語句,當備庫進行復制時,實際上是把主庫上執(zhí)行過的SQL語句在備庫上再執(zhí)行一次.這樣使復制實現(xiàn)很簡單,使二進制中的事件更加緊湊,比如一個更新幾兆數(shù)據(jù)的語句在二進制日志里只占幾十個字節(jié),發(fā)送時也可以節(jié)省資源.基于語句的復制基本上就是執(zhí)行SQL語句,在備庫上發(fā)生的數(shù)據(jù)更新就更容易理解,這樣出現(xiàn)問題的時候就可以方便的進行定位.基于語句的復制也有一些缺點,比如同一條SQL語句在主庫和備庫上執(zhí)行的時間不同,可能結果就會不相同.另外,更新必須是串行的,這需要更多的鎖.
(2)基于行的復制基于行的復制將實際數(shù)據(jù)記錄在二進制日志中,因此可以正確的復制每一行,并且在復制中只需要很少的鎖,可以達到更高的并發(fā)數(shù).但當某些語句做了全表更新時,基于行的復制會有很大開銷,因為每一行的數(shù)據(jù)都會被記錄到二進制日志中,這使得二進制日志事件非常龐大,并且會給主庫記錄日志和復制增加額外的負載.更慢的日志記錄導致降低并發(fā)數(shù).
(3)混合復制 基于語句的復制和基于行的復制各有優(yōu)點和缺點,MySQL可以在復制時在這兩種復制模式間動態(tài)切換.默認情況下使用的是基于語句的復制方式,但如果發(fā)現(xiàn)語句無法被正確執(zhí)行,就切換到基于行的復制模式.
在MySQL5.5以后增加了半同步復制(semisynchronous replication),半同步復制的理念是在允許更改操作繼續(xù)執(zhí)行前,確保更改操作至少被寫入一個備庫的磁盤.半同步復制并沒有暫停提交事務,只是在事務已被寫入到至少一個備庫的中繼日志之前,避免發(fā)送一個答復給客戶端.如圖2所示,在提交事務的過程中,客戶端提交數(shù)據(jù)更改請求以后,在主庫上執(zhí)行,并寫入二進制日志.其中一個備庫連接到主庫接收二進制日志,隨后另一個或多個備庫連接到主庫請求二進制日志,這時,當其中一臺備庫接收完畢,并將此事務寫入到本地中繼日志以后,發(fā)送一個確認標志給主庫,主庫才會給與客戶端事務提交后返回的信息.從過程中可以看到,當事務從主庫提交到備庫之前,如果主庫系統(tǒng)崩潰,則每個連接都有可能丟失一個事務,而每一次事務都是在備庫提交確認信息后才提交給客戶端的,因此最多只會丟失一個事務.
圖2 MySQL半同步復制中事務提交過程
使用半同步復制時,需要主庫和備庫都能夠支持,都要運行MySQL5.5或更高版本,并且啟用半同步復制機制.啟用半同步復制,需要以下步驟:
(1)在主庫上安裝插件:
(2)在每一臺備庫上安裝插件:
之后重啟服務器,半同步復制啟動.
MySQL的復制技術非常靈活,可以根據(jù)不同場景建立不同的復制模型,但需要遵循每個備庫只能有一個主庫這個限制條件.復制有多重拓撲結構,每種都可以擴展為多種用途.最基本的拓撲結構有(1)主從復制拓撲結構,一個主庫和一個備庫相連接;(2)一主多備復制拓撲結構,有兩臺或兩臺以上的備庫連接到主庫上;(3)主主復制拓撲結構,這種結構根據(jù)功能分為主動—主動模式和主動—被動模式,主動—主動模式中的兩個主庫都可以同時寫入數(shù)據(jù),但在同時更新一行記錄時會導致很多問題,主動—被動模式中的寫、讀操作分別在主動、被動主庫上;(4)環(huán)形復制拓撲結構,有三個或更多的主庫,每一個節(jié)點都是在它之前的節(jié)點的備庫,同時是在它之后的節(jié)點的主庫;(5)樹形復制拓撲結構,多個備庫連接到一個主庫上,同時每一個備庫又作為下一層次節(jié)點的主庫.
多源復制(multi-source)與多主復制(multi-master)并不相同,如圖3所示,多主復制通常是環(huán)形復制,在環(huán)中的每一個節(jié)點都作為主庫,每個主庫都可以擁有多個備庫.而多源復制是多個主庫將數(shù)據(jù)復制到一個備庫上.MySQL在版本5.7.2中解除了之前的對于一個備庫只能有一個主庫的限制,但這是一個開發(fā)版本的新功能,只能用來作為測試,還不適用于生產環(huán)境,因此只能從其他途徑來實現(xiàn)多源復制.
圖3 多主復制與多源復制
盡管只能同時有一個主庫,但備庫可以分時連接多個主庫,將備庫在主庫之間進行切換,定時輪流從其中一個主庫復制,近似的實現(xiàn)多源復制,復制的過程如下:
(1)將備庫配置為從一個主庫復制,這個主庫為當前主庫.
(2)設置備庫復制的時間段,備庫從當前主庫中讀取更新,然后在時段內應用這些變化.
(3)使用STOP SLAVE IO_THREAD停止備庫的I/O線程.
(4)等待中繼日志為空,即從主庫中二進制日志中讀取的事件通過SQL線程重放完畢.
(5)使用STOP SLAVE SQL_THREAD停止備庫的SQL線程.
(6)保存當前主庫中備庫讀取的坐標位置.
(7)將備庫的復制按順序轉到下一個主庫上,利用上一次在此主庫上的坐標位置,重新進行連接.
(8)使用START SLAVE重啟備庫的線程.
從第2個步驟開始重復,直到下一個主庫.
整個輪換主庫方式實現(xiàn)MySQL多源復制的過程,可以用腳本實現(xiàn)自動輪換,使用python語言,itertools模塊的cycle函數(shù),可以輪流從主庫中讀取數(shù)據(jù),編寫的腳本代碼如下:
import itertools
position = {}
def multi_master(slave,master):
corrent = masters[0]
for master in itertools. cycle(masters);
slave. sql(“STOP SLAVE IO_THREAD”);
mysqlrep. wait_for_empty_relay_log(slave)
slave. sql(“STOP SLAVE SQL_THEAD”);
positon [current. name]= mysqlrep. fetch_slave_
position(slave)
slave. change_master(position [current,name])
mastar. sql(“START SLAVE”)
current = mastar
sleep(60) #sleep 60 second
MySQL的復制技術是使得MySQL廣泛流行的特性之一,復制技術簡單、便于使用,可以根據(jù)需要進行不同形態(tài)、不同規(guī)模的部署,目前在互聯(lián)網應用的數(shù)據(jù)服務中,有很多的基于MySQL復制技術的成功案例.如果拓撲結構且配置正確,MySQL的復制通常是沒有問題的,并且很少需要調整,但也有很多情況導致故障.比如,主庫崩潰導致二進制時間丟失,主庫上表損壞,在主庫上正常運行的查詢在備庫上異常,備庫連接超時且重連頻繁,備庫上的中繼日志被破壞等等.因此,在使用復制技術的同時,監(jiān)控復制、故障排除和災難恢復顯得更加重要.
[1]Bell C.寧青,等譯.高可用MySQL——構建健壯的數(shù)據(jù)中心[M].北京:電子工業(yè)出版社,2011.10.
[2]Schwartz B.寧海元,等譯.高性能 MySQL[M].北京:電子工業(yè)出版社,2013.5.
[3]張偉麗,姜春華,魏勁超.MySQL復制技術的研究及應用[J].計算機科學,2012(11A):168–170.
[4]劉騰.MySQL復制技術的研究與改進[D].杭州:浙江大學,2011.
[5]方丹輝,張狄.MySQL主從服務器數(shù)據(jù)庫同步的實現(xiàn)[J].計算機應用,2002,22(7):116–117.
[6]蔡亮,劉騰.基于寫操作集的數(shù)據(jù)庫同步復制模型[J].計算機工程,2011(13):61-63