溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL中并行復(fù)制亂序提交引起的同步異常如何處理

發(fā)布時(shí)間:2021-11-06 09:14:43 來源:億速云 閱讀:144 作者:小新 欄目:MySQL數(shù)據(jù)庫

這篇文章將為大家詳細(xì)講解有關(guān)MySQL中并行復(fù)制亂序提交引起的同步異常如何處理,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

現(xiàn)象描述

Slave在開啟并行復(fù)制后, 默認(rèn)會(huì)亂序提交事務(wù), 可能會(huì)引起同步中斷;

Slave端表現(xiàn)為同步的SQL線程拋出異常, 為主鍵重復(fù), 修改的數(shù)據(jù)行不存在等;

GTID信息類似于: 9a2a50aa-5504-11e7-9e59-246e965d93f4:1-1371939844:1371939846

其中1371939845為報(bào)錯(cuò)的事務(wù), 直觀上看, Slave端先提交了1371939846事務(wù);


解決辦法

MySQLversion>=5.7.5
slave_preserve_commit_order:OFF(default)->ON
注:binlog_order_commits=ON(default)


問題分析

參考官方的WL#6314和WL#7165, 這里對(duì)原文內(nèi)容進(jìn)行簡(jiǎn)單的歸納, 有興趣的可以看看原文的High Level Architecture;
WL#6314 : https://dev.mysql.com/worklog/task/?id=6314
WL#7165 : https://dev.mysql.com/worklog/task/?id=7165
注: 英文原文中的commit-parent transaction, sequence number指的就是binlog中的last_commited和sequence_number; 即簡(jiǎn)單翻譯中的”邏輯時(shí)間戳標(biāo)記” 

WL#6314 關(guān)于slave端的并行applier

當(dāng)事務(wù)進(jìn)入prepare階段(組提交流程的某一個(gè)階段)時(shí), 這些事務(wù)都會(huì)獲得一個(gè)邏輯時(shí)間戳的標(biāo)記, 用來標(biāo)記最新提交的事務(wù)是哪個(gè);

在master端, 有關(guān)流程如下:

  • 在prepare階段, 從commit_clock中獲取時(shí)間戳并存儲(chǔ)下來, 用來標(biāo)記最新提交的事務(wù);

  • 在commit階段(事務(wù)已經(jīng)寫入binlog, 但是在引擎層提交前), 對(duì)commit_clock執(zhí)行步進(jìn)操作;

在Slave端, 有關(guān)流程如下:

  • coordinate線程會(huì)讀取relaylog的event, 如果這些event都有相同的邏輯時(shí)間戳(last_commited), 那么這些event就可以由worker并行執(zhí)行;

WL#7165 有關(guān)并行復(fù)制的并行度優(yōu)化

參照WL#6314的描述, 雖然已經(jīng)實(shí)現(xiàn)了并行復(fù)制, 但是并沒有達(dá)到預(yù)期的程度;

舉例: 下圖代表各個(gè)事務(wù)的執(zhí)行順序與時(shí)間線, 其中P代表單個(gè)事務(wù)的prepare階段, 在這個(gè)階段會(huì)獲取到commit_clock的時(shí)間戳, C代表這個(gè)事務(wù)的寫binlog的階段, 在這里會(huì)對(duì)commit_clock進(jìn)行步進(jìn)操作;

MySQL中并行復(fù)制亂序提交引起的同步異常如何處理

如上圖所示, Trx1, Trx2, Trx3的P階段獲取到的都是同一個(gè)last_commited值(比如說是1), 因此這三個(gè)事務(wù)可以在Slave端并行執(zhí)行; 同理, Trx4不能和< Trx1, Trx2, Trx3 > 一起并行回放, 因?yàn)門rx4的P階段, 獲取到的last_commited值是Trx1執(zhí)行完步進(jìn)以后的值(步進(jìn)之后變成了2); 

按照WL#6314的邏輯, Slave端可以發(fā)現(xiàn)這七個(gè)事務(wù)分成了四個(gè)事務(wù)組, 分別是< Trx1, Trx2, Trx3 >, < Trx4 >, < Trx5, Trx6 >, < Trx7 >;

但是需要注意的是, 對(duì)于不同的事務(wù)組, < Trx4 > 和 < Trx5, Trx6 > 是能并發(fā)執(zhí)行的, 因?yàn)閺臅r(shí)間線上看, < Trx4 > 和 < Trx5, Trx6 > 的prepare階段在時(shí)間線上是有重疊的, 這也就意味著這兩組事務(wù)并不存在鎖的沖突, 那么就可以在Slave并行執(zhí)行;

對(duì)于并行度的優(yōu)化

改進(jìn)后的并行復(fù)制使用鎖來判斷是否可以進(jìn)行并發(fā);

基本邏輯如下:

L代表鎖階段開始, C代表鎖階段結(jié)束;

MySQL中并行復(fù)制亂序提交引起的同步異常如何處理

