一、異步復(fù)制
異步復(fù)制原理圖

after commit
- master:
- Dump_Thread,通知IO_Thread數(shù)據(jù)變更
- slave:
- IO_Thread,拉取binlog增量
- SQL_Thread,SQL邏輯重放
異步復(fù)制流程
- master 寫(xiě)undo、redo
- master 發(fā)起commit,寫(xiě)binlog(filename,position)
- master 完成提交事務(wù)
- slave 通過(guò)IO_Thread拉取binlog的filename,position,并寫(xiě)入到本地的relaylog中
- slave 通過(guò)SQL_Thread邏輯重放relaylog中的SQL(單線程)
兩種場(chǎng)景
- 實(shí)時(shí)同步(IO_Thread主從沒(méi)有延遲),寫(xiě)數(shù)據(jù)之前通知IO_Thread有變更,IO_Thread拉取binlog增量
- 主從長(zhǎng)時(shí)間延遲(全備恢復(fù)),IO_Thread直接去主庫(kù)本地磁盤(pán)拉取binlog增量
復(fù)制中的坑
-
row模式下,表最好是有主鍵,其次要有普通索引。否則sql_thread重放需要全表掃描匹配,速度非常慢(mysql5.7中做了優(yōu)化)
sql_thread重放
二、半同步復(fù)制(MySQL 5.5 after commit)
半同步復(fù)制流程圖

after commit
半同步復(fù)制流程
- master 寫(xiě)undo、redo
- master 發(fā)起commit,sync binlog(filename,position)
- master 存儲(chǔ)引擎commit完成
- master_sender_thread 等待slave_reciver_thread返回ack(等待過(guò)程中會(huì)阻塞下一個(gè)事務(wù))
- master_sender_thread接收到slave_reciver_thread返回的ack,并返回給客戶端,客戶端才可以繼續(xù)操作
after帶來(lái)的三個(gè)問(wèn)題
- 性能問(wèn)題:AFTER_COMMIT半同步是單線程處理的,master把事務(wù)發(fā)送完畢后,要接受和處理slave的ack應(yīng)答,處理完ack后才能繼續(xù)發(fā)送下一個(gè)事務(wù),對(duì)性能影響比較大
- master commit完成后才開(kāi)始等待slave的ACK,其實(shí)這個(gè)時(shí)候在master上事務(wù)已經(jīng)提交完成并且其他客戶端已經(jīng)可以讀到,只是提交該事物的客戶端處于等待狀態(tài)。
- 如果master等待ack時(shí)master crash,而slave又未接收到該事務(wù)的話,那么切換到從庫(kù)后就會(huì)出現(xiàn)讀取的結(jié)果不一致的情況(因?yàn)橹鲙?kù)已commit而從庫(kù)未收到該事務(wù)binlog)
三、增強(qiáng)半同步復(fù)制(MySQL 5.7 after sync)
增強(qiáng)半同步復(fù)制流程圖

