標籤:
業務零影響!如何在Online環境中巧用MySQL傳統複製技術
這篇文章我並不會介紹如何部署一個MySQL複製環境或keepalived+雙主環境,因為此類安裝搭建的文章已經很多,大家也很熟悉。在這篇文章裡,我主要是介紹MySQL複製技術在Online【線上業務系統】環境裡如何進行架構上的調整,同時這些調整對線上業務系統的影響又是儘可能的小甚至是零影響。希望大家能有所收穫。
1MySQL複製中的監控管理
大家都知道,MySQL複製(不論是經典傳統複製還是5.6新引入的GTID複製)都是以io_thread和sql_thread這兩個核心線程為基礎來實現的。(關於複製的原理在這篇文章我就不過多闡述,有興趣可以關注我以後的文章)
那我們在實際工作中需要關心以下幾個問題:
顯然,在Slave裡的show slave status\G給我們提供了足夠的資訊來確認以上的問題。(雙主環境,兩個複製節點均有show slave status\G資訊)
show slave status\G中首先要看的資訊是:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_IO_Running代表io_thread是否正常工作,Slave_SQL_Running代表sql_thread是否正常工作。如果有出現No,那你的複製環境應該就需要警示了。
但僅僅只關注這兩個指標還遠遠不夠,show slave status\G輸出資訊裡我們還需要關注的值是:Seconds_Behind_Master【單位是秒】。
Seconds_behind_master = 0 表示沒有延遲, >0表示有延遲,當為的時候,表示複製可能出錯了。
在實際工作中,我發現很多DBA朋友通常都只根據Seconds_Behind_Master的值判斷Slave是否存在延遲,這在部分情況裡尚可接受,但並不夠準確。特別是業務高並發的系統裡,我更不建議你使用Seconds_Behind_Master來作為判定複寫延遲的標準。
也就是說,Seconds_Behind_Master並不能非常準確地體現複寫延遲,我們還需要考慮更多的因素。
真正來準確判斷Slave是否存在延遲,我們應該從複製的binlog檔案名稱和binlog位置是否一致來入手。
我們知道,show slave status\G的輸出結果中:
大多數時候,可以通過io_thread 和sql_thread執行的位置進行對比,來確認是不是存在延遲。(因為在大多數時候,io_thread很少會存在延遲,一般都是sql_thread存在延遲,這種比較方法的前提是我們可以把io_thread的執行位置看作跟主庫show master status的位置一致的)
當show slave status\G輸出的這幾個指標資訊滿足上面的條件,我們則可以認為複製不存在延遲,是即時同步完成的。
如果你對io_thread的延遲也存在擔憂【比如複製環境的網路不好等因素】,更嚴謹的思路是下面這樣:
具體實現思路是:
在第三方監控節點上,對MASTER和SLAVE同時發起SHOW BINARY LOGS【或者SHOW MASTER STATUS】和SHOW SLAVE STATUS\G的請求,然後按照上面的公式去判斷是否存在差異。
當然,這麼做起來的話,指令碼實現相對麻煩,而且對第三方監控節點的網路要求也非常高,同時,由於io_thread一般不會是瓶頸,所以在做指令碼監控的時候,不會這麼幹。大多數時候按照我之前說的做法來監控複寫延遲就已經足夠了:
還有一種監控MySQL複製的方式是:通過維護一個監控表來判定複寫延遲。
可以在MASTER上維護一個監控表,一般只有兩個欄位(id和time),儲存這最新最新時間戳記(高版本MySQL可以採用event_scheduler來更新,低版本可以用Linux cron結合自動迴圈指令碼來更新),然後在SLAVE上讀取該欄位的時間,只要MASTER和SLAVE的系統時間【NTP是必須的】一致,即可快速知道SLAVE和MASTER延遲差了多少。
舉例:
這種監控方式稱為update心跳。
另外注意,在高並發的系統下,這個時間戳記需要細化到毫秒,否則哪怕時間一致,也是有可能會延遲數個binlog event的。
以上是MySQL傳統複製中在監控這一塊需要我們注意的一些地方,只要我們把思路理清,編寫一個MySQL複製的監控指令碼應該是順理成章的事情。(用python、perl、shell或其他語言寫一個都應該問題不大)
那接下來,進入我們的正題。
2MySQL複製中Online(線上)架構的調整
首先我要強調下線上架構,因為在一個已經離線(停機)的環境裡做架構調整並沒有太多技術含量。
線上架構,就是已經投入在使用的架構,已經面向業務使用者開放的系統架構。
線上架構,意味著資料每份每秒都在不停得寫入,show master status的log_file和log_pos,時刻都在進行變化。資料是不會靜止的,這就是線上架構。
這和公司裡的開發環境或測試環境不同,是線上線上的環境。
那我們下面說的複製架構調整,就是必須在Online這個背景下來做調整的。
另外,下面的介紹基於MySQL傳統複製,如果是使用MySQL5.6以後的GTID複製,你可以不用太關心下面的內容。 GTID複製在營運上比傳統複製方便了很多,有關GTID複製的內容會在以後的文章裡講解。
第一個實戰:如何在一個線上架構的複製環境裡引入VIP
假設我們已經線上的一個簡單的主從環境如下:
應用的串連全部都是連在192.168.1.10的master上進行訪問的。
我們這裡想通過實現一次Online(線上)切換,來實現MySQL的記憶體擴容,因為Slave的記憶體是32G。
按照目前的架構,在做切換完成後,我們得需要修改應用伺服器的IP地址為192.168.1.11,那這個操作肯定會影響業務系統使用,無法滿足線上架構系統的要求。
更好的解決方案是給目前的複製環境引入一個虛擬IP(VIP),通過VIP來實現切換,這樣線上切換起來的影響會小很多。
假設我們申請的VIP是:192.168.1.20
那我們把這個VIP先綁到master上:
master的主機節點上會有兩個IP:
192.168.1.10【Real_IP】
192.168.1.20【VIP】 這個是我們手工綁上的。
那我們現在要考慮的是線上把應用伺服器的資料庫地址串連改192.168.1.20:3306 ,這個影響有多大?
實際的情況取決與你前端應用伺服器的架構了,如果你的前端應用伺服器只有一台,那肯定還是有影響的,但大多數時候,前端的應用伺服器也是叢集架構,都是能實現無狀態的。那其實只要前端應用伺服器的結構稍微合理,這個引入VIP的操作是0影響的。
引入VIP後【實際上就是在node1上綁定一個VIP】,應用伺服器就都通過VIP串連到資料庫了,架構如下:
這裡的切換,我們不引入任何第三方的組件,什麼keepalived,MHA都不考慮,我們就是自己寫指令碼來做切換。
我們來看下,手動指令碼切換的思路,前提還是我們說的線上架構:
1. 前置準備
master【node1】 vip unbind【VIP解除綁定】,同時檢查原來的master是否還有串連及串連的處理,如果還存在串連,要考慮把這些串連都幹掉:
然後source /tmp/1.sql 就行了。
master上幹掉殘餘串連後,前置準備還要注意下slave的read_only問題,如果slave設定了read_only,記得取消。
master幹掉串連後,可以短暫的實現資料靜止。
2. 接管VIP之前需要做複製一致性檢查
這個複製一致性檢查很簡單,我們之前講的老辦法:
確認複製pos都對上了,node2才能接管VIP,這裡在指令碼裡面最好把判斷一致性通過的log_file和log_pos記錄下來。
3. node2上綁定VIP
slave vip bind
這樣就完成了整個的切換流程。
總結來說,非常簡單:
複製環境引入VIP,修改應用伺服器串連資料庫地址為VIP
解除綁定原master上的VIP
幹掉原master上的所有應用串連
檢查同步一致性
slave上綁定vip
以上這些動作,如果指令碼準備充分,執行指令碼一般3-5秒就可以搞定了。
雖然是線上架構,3-5秒左右的資料庫短暫影響,在業務低峰期應用基本是無感知的【切換我們還是需要錯峰來執行】,絕對能滿足線上架構系統的要求。
另外的一個注意點就是要確保檢查同步都完成了,同步沒完成的話,是還要花一點時間等待直到完成為止。
那成功切換後,現在VIP綁定在了node2上【新的master】,那node1重新要從node2上同步資料,node1變為slave,這裡分情況討論:
如果node1和node2之前做的是雙master架構,那最簡單,不用多管【實際架構中雙master也是最多用的,就是切換後維護方便】
如果node1和node2隻做了主從架構,那還得在之前的指令碼裡【檢查同步是否完成這1步中】記錄下log_file和log_pos,在node1【新的slave】上重新做一次change master to master_log_file=XXX,master_log_pos=XXX,然後在node2【新的master】上reset slave all,清空原來的show slave status\G資訊
第二個實戰:線上系統內容中調整為MySQL級聯複製架構
假設,現有的架構如下:
目前的架構是:
A->B(單向複製)
A->C(單向複製)
如何把上面的架構調整為:A->B->C 的級聯複製架構呢?
同樣,我們需要線上實現,不能對業務有太大影響【假設業務都是在master上執行,沒有做讀寫分離拆分】
這裡的思路是:
操作步驟:
1.(master)A上執行 : create table biaobiao(id int);
2.(slave)B和C上執行: drop table biaobiao;
3.(master)A上執行 : drop table biaobiao;
上面的操作會導致B、C上同步報錯,都報錯後【sql thread報錯】,我們就可以開始比對sql_thread執行的位置了(實際目的就是人為地去讓B和C停在同一個位置上)
4.slave1(B)和slave2(C)上show slave status\G 發現報錯,同時檢查各個複製點的位置是否相等(此時Slave上的sql_thread應該都停止工作了):
檢查複製點位置的公式如下:
檢查後公式都相等,就代表B和C已經停到同一個複製位置了。B和C的資料此時應該是完全一致。
此時B和C上的relay_master_log_file和exec_master_log_pos 都不會變化了。
一旦讓B和C停在了同一個位置,那接下來的事情就好辦了。
此時,C就變成了B的Slave
完成了架構調整 A->B->C
如果指令碼來做,一定要在B上多做幾次show master status,確保輸出不會變化,靜止下來,同時B和C的pos要相等:
B節點: show master status;
sleep(10);
B節點: show master status;
因為此時sql thread已經報錯卡住了【sql_thread:no 、io_thread:yes】,因此前後的show master status在B上肯定是一致的。
B是靜止的,C也是靜止的,然後B和C的exec_master_log_pos相等。
接下來還沒完,還需要恢複A->B的複製,A到B的複製sql thread人為搞斷了,還得恢複:
在B上跳過複製錯誤,在B上執行
因為,這個複製錯誤是我們人工類比出來的,是有把握的,所以才能跳過。任何沒有把握的複製錯誤,都是不能輕易跳過的。
8.最後全部恢複後,進行一把測試,測試下新的架構是否通的。有條件再效驗下資料。
這裡,完成了我們需求的複製線上架構調整。
第三個實戰:雙master複製環境中的營運管理
實際上,業務規模稍微大一點的公司,在做MySQL的時候都會搭建雙master【主主】架構。相較於單向的主從複製,雙master架構在營運管理上相對更方便,省事。因為單向的主從結構,在發生主從切換後,還得在原來舊的master上再搞一次change master to ,同時在新的master上執行reset slave all;
這就比雙master複製架構稍顯繁瑣了。雙master架構在發生切換後,撒事不用做,僅漂移VIP就行了【雙master和keeaplived這類HA組件結合起來也能非常方便得實現自動切換】。
那如果僅僅就是兩個節點的雙master環境,大家需要注意的就是在生產環境保持其中一個節點來進行業務資料寫入就好了。
那為什麼明明雙master是雙向複製,照理兩個節點都可以雙向同時寫入資料,我這裡卻只建議大家單邊寫入呢?單邊寫是不是有點浪費資源呢?
也許有朋友會答到MySQL裡面有兩個不錯的參數:
我只要在雙master的兩個節點上分別把這兩個參數配置正確,就可以很好的解決雙寫衝突的問題,同時也最大化的利用了伺服器資源,減緩了單台的寫入壓力。
的確,利用auto_increment_increment和auto_increment_offset能夠解決部分的寫入衝突問題,但是僅僅只能解決insert的衝突,但遇到是針對同一行資料的update和delete操作,配置這兩個參數還是搞不定的。
試想一下,在雙master的兩個節點上同時發起下面這條SQL語句【假設在業務高峰期並發度高的時候】:
update tb set col1=xxx where id = 1;
顯然會引起寫入衝突和鎖競爭,就無疑就給我們挖坑了。
因此,auto_increment_increment和auto_increment_offset參數其實只能解決insert的寫入衝突,而對同一行的update或delete衝突卻無法解決。
也許你還會說,我們公司的業務拆分做得不錯,在node1我們只會寫A表,在node2上只會寫B表,不可能在兩個節點上發生update同一行資料的問題。這聽起來確實是一個不錯的最終解決寫入衝突的方案,但你依然可能遇到另外一個問題:
如果啟用雙節點雙邊寫,其中一個節點不幸掛掉的話,切換另外一個節點能順利接管嗎?你會面臨效能瓶頸的問題,在大多數時候,你用了兩個節點的資源來承擔讀寫壓力,當突然變成一個節點來承擔所有的讀寫壓力時候,這個節點的效能能抗得住嗎?
這跟Oracle RAC的架構設計有點類似,兩個節點同時提供服務的話,你還得考慮很多效能上的問題,每個節點都要做效能的預留,不然其中一個節點掛了,另外一個節點就算你能故障切換過來,效能扛不住的話也是一點意義沒有。
因此,在雙master複製環境中我建議大家用單節點抗業務就好了,另外一個節點就完全預留做為故障切換使用,沒有必要用兩個節點來同時承擔業務壓力,因為這可能會給我們在營運管理上挖坑。
這是雙master架構裡只有兩個節點的營運管理注意點,但很多時候,我們還會為雙master環境引入一個或多個slave來分擔讀(read)的壓力,或者用來做一些經分統計和統計報表用,就像下面這樣:
上面這種架構才是我們實際營運管理工作中最常見的架構。
在裡面:
在這類架構中,我們要理清的第一個問題是:
S1是掛在M1上,還是掛在M2上,或者說是掛在W_VIP上呢?
另外,如果把S1掛在M1這個抗業務的節點上,那當M1節點不幸掛掉,在傳統複製原理下,S1和M2就很難聯絡起來了。、
因此,正確答案是:S1必須掛在不是抗業務的那個雙master節點上,即掛在圖裡的M2這個節點,這樣做的好處是當M1不幸掛掉,M2和S1的複製不會受到任何影響。
這是我們設計架構時的注意點。
另外一個重要的注意點是,當M1掛掉後,W_VIP會漂移到M2節點上,保證應用程式繼續能正常串連資料庫,像這樣:
那當M1掛掉後,我們把M1修複好後,M1還會繼續加入到複製叢集架構裡,像下面這樣:
此時的架構變為了:
M2->S
M2<->M1
但如果是這樣的架構,就和我們剛才提到的設計依據:
我們還需要想辦法從左邊的架構調整為右邊的架構,同樣,這個調整我們肯定也需要在Online線上業務的背景下去完成。
那這個調整其實跟我們在第二個實戰裡講的案例非常類似了。
原來的架構是:
M2<->M1(雙向複製)
M2->S1(單向複製)
現在要把架構調成為:M2<->M1->S1(級聯複製)
要實現這個調整的辦法,我們就可以完全照著第二個實戰裡說的方法來做【這裡請大家回到前面的內容,再仔細閱讀一遍】。
基本的思路依然是讓保持對M2的0影響,而通過人為的類比複製錯誤讓M1和S1停在相同的複製點位上。
這裡稍微不同的就是因為M2和M1互為主主,M1上的人為類比操作也會同步到M2上,所以在M1上做人為類比操作的時候,要記得臨時禁止寫binlog,免得把M1上做的人為類比操作也同步到M2上了。
後面的步驟和我們在第二個實戰裡面講的步驟完全一致,照搬就行了。我就不贅述了。
完成以上的調整,才算一個雙master+slave複製架構的切換完成。
第四個實戰: 線上系統內容把級聯複製架構再調整回一主多從的架構
原來的架構是:A->B->C【級聯複製】
現在要把架構調成為:
A->B
A->C 【一主兩從】
同樣,A節點是抗應用業務的節點。
其實經過我們之前的幾個案例,這個案例是很簡單的了,這個我就簡單提下:
對上面的這類需求,在B節點上stop slave就行了,stop後等待會,B和C的資料應該就能一致了:
檢查公式:
滿足以上公式,代表B節點和C節點的同步是一致的了。
接下來在C上進行change master的修改,change master到A上,在C節點的MySQL上操作:
注意,這裡要取B節點上show slave status\G的relay_master_log_file , exec_master_log_pos
start slave;
最後回到B節點的MySQL上操作:
start slave;
整個架構調整完成。
總結
以上是一些工作中的總結,重點在於給大家提供一種思路,希望大家能在這個基礎上繼續擴充思維。
有了清晰的思路,編寫一些MySQL複製營運中的管理指令碼也並不是難事。
如果大家在編寫複製管理的指令碼中遇到任何問題,也可以隨時找我交流。
另外,每個公司的業務對線上【Online】架構的要求可能是不同的,有的公司業務在Online環境裡也能容忍在特定時間的3-5秒甚至更長時間的業務暫停寫入,而有的公司業務卻是0容忍,我們應該緊密結合業務上的需求,以需求為導向,才能更好的完成MySQL複製管理工作。
當然,隨著MySQL版本的不斷髮展,比如:MySQL5.6引入的GTID複製,MySQL5.7引入的group commit和並行複製,這些新的技術也逐漸讓MySQL的複製營運管理工作變得更加得便捷,高效。
但是,不論技術如何發展和變化,掌握MySQL經典傳統複製的營運管理技巧仍然能幫我們搞定很多線上環境的管理需求。
轉自
業務零影響!如何在Online環境中巧用MySQL傳統複製技術_Mysql_資料庫-ITnose
http://www.itnose.net/detail/6525929.html
業務零影響!如何在Online環境中巧用MySQL傳統複製技術【轉】