A中的Trx1和Trx2由于鎖階段存在重合, 也沒有發(fā)生沖突, 說明Trx1和Trx2是可以并行執(zhí)行的, 但是B不行, 因?yàn)門rx1和Trx2的鎖階段沒有重合, 所以無法確認(rèn)是不是可以并行執(zhí)行(不做額外的判斷, 直接當(dāng)做不可并行處理, 節(jié)約性能開銷);

關(guān)于鎖階段的判斷, WL中明確表示沒有進(jìn)行鎖分析, 而是直接把事務(wù)提交的一些階段作為加鎖與釋放鎖的時(shí)間點(diǎn)(從事務(wù)提交的階段來看, 也沒什么問題);

  • 假設(shè)在進(jìn)行存儲(chǔ)引擎層的提交之前, 所有的鎖都已已經(jīng)釋放(鎖階段結(jié)束的時(shí)間點(diǎn));

  • 假設(shè)在prepare階段開始的時(shí)候, 所有需要的鎖已經(jīng)全部獲取到(鎖階段開始的時(shí)間點(diǎn));


在MySQL的binlog中, L所指的標(biāo)記就是last_commited, C所指的標(biāo)記就是sequence_number;

關(guān)于last_commited和sequence_number, WL#7165有做如下描述

  • 在事務(wù)進(jìn)入flush階段前, 會(huì)步進(jìn)transaction.sequence_number的值 –> 顯示為sequence_number

  • 在事務(wù)進(jìn)入引擎層提交之前, 會(huì)修改 global.max_committed_transaction的值 

    • = max(global.max_committed_timestamp, transaction.sequence_number) 

    • = transaction.sequence_number (如果binlog_order_commits使用默認(rèn)值ON)


因此, Slave端在決定SQL是否可以并發(fā)執(zhí)行時(shí), 參考如下原則:

-----------------------------------------------------------------------------------------------------------
Slave can execute a transactionifthe smallest sequence_number 
    among all executing transactions is greater than transaction.last_committed.
-----------------------------------------------------------------------------------------------------------

偽代碼會(huì)更直觀一些:
-----------------------------------------------------------------------------------------------------------
Slave logic:
    -before scheduler pushes the transaction for execution : wait until         transaction_sequence[0].sequence_number>transaction.last_committed
-----------------------------------------------------------------------------------------------------------

所以使用基于鎖的并行度優(yōu)化后, 確實(shí)可以讓W(xué)L#6314的< Trx4 > 和 < Trx5, Trx6 > 并發(fā)執(zhí)行;

故障場(chǎng)景還原

Slave上報(bào)錯(cuò)的事務(wù)為1371939845, binlog內(nèi)容如下, 事務(wù)缺少1371939845; 
MySQL中并行復(fù)制亂序提交引起的同步異常如何處理
Master上的事務(wù)序列如下: 
MySQL中并行復(fù)制亂序提交引起的同步異常如何處理

參考WL#6314的格式, 根據(jù)Master的事務(wù)序列繪制事務(wù)序列圖, GTID, last_commited, sequence_number均使用最后兩位數(shù)作為標(biāo)記;

由于Slave是亂序提交的, 所以這些事務(wù)在Slave的binlog中并非嚴(yán)格按照GTID遞增的順序出現(xiàn)

MySQL中并行復(fù)制亂序提交引起的同步異常如何處理

根據(jù)WL#7165的描述, 可以得出: 在Slave上, 當(dāng)Trx41執(zhí)行完畢之后, Slave認(rèn)為, Trx46與Trx47已經(jīng)可以由coordinate進(jìn)行調(diào)度, 與< Trx42, Trx43, Trx44, Trx45 > 并行執(zhí)行了, 但是Trx45與Trx46, Trx47 存在業(yè)務(wù)上的先后順序(且確實(shí)存在鎖沖突), 所以先執(zhí)行的Trx46刪除了Trx45需要的數(shù)據(jù), 導(dǎo)致同步中斷;

PS: 既然Trx45和Trx46有鎖沖突, 為什么Trx46會(huì)拿到84作為last_commited, 而不是88?


參考WL#7165的偽代碼,
-----------------------------------------------------------------------------------------------------------
When@@global.binlog_order_commitsistrue,inprinciple we could reduce  the max
    to an assignment:
     global.max_committed_transaction=transaction.sequence_number
-----------------------------------------------------------------------------------------------------------
MySQL-5.7.21的源代碼:
MYSQL_BIN_LOG::ordered_commit-->
process_commit_stage_queue-->
update_max_committed
-----------------------------------------------------------------------------------------------------------

因此推測(cè)主庫當(dāng)時(shí)候是如下場(chǎng)景:<Trx35~Trx45>作為一個(gè)事務(wù)組,進(jìn)入到了存儲(chǔ)引擎的commit階段前,會(huì)遞增sequence_number,而不是一次到位的全部加上;

所以Trx46進(jìn)入prepare階段時(shí),剛好是Trx41完成了commit階段,所以拿到的是84,而不是88;雖然官方描述中,認(rèn)為會(huì)達(dá)到最終一致的狀態(tài),但是同步過程中會(huì)存在短暫的不一致現(xiàn)象,這種現(xiàn)象被描述為"GAP";

關(guān)于“MySQL中并行復(fù)制亂序提交引起的同步異常如何處理”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI