MySQL高可用淺析

對于多數(shù)應用來說杠娱,MySQL都是作為最關鍵的數(shù)據(jù)存儲中心的匪煌,所以,如何讓MySQL提供HA服務应民,是我們不得不面對的一個問題吼拥。當master當機的時候倚聚,我們?nèi)绾伪WC數(shù)據(jù)盡可能的不丟失,如何保證快速的獲知master當機并進行相應的故障轉移處理凿可,都是需要我們好好思考的惑折。這里,筆者將結合這段時間做的MySQL proxy以及toolsets相關工作枯跑,說說我們現(xiàn)階段以及后續(xù)會在項目中采用的MySQL HA方案惨驶。

Replication

要保證MySQL數(shù)據(jù)不丟失,replication是一個很好的解決方案敛助,而MySQL也提供了一套強大的replication機制粗卜。只是我們需要知道,為了性能考量纳击,replication是采用的asynchronous模式续扔,也就是寫入的數(shù)據(jù)并不會同步更新到slave上面,如果這時候master當機焕数,我們?nèi)匀豢赡軙媾R數(shù)據(jù)丟失的風險纱昧。

為了解決這個問題,我們可以使用semi-synchronous replication堡赔,semi-synchronous replication的原理很簡單识脆,當master處理完一個事務,它會等待至少一個支持semi-synchronous的slave確認收到了該事件并將其寫入relay-log之后,才會返回存璃。這樣即使master當機仑荐,最少也有一個slave獲取到了完整的數(shù)據(jù)。

但是纵东,semi-synchronous并不是100%的保證數(shù)據(jù)不會丟失粘招,如果master在完成事務并將其發(fā)送給slave的時候崩潰,仍然可能造成數(shù)據(jù)丟失偎球。只是相比于傳統(tǒng)的異步復制洒扎,semi-synchronous replication能極大地提升數(shù)據(jù)安全。更為重要的是衰絮,它并不慢袍冷,MHA的作者都說他們在facebook的生產(chǎn)環(huán)境中使用了semi-synchronous(這里),所以我覺得真心沒必要擔心它的性能問題猫牡,除非你的業(yè)務量級已經(jīng)完全超越了facebook或者google胡诗。在這篇文章里面已經(jīng)提到,MySQL 5.7之后已經(jīng)使用了Loss-Less Semi-Synchronous replication淌友,所以丟數(shù)據(jù)的概率已經(jīng)很小了煌恢。

如果真的想完全保證數(shù)據(jù)不會丟失,現(xiàn)階段一個比較好的辦法就是使用gelera震庭,一個MySQL集群解決方案瑰抵,它通過同時寫三份的策略來保證數(shù)據(jù)不會丟失。筆者沒有任何使用gelera的經(jīng)驗器联,只是知道業(yè)界已經(jīng)有公司將其用于生產(chǎn)環(huán)境中二汛,性能應該也不是問題。但gelera對MySQL代碼侵入性較強拨拓,可能對某些有代碼潔癖的同學來說不合適了:-)

我們還可以使用drbd來實現(xiàn)MySQL數(shù)據(jù)復制肴颊,MySQL官方文檔有一篇文檔有詳細介紹,但筆者并未采用這套方案千元,MHA的作者寫了一些采用drdb的問題苫昌,在這里,僅供參考幸海。

在后續(xù)的項目中祟身,筆者會優(yōu)先使用semi-synchronous replication的解決方案,如果數(shù)據(jù)真的非常重要物独,則會考慮使用gelera袜硫。

Monitor

前面我們說了使用replication機制來保證master當機之后盡可能的數(shù)據(jù)不丟失,但是我們不能等到master當了幾分鐘才知道出現(xiàn)問題了挡篓。所以一套好的監(jiān)控工具是必不可少的婉陷。

當master當?shù)糁笾愠疲琺onitor能快速的檢測到并做后續(xù)處理,譬如郵件通知管理員秽澳,或者通知守護程序快速進行failover闯睹。

通常,對于一個服務的監(jiān)控担神,我們采用keepalived或者heartbeat的方式楼吃,這樣當master當機之后,我們能很方便的切換到備機上面妄讯。但他們?nèi)匀徊荒芎芗磿r的檢測到服務不可用孩锡。筆者的公司現(xiàn)階段使用的是keepalived的方式,但后續(xù)筆者更傾向于使用zookeeper來解決整個MySQL集群的monitor以及failover亥贸。