after sync
增強(qiáng)半同步復(fù)制流程
- master 寫(xiě)undo、redo
- master 發(fā)起commit,sync binlog(filename,position)
- master 通過(guò)單獨(dú)的semisync_reciver_thread等待slave_reciver_thread返回ack,此過(guò)程中master_sender_thread可以處理其他事務(wù)的請(qǐng)求
- semisync_reciver_thread接收到slave_reciver_thread返回的ack,并返回給客戶端
- master 存儲(chǔ)引擎層commit
增強(qiáng)半同步解決的問(wèn)題
- AFTER_SYNC采用雙工處理,master采用單獨(dú)semisync_reciver_thread處理ack應(yīng)答,不阻塞其他事務(wù),提升性能
- AFTER_SYNC等待ack的操作是在引擎層commit之前處理,避免了其他客戶端臟讀
- 在等待ack的期間master crash,由于master引擎層未commit,如果slave未接受到該事務(wù),那么數(shù)據(jù)是一致的
增強(qiáng)半同步帶來(lái)的新問(wèn)題
極端情況:在master sync binlog(寫(xiě)入xid)后,且在發(fā)送日志之前,這個(gè)時(shí)間master crash了。那么slave是沒(méi)有拿到master的binlog增量的,而master重啟后的crash recovery會(huì)認(rèn)為該事務(wù)已寫(xiě)到binlog中,然后進(jìn)行重做。這樣就會(huì)導(dǎo)致主從不一致
5.7增強(qiáng)半同步配置
- master
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
set global rpl_semi_sync_master_enabled=ON;
- slave
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
set global rpl_semi_sync_slave_enabled=ON;
- 主要參數(shù)
- mster:
- rpl_semi_sync_master_enabled=ON 表示在master上已經(jīng)開(kāi)啟半同步復(fù)制模式。
- rpl_semi_sync_master_timeout=10000 該參數(shù)默認(rèn)為10000毫秒,即10秒,可以調(diào)整,表示如果主庫(kù)在某次事務(wù)中等待事件超過(guò)10秒,則降級(jí)為異步復(fù)制模式,不再等待slave,如果master探測(cè)到slave恢復(fù),則會(huì)自動(dòng)回到半同步模式。
- rpl_semi_sync_master_wait_no_slave=ON 表示是否允許master每個(gè)事務(wù)提交后都要等待slave的確認(rèn)信號(hào),默認(rèn)是ON,即每一個(gè)事務(wù)都會(huì)等待,如果是OFF,則slave追趕上之后,也不會(huì)回到半同步模式。
- rpl_semi_sync_master_trace_level=32 表示開(kāi)啟半同步復(fù)制模式時(shí)的調(diào)試級(jí)別,默認(rèn)是32
- slave:
- rpl_semi_sync_slave_enabled=ON
- rpl_semi_sync_master_trace_level=32
四、并行復(fù)制
并行復(fù)制的演變
- MySQL 5.6 是基于庫(kù)級(jí)別的并行復(fù)制(適用于單實(shí)例多庫(kù)而且?guī)熘g的寫(xiě)入分布比較平均的情況,比較雞肋,可以忽略)
- MySQL 5.7 是基于事務(wù)級(jí)別的并行復(fù)制(主要介紹)
- MySQL 8.0 是基于行級(jí)別的并行復(fù)制(太新還沒(méi)來(lái)得及研究,后面補(bǔ)上)
MySQL 5.7基于行的并行復(fù)制
原理:
與組提交結(jié)合,一個(gè)組提交的事務(wù)都是可以并行回放,因?yàn)檫@些事務(wù)都已進(jìn)入到事務(wù)的prepare階段,則說(shuō)明事務(wù)之間沒(méi)有任何沖突(否則就不可能提交)。
復(fù)制中的重要參數(shù)
- log-bin = /binlog_dir
- binlog_format = row
- binlog_row_image = full //默認(rèn)full
- gtid_mode = on
- enforce_gtid_consistency = on //打開(kāi)gtid之前必須打開(kāi)此選項(xiàng),服務(wù)器通過(guò)允許僅執(zhí)行可使用GTID安全記錄的語(yǔ)句來(lái)強(qiáng)制執(zhí)行GTID一致性(開(kāi)啟后強(qiáng)制檢測(cè)gtid一致性,在事務(wù)中更改非事務(wù)表將會(huì)報(bào)錯(cuò))
- binlog_group_commit_sync_delay = 100 //單位(微秒)。如果不啟用組提交,則每次提交一個(gè)事務(wù),binlog做一次fsync。如果啟用了binlog-group-commit,此時(shí)sync_binlog=N代表每N組事務(wù),而不是每N個(gè)事務(wù)。建議設(shè)置sync_binlog=1
- binlog_group_commit_sync_no_delay_count = 10
- binlog_order_commit = off //開(kāi)啟后事務(wù)提交順序與binlog順序一致,默認(rèn)on,設(shè)置為off則事務(wù)可并行提交,對(duì)數(shù)據(jù)一致性可能產(chǎn)生影響。如果啟用了binlog-group-commit,則設(shè)置為off
- transaction_write_set_extraction = on //8.0特性,5.7默認(rèn)off
- binlog_transation_dependency_tracking = COMMIT_ORDER //等同于打開(kāi)binlog_order_commit,基于行級(jí)別并行復(fù)制配置成writeset_session
- binlog_transation_dependency_history_size = 25000 //控制隊(duì)列長(zhǎng)度
- slave_net_timeout = 20|30 //io_thread超時(shí)時(shí)間
- log_slave_updates
- slave_parallel_type = LOGICAL_CLOCK //從庫(kù)開(kāi)啟并行復(fù)制
- slave_parallel_type = 4|8
- slave_preserve_commit_order = on //保證從庫(kù)提交順序與主庫(kù)一致,前置條件log-bin,log_slave_update,slave_parallel_type = LOGICAL_CLOCK
- slave_rows_search_algorithms = TABLE_SCAN,INDEX_SCAN //配置成INDEX_SCAN,HASH_SCAN,當(dāng)沒(méi)主鍵的表復(fù)制中可以用hash索引
- relay_log_info_reposity = table //crash-safe replication
- sync_relay_log_info = 1
- relay_log_recovery = 1
