mysql并行復(fù)制降低主從同步延時(shí)的思路與啟示

2018-09-06 17:08 更新

一、緣起

mysql主從復(fù)制,讀寫分離是互聯(lián)網(wǎng)用的非常多的mysql架構(gòu),主從復(fù)制最令人詬病的地方就是,在數(shù)據(jù)量較大并發(fā)量較大的場(chǎng)景下,主從延時(shí)會(huì)比較嚴(yán)重。


為什么mysql主從延時(shí)這么大?
MySQL主從延時(shí)
回答:從庫(kù)使用【單線程】重放relaylog。

優(yōu)化思路是什么?

回答:使用單線程重放relaylog使得同步時(shí)間會(huì)比較久,導(dǎo)致主從延時(shí)很長(zhǎng),優(yōu)化思路不難想到,可以【多線程并行】重放relaylog來(lái)縮短同步時(shí)間。


mysql如何“多線程并行”來(lái)重放relaylog,是本文要分享的主要內(nèi)容。

二、如何多線程并行重放relaylog

多線程并行重放relaylog

通過(guò)多個(gè)線程來(lái)并行重放relaylog是一個(gè)很好縮短同步時(shí)間的思路,但實(shí)施之前要解決這樣一個(gè)問(wèn)題:

如何來(lái)分割relaylog,才能夠讓多個(gè)work-thread并行操作數(shù)據(jù)data時(shí),使得data保證一致性?


首先,【隨機(jī)的分配relaylog肯定是不行的】,假設(shè)relaylog中有這樣三條串行的修改記錄:
update account set money=100 where uid=58;
update account set money=150 where uid=58;

update account set money=200 where uid=58;

串行執(zhí)行:肯定能保證與主庫(kù)的執(zhí)行序列一致,最后得到money=200

隨機(jī)分配并行執(zhí)行:3個(gè)工作線程并發(fā)執(zhí)行這3個(gè)語(yǔ)句,誰(shuí)最后執(zhí)行成功是不確定的,故得到的數(shù)據(jù)可能與主庫(kù)不同


好,對(duì)于這個(gè)問(wèn)題,可以用什么樣的思路來(lái)解決呢(大伙怎么想,mysql團(tuán)隊(duì)其實(shí)也就是這么想的)

【方法一:相同庫(kù)上的寫操作,用相同的work-thread來(lái)重放relaylog;不同庫(kù)上的寫操作,可以用多個(gè)work-thread并發(fā)來(lái)重放relaylog】

用相同的work-thread來(lái)重放relaylog

如何做到呢?

回答:不難,hash(db-name) % thread-num,庫(kù)名hash之后再模上線程數(shù),就能夠做到。


存在的不足?

很多公司對(duì)mysql的使用是“單庫(kù)多表”,如果是這樣的話,仍然是同一個(gè)work-thread在串行執(zhí)行,還是不能提高relaylog的重放速度。


優(yōu)化方案將“單庫(kù)多表”的模式升級(jí)為“多庫(kù)多表”的模式。

其實(shí),數(shù)據(jù)量大并發(fā)量大的互聯(lián)網(wǎng)業(yè)務(wù)場(chǎng)景,“多庫(kù)”模式還具備著其他很多優(yōu)勢(shì),例如:

(1)非常方便的實(shí)例擴(kuò)展:dba很容易將不同的庫(kù)擴(kuò)展到不同的實(shí)例上

(2)按照業(yè)務(wù)進(jìn)行庫(kù)隔離:業(yè)務(wù)解耦,進(jìn)行業(yè)務(wù)隔離,減少耦合與相互影響

(3)…


對(duì)于架構(gòu)師進(jìn)行架構(gòu)設(shè)計(jì)的啟示是:使用多庫(kù)的方式設(shè)計(jì)db架構(gòu),能夠降低主從同步的延時(shí)

新的想法:“單庫(kù)多表”的場(chǎng)景,還有并行執(zhí)行優(yōu)化余地么?

仔細(xì)回顧和思考,即使只有一個(gè)庫(kù),數(shù)據(jù)的修改和事務(wù)的執(zhí)行在主庫(kù)上也是并行操作的,既然在主庫(kù)上可以并行操作,在從庫(kù)上為啥就不能并行操作,而要按照庫(kù)來(lái)串行執(zhí)行呢(表示不服)?

新的思路將主庫(kù)上同時(shí)并行執(zhí)行的事務(wù),分為一組,編一個(gè)號(hào),這些事務(wù)在從庫(kù)上的回放可以并行執(zhí)行(事務(wù)在主庫(kù)上的執(zhí)行都進(jìn)入到prepare階段,說(shuō)明事務(wù)之間沒(méi)有沖突,否則就不可能提交),沒(méi)錯(cuò),mysql正是這么做的。


【方法二:基于GTID的并行復(fù)制】

新版的mysql,將組提交的信息存放在GTID中,使用mysqlbinlog工具,可以看到組提交內(nèi)部的信息:

20160607 23:22 server_id 58 XXX GTID last_committed=0 sequence_numer=1
20160607 23:22 server_id 58 XXX GTID last_committed=0 sequence_numer=2
20160607 23:22 server_id 58 XXX GTID last_committed=0 sequence_numer=3
20160607 23:22 server_id 58 XXX GTID last_committed=0 sequence_numer=4
基于GTID的并行復(fù)制

和原來(lái)的日志相比,多了last_committed和sequence_number。

last_committed表示事務(wù)提交時(shí),上次事務(wù)提交的編號(hào),如果具備相同的last_committed,說(shuō)明它們?cè)谝粋€(gè)組內(nèi),可以并發(fā)回放執(zhí)行。


三、結(jié)尾

從mysql并行復(fù)制縮短主從同步時(shí)延的思想可以看到,架構(gòu)的思路是相同的:

(1)多線程是一種常見(jiàn)的縮短執(zhí)行時(shí)間的方法

(2)多線程并發(fā)分派任務(wù)時(shí)必須保證冪等性:mysql的演進(jìn)思路,提供了“按照庫(kù)冪等”,“按照commit_id冪等”兩種方式,思路大伙可以借鑒


另,mysql在并行復(fù)制上的逐步優(yōu)化演進(jìn):

mysql5.5 -> 不支持并行復(fù)制,對(duì)大伙的啟示:升級(jí)mysql吧

mysql5.6 -> 按照庫(kù)并行復(fù)制,對(duì)大伙的啟示:使用“多庫(kù)”架構(gòu)吧

mysql5.7 -> 按照GTID并行復(fù)制


我不是mysql的開發(fā)人員,也不是專業(yè)的dba,本文僅為一個(gè)思路的分享,希望大伙有收獲,如果不對(duì)也歡迎隨時(shí)指出。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)