對于任何一個MySQL實例躬窜,我們都有一個對應的agent程序,agent跟該MySQL實例放到同一臺機器上面炕置,并且定時的對MySQL實例發(fā)送ping命令檢測其可用性荣挨,同時該agent通過ephemeral的方式掛載到zookeeper上面。這樣讹俊,我們可以就能知道MySQL是否當機垦沉,主要有以下幾種情況:

  1. 機器當機,這樣MySQL以及agent都會當?shù)羧耘琣gent與zookeeper連接自然斷開
  2. MySQL當?shù)簦琣gent發(fā)現(xiàn)ping不通寡壮,主動斷開與zookeeper的連接
  3. Agent當?shù)舴犯恚玀ySQL未當

上面三種情況,我們都可以認為MySQL機器出現(xiàn)了問題况既,并且zookeeper能夠立即感知这溅。agent與zookeeper斷開了連接,zookeeper觸發(fā)相應的children changed事件棒仍,監(jiān)控到該事件的管控服務就可以做相應的處理悲靴。譬如如果是上面前兩種情況,管控服務就能自動進行failover莫其,但如果是第三種癞尚,則可能不做處理,等待機器上面crontab或者supersivord等相關服務自動重啟agent乱陡。

使用zookeeper的好處在于它能很方便的對整個集群進行監(jiān)控浇揩,并能即時的獲取整個集群的變化信息并觸發(fā)相應的事件通知感興趣的服務,同時協(xié)調(diào)多個服務進行相關處理憨颠。而這些是keepalived或者heartbeat做不到或者做起來太麻煩的胳徽。

使用zookeeper的問題在于部署起來較為復雜积锅,同時如果進行了failover,如何讓應用程序獲取到最新的數(shù)據(jù)庫地址也是一個比較麻煩的問題养盗。

對于部署問題缚陷,我們要保證一個MySQL搭配一個agent,幸好這年頭有了docker往核,所以真心很簡單蹬跃。而對于第二個數(shù)據(jù)庫地址更改的問題,其實并不是使用了zookeeper才會有的铆铆,我們可以通知應用動態(tài)更新配置信息蝶缀,VIP,或者使用proxy來解決薄货。

雖然zookeeper的好處很多翁都,但如果你的業(yè)務不復雜,譬如只有一個master谅猾,一個slave柄慰,zookeeper可能并不是最好的選擇,沒準keepalived就夠了税娜。

Failover

通過monitor坐搔,我們可以很方便的進行MySQL監(jiān)控,同時在MySQL當機之后通知相應的服務做failover處理敬矩,假設現(xiàn)在有這樣的一個MySQL集群概行,a為master,b弧岳,c為其slave凳忙,當a當?shù)糁螅覀冃枰鰂ailover禽炬,那么我們選擇b涧卵,c中的哪一個作為新的master呢?

原則很簡單腹尖,哪一個slave擁有最近最多的原master數(shù)據(jù)柳恐,就選哪一個作為新的master。我們可以通過show slave status這個命令來獲知哪一個slave擁有最新的數(shù)據(jù)热幔。我們只需要比較兩個關鍵字段Master_Log_File以及Read_Master_Log_Pos乐设,這兩個值代表了slave讀取到master哪一個binlog文件的哪一個位置,binlog的索引值越大断凶,同時pos越大伤提,則那一個slave就是能被提升為master。這里我們不討論多個slave可能會被提升為master的情況认烁。

在前面的例子中肿男,假設b被提升為master了介汹,我們需要將c重新指向新的master b來開始復制。我們通過CHANGE MASTER TO來重新設置c的master舶沛,但是我們怎么知道要從b的binlog的哪一個文件嘹承,哪一個position開始復制呢?

GTID

為了解決這一個問題如庭,MySQL 5.6之后引入了GTID的概念叹卷,即uuid:gid,uuid為MySQL server的uuid坪它,是全局唯一的骤竹,而gid則是一個遞增的事務id,通過這兩個東西往毡,我們就能唯一標示一個記錄到binlog中的事務蒙揣。使用GTID,我們就能非常方便的進行failover的處理开瞭。

仍然是前面的例子懒震,假設b此時讀取到的a最后一個GTID為3E11FA47-71CA-11E1-9E33-C80AA9429562:23,而c的為3E11FA47-71CA-11E1-9E33-C80AA9429562:15嗤详,當c指向新的master b的時候个扰,我們通過GTID就可以知道,只要在b中的binlog中找到GTID為3E11FA47-71CA-11E1-9E33-C80AA9429562:15這個event葱色,那么c就可以從它的下一個event的位置開始復制了递宅。雖然查找binlog的方式仍然是順序查找,稍顯低效暴力冬筒,但比起我們自己去猜測哪一個filename和position恐锣,要方便太多了。

google很早也有了一個Global Transaction ID的補丁舞痰,不過只是使用的一個遞增的整形,LedisDB就借鑒了它的思路來實現(xiàn)failover诀姚,只不過google貌似現(xiàn)在也開始逐步遷移到MariaDB上面去了响牛。

MariaDB的GTID實現(xiàn)跟MySQL 5.6是不一樣的,這點其實比較麻煩赫段,對于我的MySQL工具集go-mysql來說呀打,意味著要寫兩套不同的代碼來處理GTID的情況了。后續(xù)是否支持MariaDB再看情況吧糯笙。

Pseudo GTID

GTID雖然是一個好東西贬丛,但是僅限于MySQL 5.6+,當前仍然有大部分的業(yè)務使用的是5.6之前的版本给涕,筆者的公司就是5.5的豺憔,而這些數(shù)據(jù)庫至少長時間也不會升級到5.6的额获。所以我們?nèi)匀恍枰惶缀玫臋C制來選擇master binlog的filename以及position。

最初恭应,筆者打算研究MHA的實現(xiàn)抄邀,它采用的是首先復制relay log來補足缺失的event的方式,但筆者不怎么信任relay log昼榛,同時加之MHA采用的是perl境肾,一個讓我完全看不懂的語言,所以放棄了繼續(xù)研究胆屿。

幸運的是奥喻,筆者遇到了orchestrator這個項目,這真的是一個非常神奇的項目非迹,它采用了一種Pseudo GTID的方式环鲤,核心代碼就是這個

create database if not exists meta;

drop event if exists meta.create_pseudo_gtid_view_event;

delimiter ;;
create event if not exists
  meta.create_pseudo_gtid_view_event
  on schedule every 10 second starts current_timestamp
  on completion preserve
  enable
  do
    begin
      set @pseudo_gtid := uuid();
      set @_create_statement := concat('create or replace view meta.pseudo_gtid_view as select \'', @pseudo_gtid, '\' as pseudo_gtid_unique_val from dual');
      PREPARE st FROM @_create_statement;
      EXECUTE st;
      DEALLOCATE PREPARE st;
    end
;;

delimiter ;

set global event_scheduler := 1;

它在MySQL上面創(chuàng)建了一個事件,每隔10s彻秆,就將一個uuid寫入到一個view里面楔绞,而這個是會記錄到binlog中的,雖然我們?nèi)匀徊荒芟馟TID那樣直接定位到一個event唇兑,但也能定位到一個10s的區(qū)間了酒朵,這樣我們就能在很小的一個區(qū)間里面對比兩個MySQL的binlog了。

繼續(xù)上面的例子扎附,假設c最后一次出現(xiàn)uuid的位置為s1蔫耽,我們在b里面找到該uuid,位置為s2留夜,然后依次對比后續(xù)的event匙铡,如果不一致,則可能出現(xiàn)了問題碍粥,停止復制鳖眼。當遍歷到c最后一個binlog event之后,我們就能得到此時b下一個event對應的filename以及position了嚼摩,然后讓c指向這個位置開始復制钦讳。

使用Pseudo GTID需要slave打開log-slave-update的選項,考慮到GTID也必須打開該選項枕面,所以個人感覺完全可以接受愿卒。

后續(xù),筆者自己實現(xiàn)的failover工具潮秘,將會采用這種Pseudo GTID的方式實現(xiàn)琼开。

