Mysql的主從復(fù)制

Mysql主備流程圖.png

同步的步驟如下
1.在備庫B上通過change master命令,設(shè)置主庫A的ip,端口,用戶名,密碼,以及要從哪個(gè)位置開始請(qǐng)求binlog,這個(gè)位置包含文件名和偏移量
2.在備庫B上執(zhí)行start slave命令,這時(shí)候備庫會(huì)啟動(dòng)兩個(gè)線程,就是圖中的io_thread和sql_thread.其中io_thread負(fù)責(zé)與主庫建立連接
3.主庫a校驗(yàn)完用戶名,密碼之后,開始按照備庫B傳過來的位置,從本地讀取binlog,發(fā)送給b
4.備庫B拿到binlog后,寫到本地文件,稱為中繼日志(relay log)
5.sql_thread讀取中繼日志,解析出日志里面的命令,并執(zhí)行

備注:主要采用row格式的日志而不是statement,因?yàn)橛袝r(shí)候主庫與從庫或者容災(zāi)恢復(fù)的時(shí)候數(shù)據(jù)庫版本不一致導(dǎo)致的對(duì)sql的支持不一定進(jìn)而導(dǎo)致復(fù)制出問題,當(dāng)然這只是打個(gè)比方


主從復(fù)制的一些問題以及解決方案

循環(huán)復(fù)制
假如是雙主互備的架構(gòu)(即互為彼此的從庫),就會(huì)出現(xiàn)循環(huán)復(fù)制,當(dāng)然解決方案也很簡單,復(fù)制的時(shí)候帶上一個(gè)server id
兩個(gè)庫的server id必須不同,一個(gè)庫接到binlog并在重放的過程中,生成與原binlog的server id相同的binlog,每個(gè)庫在收到從自己的主庫發(fā)過來的日志后,先判斷server id,如果跟自己的相同,則表示這個(gè)日志是自己生成的,就直接丟棄這個(gè)日志

主備延遲
可以通過show slave status查看seconds_behind_master.表示當(dāng)前備庫延遲了多少秒

主備延遲的第一種場景
備庫所在的機(jī)器性能要比主庫所在的機(jī)器性能差,導(dǎo)致從庫的壓力過大

解決方案:可以多接幾個(gè)從庫,分擔(dān)壓力,也可以先將binlog輸出到外部系統(tǒng),比如hadoop這類系統(tǒng),讓外部系統(tǒng)提供統(tǒng)計(jì)類查詢的能力

第二種場景
就是大事務(wù),因?yàn)橹鲙焐现挥械却聞?wù)執(zhí)行完了才會(huì)寫入binlog,再傳給備庫,所以如果一個(gè)主庫上的語句執(zhí)行10分鐘,那么這個(gè)事務(wù)很有可能就會(huì)導(dǎo)致從庫延遲10分鐘
當(dāng)然對(duì)大表的操作也要慎重,因?yàn)楹苋菀桩a(chǎn)生大事務(wù)

另外一種解決方案就是
開啟并行復(fù)制
Mysql5.7提供了slave-parallel-type來控制并行復(fù)制的策略(是按表還是按行?需要考慮是否保證了事務(wù)不被破壞)

1.配置為DATABASE,按庫來分發(fā)事務(wù)
2.配置為LOGICAL_CLOCK,表示的就是類似于組提交的策略

mysql組提交優(yōu)化.png

1.同時(shí)處于prepare狀態(tài)的事務(wù),在備庫執(zhí)行時(shí)是可以并行的
2.處于prepare狀態(tài)的事務(wù),與處于commit狀態(tài)的事務(wù)之間,在備庫上也是可以同時(shí)執(zhí)行的

而又兩個(gè)參數(shù)如下
1.binlog_group_commit_sync_delay參數(shù),表示的是延遲多少微秒才能fsync,即刷盤
2.binlog_group_commit_sync_no_delay_count參數(shù),表示累積多少次才調(diào)用fsync

可以使用這兩個(gè)參數(shù)故意拉長binlog從write到fsync的時(shí)間,以此來減少binlog的寫盤次數(shù).(即讓主庫慢一些,從庫就相對(duì)看起來快一些)


主從切換

當(dāng)發(fā)生故障時(shí)就需要進(jìn)行主從切換

有以下幾種切換方案

基于位點(diǎn)的主備切換

假設(shè)B原先是A的備庫,現(xiàn)在A掛了,主庫變成了A',這個(gè)時(shí)候B就需要和A'進(jìn)行同步,相同的日志,A的位點(diǎn)和A'的位點(diǎn)可能是不相同的,因此B在切換的時(shí)候,就需要先"找同步位點(diǎn)"

但問題是這個(gè)位點(diǎn)并不精確
原因如下
假設(shè)主庫A已經(jīng)執(zhí)行完一個(gè)insert語句插入了一行數(shù)據(jù)R,并且已經(jīng)將binlog傳給了A'和B,然后在傳完的瞬間主庫A的主機(jī)就斷電了

那么這個(gè)時(shí)候
1.在從庫B上,由于同步了binlog,R這行已經(jīng)存在
2.在新主庫A'上,R這一行也已經(jīng)存在了,日志位置假設(shè)是寫在123這個(gè)位置之后的
3.我們在從庫B上執(zhí)行change master命令,執(zhí)行A'的File文件的123位置,就會(huì)把插入R這一行的數(shù)據(jù)的binlog又同步到從庫B去執(zhí)行,這個(gè)時(shí)候從庫B就會(huì)報(bào)主鍵沖突,然后停止同步,這個(gè)時(shí)候需要手動(dòng)判斷是否需要跳過

基于GTID
GTID的全稱就是Global Transaction Identifier,也就是全局事務(wù)ID,是一個(gè)事務(wù)在提交的時(shí)候生成的,是這個(gè)事務(wù)的唯一標(biāo)識(shí).它由兩部分組成,格式如下

GTID=server_uuid:gno

  • server_uuid是一個(gè)實(shí)例第一次啟動(dòng)時(shí)自動(dòng)生成的,是全局唯一的
  • gno是一個(gè)整數(shù),初始值是1,每次提交事務(wù)的時(shí)候分配給這個(gè)事務(wù),并加1

這樣每個(gè)Mysql實(shí)例都維護(hù)一個(gè)GTID集合,用來對(duì)應(yīng)"這個(gè)實(shí)例執(zhí)行過的所有事務(wù)"

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容