深度分析 | MGR相同GTID產生不同transaction故障分析
本文是由愛可生運維團隊出品的「MySQL專欄」系列文章,內容來自於運維團隊一線實戰經驗,涵蓋MySQL各種特性的實踐,優化案例,資料庫架構,HA,監控等,有掃雷功效。
愛可生開源社群持續運營維護的小目標:
- 每週至少推送一篇 高質量技術文章
- 每月研發團隊釋出 開源元件新版
- 每年 1024開源 一款企業級元件
- 2019年至少 25場社群活動
歡迎大家持續關注~
MGR作為MySQL原生的高可用方案,它的基於共識協議的同步和決策機制,看起來也更為先進。吸引了一票使用者積極嘗試,希望通過MGR架構解決RPO=0的高可用切換。在實際使用中經常會遇到因為網路抖動的問題造成叢集故障,最近我們某客戶就遇到了這類問題,導致資料不一致。
問題現象
這是在生產環境中一組MGR叢集,單主架構,我們可以看到在相同的GTID86afb16f-1b8c-11e8-812f-0050568912a4:57305280下,本應執行相同的事務,但binlog日誌顯示不同事務資訊。
- Primary節點binlog :
SET @@SESSION.GTID_NEXT= '86afb16f-1b8c-11e8-812f-0050568912a4:57305280'/*!*/;# at 637087357#190125 15:02:55 server id 3136842491 end_log_pos 637087441 Querythread_id=19132957 exec_time=0 error_code=0SET TIMESTAMP=1548399775/*!*/;BEGIN/*!*/;# at 637087441#190125 15:02:55 server id 3136842491 end_log_pos 637087514 Table_map:`world`.`IC_WB_RELEASE` mapped to number 398# at 637087514#190125 15:02:55 server id 3136842491 end_log_pos 637087597 Write_rows: table id 398flags: STMT_END_FBINLOG 'n7RKXBP7avi6SQAAABov+SUAAI4BAAAAAAEAB2ljZW50ZXIAFUlDX1FVRVJZX1VTRVJDQVJEX0xP'/*!*/;### INSERT INTO `world`.`IC_WB_RELEASE`### SET
- Secondary節點binlog :
SET @@SESSION.GTID_NEXT= '86afb16f-1b8c-11e8-812f-0050568912a4:57305280'/*!*/;# at 543772830#190125 15:02:52 server id 3136842491 end_log_pos 543772894 Querythread_id=19162514 exec_time=318 error_code=0SET TIMESTAMP=1548399772/*!*/;BEGIN/*!*/;# at 543772894#190125 15:02:52 server id 3136842491 end_log_pos 543772979 Table_map:`world`.`IC_QUERY_USERCARD_LOG` mapped to number 113# at 543772979#190125 15:02:52 server id 3136842491 end_log_pos 543773612 Delete_rows: table id113 flags: STMT_END_FBINLOG 'nLRKXBP7avi6VQAAADNRaSAAAHEAAAAAAAEAB2ljZW50ZXIADUlDX1dCX1JFTEVBU0UACw8PEg8'/*!*/;### DELETE FROM `world`.`IC_QUERY_USERCARD_LOG`### WHERE
從以上資訊可以推測,primary節點在這個GTID下對world.IC_WB_RELEASE表執行了insert操作事件沒有同步到secondary節點,secondary節點收到主節點的其他事件,造成了資料是不一致的。當在表IC_WB_RELEASE發生delete操作時,引發了下面的故障,導致從節點脫離叢集。
2019-01-28T11:59:30.919880Z 6 [ERROR] Slave SQL for channel 'group_replication_applier': Could not execute Delete_rows event on table `world`.`IC_WB_RELEASE`; Can't find record in 'IC_WB_RELEASE', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND, Error_code: 10322019-01-28T11:59:30.919926Z 6 [Warning] Slave: Can't find record in 'IC_WB_RELEASE' Error_code: 10322019-01-28T11:59:30.920095Z 6 [ERROR] Plugin group_replication reported: 'The applier thread execution was aborted. Unable to process more transactions, this member will now leave the group.'2019-01-28T11:59:30.920165Z 6 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'FIRST' position 271.2019-01-28T11:59:30.920220Z 3 [ERROR] Plugin group_replication reported: 'Fatal error during execution on the Applier process of Group Replication. The server will now leave the group.'2019-01-28T11:59:30.920298Z 3 [ERROR] Plugin group_replication reported: 'The server was automatically set into read only mode after an error was detected.'
問題分析
- 主節點在向從節點同步事務時,至少有一個GTID為86afb16f-1b8c-11e8-812f-0050568912a4:57305280(執行的是insert操作)的事務沒有同步到從節點,此時從例項還不存在這個GTID;於是主例項GTID高於從例項。資料就已經不一致了。
- 叢集業務正常進行,GTID持續上漲,新上漲的GTID同步到了從例項,佔用了86afb16f-1b8c-11e8-812f-0050568912a4:57305280這個GTID,所以從例項沒有執行insert操作,少了一部分資料。
- 主節點對GTID為86afb16f-1b8c-11e8-812f-0050568912a4:57305280執行的insert資料進行delete,而從節點由於沒有同步到原本的insert操作;沒有這部分資料就不能delete,於是脫離了叢集。
對於該故障的分析,我們要從主從例項GTID相同,但是事務不同的原因入手,該問題猜測與bug( https://bugs.mysql.com/bug.ph... )相關,我們針對MGR同步事務的時序做如下分析。
相關知識背景
MGR全組同步資料的Xcom元件是基於paxos演算法的實現;每當提交新生事務時,主例項會將新生事務傳送到從例項進行協商,組內協商通過後全組成員一起提交該事務;每一個節點都以同樣的順序,接收到了同樣的事務日誌,所以每一個節點以同樣的順序回放了這些事務,最終組內保持了一致的狀態。
paxos包括兩個角色:
提議者(Proposer):主動發起投票選主,允許發起提議。
接受者(Acceptor):被動接收提議者(Proposer)的提議,並記錄和反饋,或學習達成共識的提議。
paxos達成共識的過程包括兩個階段:
第一階段(prepare)
a:提議者(Proposer)傳送prepare請求,附帶自己的提案標識(ballot,由數值編號加節點編號組成)以及value值。組成員接收prepare請求;b:如果自身已經有了確認的值,則將該值以ack_prepare形式反饋;在這個階段中,Proposer收到ack回覆後會對比ballot值,數值大的ballot會取代數值小的ballot。如果收到大多數應答之後進入下一個階段。
第二階段(accept)
a:提議者(Proposer)傳送accept請求
b:接收者(Acceptor)收到請求後對比自身之前的bollat是否相同以及是否接收過value值。如果未接受過value值 以及ballot相同,則返回ack_accept,如果接收過value值,則選取最大的ballot返回ack_accept。c:之後接受相同value值的Proposer節點發送learn_op,收到learn_op節點的例項表示確認了資料修改,傳遞給上層應用。
針對本文案例我們需要 強調幾個關鍵點 :
- 1.該案例最根本的異常對比發生在第二次提案的prepare階段。
- 2.prepare階段的提案標識由數值編號和節點編號兩部分組成;其中數值編號類似自增長數值,而節點編號不變。
分析過程
結合paxos時序,我們對案例過程進行推測:
Tips:以下分析過程請結合時序圖操作步驟觀看
建議點開放大,效果更清晰 ^ ^
- 【step1】primary節點要執行對錶world.IC_WB_RELEASE的insert操作,向組內傳送假設將ballot設定為(0.0)以及將value值world.IC_WB_RELEASE的prepare請求,並收到大多數成員的ack_prepare返回,於是開始傳送accept請求。primary節點將ballot(0.0)的提案資訊傳送至組內,仍收到了大多數成員ack_accept(ballot=0.0value=world.IC_WB_RELEASE)返回。然後傳送learn_op資訊【step3】。
- 同時其他從節點由於網路原因沒有收到主例項的的learn_op資訊【step3】,而其中一臺從例項開始新的prepare請求【step2】,請求value值為no_op(空操作)ballot=1.1(此編號中節點編號是關鍵,該secondary節點編號大於primary節點編號,導致了後續的問題,數值編號無論誰大誰小都要被初始化)。
其他的從例項由於收到過主節點的value值;所以將主節點的(ballot=0.0,value=world.IC_WB_RELEASE)返回;而收到的ack_prepare的ballot值的數值符號全組內被初始化為0,整個ballot的大小完全由節點編號決定,於是從節點選取了ballot較大的該例項value值作為新的提案,覆蓋了主例項的value值並收到大多數成員的ack_accept【step2】。並在組成員之間傳送了learn_op資訊【step3】,跳過了主例項提議的事務。
從原始碼中可以看到關於handle_ack_prepare的邏輯。
handle_ack_prepare has the following code:if (gt_ballot(m->proposal,p->proposer.msg->proposal)){replace_pax_msg(&p->proposer.msg, m);...}
- 此時,主節點在accept階段收到了組內大多數成員的ack_accept並收到了 自己所傳送的learn_op資訊,於是把自己的提案(也就是binlog中對錶的insert操作)提交【step3】,該事務GTID為86afb16f-1b8c-11e8-812f-0050568912a4:57305280。而其他節點的提案為no_op【step3】,所以不會提交任何事務。此時主例項GTID大於其他從例項的。
- 主節點新生GTID繼續上漲;同步到從例項,佔用了從例項的86afb16f-1b8c-11e8-812f-0050568912a4:57305280這個GTID,於是產生了主節點與從節點binlog中GTID相同但是事務不同的現象。
- 當業務執行到對錶world.IC_WB_RELEASE的delete操作時,主例項能進行操作,而其他例項由於沒有insert過資料,不能操作,就脫離了叢集。
▽過程總結:
- 舊主傳送prepare請求,收到大多數ack,進入accept階段,收到大多數ack。
- 從例項由於網路原因沒有收到learn_op資訊。
- 其中一臺從例項傳送新的prepare請求,value為no_op。
- 新一輪的prepare請求中,提案標識的數值編號被初始化,新的提案者大於主例項,從例項選取新提案,執行空操作,不寫入relay-log。代替了主例項的事務,使主例項GTID大於從例項。
- 叢集網路狀態恢復,新生事物正常同步到從例項,佔用了本該正常同步的GTID,使叢集中主節點與從節點相同GTID對應的事務時不同的。
結論
針對此問題我們也向官方提交SR,官方已經反饋社群版MySQL 5.7.26和MySQL 8.0.16 中會修復,如果是企業版客戶可以申請最新的hotfix版本。
在未升級 MySQL 版本前,若再發生此類故障,在修復時需要人工檢查,檢查切換時binlog中 GTID 資訊與新主節點對應 GTID 的資訊是否一致。如果不一致需要人工修復至一致狀態,如果一致才可以將被踢出的原主節點加回叢集。
所以正在使用了MGR 5.7.26之前社群版的DBA同學請注意避坑。
開源分散式中介軟體DBLE
社群官網: https://opensource.actionsky....
GitHub主頁: https://github.com/actiontech...
技術交流群:669663113
開源資料傳輸中介軟體DTLE
社群官網: https://opensource.actionsky....
GitHub主頁: https://github.com/actiontech...
技術交流群:852990221