在《MySQL High Availability》這本書中,作者使用了另一種GTID的做法枕荞,每次commit的時候柜候,需要在一個表里面記錄gtid搞动,然后就通過這個gtid來找到對應的位置信息,只是這種方式需要業(yè)務MySQL客戶端的支持改橘,筆者不很喜歡滋尉,就不采用了。

后記

MySQL HA一直是一個水比較深的領域飞主,筆者僅僅列出了一些最近研究的東西狮惜,有些相關工具會盡量在go-mysql中實現(xiàn)。

更新

經(jīng)過一段時間的思考與研究碌识,筆者又有了很多心得與收獲碾篡,設計的MySQL HA跟先前有了很多不一樣的地方。后來發(fā)現(xiàn)筏餐,自己設計的這套HA方案开泽,跟facebook這篇文章幾乎一樣,加之最近跟facebook的人聊天聽到他們也正在大力實施魁瞪,所以感覺自己方向是對了穆律。

新的HA,我會完全擁抱GTID导俘,比較這玩意的出現(xiàn)就是為了解決原先replication那一堆問題的峦耘,所以我不會考慮非GTID的低版本MySQL了。幸運的是旅薄,我們項目已經(jīng)將MySQL全部升級到5.6辅髓,完全支持GTID了。

不同于fb那篇文章將mysqlbinlog改造支持semi-sync replication協(xié)議少梁,我是將go-mysql的replication庫支持semi-sync replication協(xié)議洛口,這樣就能實時的將MySQL的binlog同步到一臺機器上面。這可能就是我和fb方案的唯一區(qū)別了凯沪。

只同步binlog速度鐵定比原生slave要快第焰,畢竟少了執(zhí)行binlog里面event的過程了,而另外真正的slaves妨马,我們?nèi)匀皇褂米钤嫉耐椒绞秸燎玻皇褂胹emi-sync replication。然后我們通過MHA監(jiān)控整個集群以及進行故障轉移處理身笤。

以前我總認為MHA不好理解,但其實這是一個非常強大的工具葵陵,而且真正看perl液荸,發(fā)現(xiàn)也還是看的懂得。MHA已經(jīng)被很多公司用于生產(chǎn)環(huán)境脱篙,經(jīng)受了檢驗娇钱,直接使用絕對比自己寫一個要劃算伤柄。所以后續(xù)我也不會考慮zookeeper,考慮自己寫agent了文搂。

不過适刀,雖然設想的挺美好,但這套HA方案并沒有在項目中實施煤蹭,主要原因在于筆者打算近期離職笔喉,如果現(xiàn)在貿(mào)然實施,后續(xù)出問題了就沒人維護了硝皂。:-)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末常挚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稽物,更是在濱河造成了極大的恐慌奄毡,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贝或,死亡現(xiàn)場離奇詭異吼过,居然都是意外死亡,警方通過查閱死者的電腦和手機咪奖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門盗忱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赡艰,你說我怎么就攤上這事售淡。” “怎么了慷垮?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵揖闸,是天一觀的道長。 經(jīng)常有香客問我料身,道長汤纸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任芹血,我火速辦了婚禮贮泞,結果婚禮上,老公的妹妹穿的比我還像新娘幔烛。我一直安慰自己啃擦,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布饿悬。 她就那樣靜靜地躺著令蛉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上珠叔,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天蝎宇,我揣著相機與錄音,去河邊找鬼祷安。 笑死姥芥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的汇鞭。 我是一名探鬼主播凉唐,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼虱咧!你這毒婦竟也來了熊榛?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤腕巡,失蹤者是張志新(化名)和其女友劉穎玄坦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绘沉,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡煎楣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了车伞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片择懂。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖另玖,靈堂內(nèi)的尸體忽然破棺而出困曙,到底是詐尸還是另有隱情,我是刑警寧澤谦去,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布慷丽,位于F島的核電站,受9級特大地震影響鳄哭,放射性物質(zhì)發(fā)生泄漏要糊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一妆丘、第九天 我趴在偏房一處隱蔽的房頂上張望锄俄。 院中可真熱鬧,春花似錦勺拣、人聲如沸奶赠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽车柠。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竹祷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工羊苟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留塑陵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓蜡励,卻偏偏與公主長得像令花,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凉倚,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容