詳解Mysql并行復(fù)制的原理
并行復(fù)制是 MySQL 復(fù)制技術(shù)中一個至關(guān)重要的性能特性,它主要用于解決主從延遲(Replication Lag)問題。它的核心思想是:在從庫上,使用多個工作線程來并發(fā)應(yīng)用(Apply)從主庫接收到的二進(jìn)制日志(Binary Log)事件,從而大幅提升從庫的數(shù)據(jù)回放速度。
一、為什么需要并行復(fù)制?—— 問題的根源
在傳統(tǒng)的單線程復(fù)制模式下(SQL 線程為單線程),從庫的 SQL 線程嚴(yán)格按照主庫二進(jìn)制日志(binlog)中事件的順序,逐一地、串行地執(zhí)行 SQL 事件。
- 主庫:在高并發(fā)環(huán)境下,多個客戶端連接同時操作,可以并行提交事務(wù),吞吐量很高。
- 從庫:無論主庫多么繁忙,從庫都只能用單個線程去重放這些事件,就像一個狹窄的單車道,很容易造成交通堵塞。
這就導(dǎo)致了:從庫的應(yīng)用速度遠(yuǎn)遠(yuǎn)跟不上主庫的寫入速度,數(shù)據(jù)延遲(Seconds Behind Master)會越來越大。并行復(fù)制就是為了將這個“單車道”改造成“多車道”。
二、并行復(fù)制的核心:如何判斷哪些事務(wù)可以并行?
并行復(fù)制并非簡單地將所有事件亂序并行執(zhí)行,因為存在依賴關(guān)系的事務(wù)(例如,對同一行的修改)必須按順序執(zhí)行,否則會導(dǎo)致數(shù)據(jù)不一致。因此,并行復(fù)制的核心技術(shù)在于如何準(zhǔn)確地識別出哪些事務(wù)之間沒有依賴關(guān)系,可以安全地并行執(zhí)行。
MySQL 的并行復(fù)制技術(shù)經(jīng)歷了多個版本的演進(jìn),其算法也在不斷優(yōu)化:
2.1 MySQL 5.6:按數(shù)據(jù)庫(Schema)并行
- 策略:如果兩個事務(wù)操作的是不同的數(shù)據(jù)庫,則認(rèn)為它們沒有沖突,可以并行執(zhí)行。
- 優(yōu)點:實現(xiàn)簡單,開銷小。
缺點:粒度太粗。絕大多數(shù)應(yīng)用通常只使用一個數(shù)據(jù)庫,或者不同數(shù)據(jù)庫的負(fù)載不均衡,導(dǎo)致無法有效并行。這對于現(xiàn)代微服務(wù)或多租戶架構(gòu)來說效果有限。
slave_parallel_workers = 4 -- 設(shè)置并行工作線程數(shù) slave_parallel_type = DATABASE -- 并行策略為 DATABASE
2.2 MySQL 5.7:LOGICAL_CLOCK(基于組提交)
這是里程碑式的改進(jìn),極大地提升了并行復(fù)制的效率和通用性。
策略:基于主庫的組提交(Group Commit) 信息。
- 在主庫上,高并發(fā)時為了提高效率,會將多個不同事務(wù)的
commit操作打包成一個組(Group)一起寫入 binlog 并刷盤。 - 被分到同一個組內(nèi)提交的事務(wù),意味著它們在主庫上是并行執(zhí)行的,因此它們之間沒有最后一序約束(no locking constraint),在從庫上也可以安全地并行回放。
- 主庫會在 binlog 中為每個事件記錄一個
last_committed和sequence_number。last_committed相同的事務(wù),表示它們屬于同一個組,可以在從庫并行執(zhí)行。
工作原理:
主庫:事務(wù)在 prepare 階段會進(jìn)入一個隊列。當(dāng)某個事務(wù)要刷盤時,它會將其隊列中所有已經(jīng) prepare 好的事務(wù)一起打包成一個組。
Binlog:記錄形式如下。last_committed 相同的事務(wù)(如 6、7、8)可以并行。
# sequence_number=6 last_committed=5 ... # sequence_number=7 last_committed=5 ... # sequence_number=8 last_committed=5 ... # sequence_number=9 last_committed=8 ... -- 必須等8提交后才能執(zhí)行
從庫:協(xié)調(diào)線程(Coordinator Thread)會讀取這些信息,將 last_committed 相同的事務(wù)分發(fā)給不同的工作線程(Worker Thread)并行執(zhí)行。只有 last_committed 小于當(dāng)前已執(zhí)行事務(wù) sequence_number 的事務(wù)才能被分發(fā),以保證依賴關(guān)系。
優(yōu)點:并行粒度從數(shù)據(jù)庫級別細(xì)化到了事務(wù)級別,只要事務(wù)在主庫上是并行提交的,在從庫就能并行回放,效果非常好。
配置:
slave_parallel_workers = 8 slave_parallel_type = LOGICAL_CLOCK -- 控制組提交的積極性,值越小組提交越頻繁,意味著從庫并行度可能更高 binlog_group_commit_sync_delay = 100 -- 微秒級延遲,以等待更多事務(wù)成組 binlog_group_commit_sync_no_delay_count = 10 -- 達(dá)到一定數(shù)量立即成組
2.3 MySQL 8.0:WRITESET(基于事務(wù)沖突)
在 5.7 的基礎(chǔ)上,MySQL 8.0 引入了更先進(jìn)的 WRITESET 策略,進(jìn)一步提升了并行效率。
策略:不再依賴主庫的組提交時機(jī),而是直接分析事務(wù)本身修改了哪些數(shù)據(jù)。
- 每個事務(wù)都會有一個
writeset,這是一個集合,包含了本事務(wù)修改的所有行的唯一哈希值(由庫名、表名、主鍵或唯一索引鍵值計算得出)。 - 如果兩個事務(wù)的
writeset沒有交集,即它們修改的不是同一行,就說明它們沒有沖突,可以并行。 - 主庫會維護(hù)一個
writeset歷史映射(在內(nèi)存中),記錄最近修改過某行數(shù)據(jù)的事務(wù)的sequence_number。當(dāng)一個新事務(wù)到來時,系統(tǒng)會檢查其writeset中的每一行,找出所有修改過這些行的最新事務(wù)的sequence_number,其中最大的那個數(shù),就是這個新事務(wù)的last_committed值。
優(yōu)點:
- 更高的并行度:即使主庫并發(fā)很低、組提交很少發(fā)生,8.0 也能通過分析行沖突來創(chuàng)造并行機(jī)會。它可以讓更多的事務(wù)被標(biāo)記為相同的
last_committed。 - 降低延遲敏感:從庫的并行不再完全依賴于主庫的組提交設(shè)置(如
binlog_group_commit_sync_delay),即使主庫沒有故意延遲提交,從庫也能獲得很好的并行效果。
配置:
slave_parallel_workers = 16 slave_parallel_type = LOGICAL_CLOCK -- WRITESET 是 LOGICAL_CLOCK 的增強(qiáng)子功能 -- 在主庫上開啟 writeset 識別(也用于增強(qiáng)半同步復(fù)制) transaction_write_set_extraction = XXHASH64 -- 計算 writeset 的哈希算法 binlog_transaction_dependency_tracking = WRITESET -- 依賴跟蹤模式:COMMIT_ORDER(5.7默認(rèn)), WRITESET, WRITESET_SESSION
三、并行復(fù)制的架構(gòu)
在啟用并行復(fù)制后,從庫的 SQL 線程演變?yōu)橐粋€協(xié)調(diào)者線程(Coordinator) 和多個工作線程(Worker Threads) 的架構(gòu):
I/O Thread:保持不變,負(fù)責(zé)從主庫拉取 binlog 事件并寫入本地的中繼日志(Relay Log)。
Coordinator Thread:
- 負(fù)責(zé)讀取 Relay Log。
- 根據(jù)配置的并行復(fù)制策略(DATABASE/LOGICAL_CLOCK)來判斷事務(wù)的依賴關(guān)系。
- 將可以并行執(zhí)行的事務(wù)分發(fā)給不同的 Worker Thread。
- 維護(hù)事務(wù)的執(zhí)行順序,確保有依賴關(guān)系的事務(wù)被正確地串行化。
Worker Threads:多個工作線程,真正負(fù)責(zé)執(zhí)行被分配到的 Relay Log 中的事務(wù)。它們是并行的執(zhí)行單元。
四、舉例組提交和WriteSet提交
想象一下,主庫是一個接一個地發(fā)出指令的指揮官(串行提交事務(wù)),從庫是一隊士兵。
- 指令1:士兵A,去占領(lǐng)山頭X。
- 指令2:士兵B,去占領(lǐng)山頭Y。
- 指令3:士兵C,去山頭X挖戰(zhàn)壕。(這個指令依賴于指令1,必須等山頭X被占領(lǐng)后才能執(zhí)行)
4.1 組提交(LOGICAL_CLOCK)模式的做法:
指揮官發(fā)出指令時沒有特意 grouping(因為壓力小,指令是串行發(fā)出的)。那么從庫的士兵們就會認(rèn)為:“指令1、2、3是在不同時間收到的,它們必須按順序執(zhí)行。”
所以執(zhí)行順序是:A完成 -> B開始并完成 -> C開始并完成。
結(jié)果: 士兵B明明可以去獨立完成任務(wù),卻被迫要等士兵A完成后才能開始。效率低下。
4.2 WRITESET模式的做法:
從庫這邊有一個超級智能的參謀長。他拿到指令清單后,會分析每條指令的具體內(nèi)容:
- 指令1:修改了地點X。
- 指令2:修改了地點Y。
- 指令3:修改了地點X。(同時依賴指令1)
參謀長的推理:
- “指令2(修改Y)和指令1(修改X)毫無關(guān)系。它們可以同時執(zhí)行!”
- “指令3(修改X)和指令1(修改X)強(qiáng)相關(guān),必須先執(zhí)行完指令1,才能執(zhí)行指令3。”
- “指令3和指令2毫無關(guān)系,但指令3依賴于指令1,所以只要指令1完成,指令3就可以和指令2同時執(zhí)行。”
于是,參謀長制定了這樣一個并行執(zhí)行計劃:
- 時間點T1:同時派出士兵A(執(zhí)行指令1)和士兵B(執(zhí)行指令2)。
- 時間點T2:士兵A完成任務(wù),成功占領(lǐng)山頭X。士兵B還在前往Y的路上。
- 時間點T2+:由于指令1已完成,指令3的依賴已解決。參謀長立即派出士兵C(執(zhí)行指令3),讓他和士兵B并行工作。
最終結(jié)果:
- 保證了正確性:士兵C是在山頭X被占領(lǐng)后才去挖戰(zhàn)壕的,邏輯正確。
- 最大化并行:士兵B和士兵A/C的大部分工作都是并行的。整體完成時間遠(yuǎn)小于串行執(zhí)行。
- 沒有“不必要的等待”:士兵B沒有浪費任何時間等待士兵A。
技術(shù)原理解析:last_committed的魔法
在WRITESET模式下,主庫在寫binlog時,會基于writeset歷史映射表,為每個事務(wù)重新計算一個last_committed值。
- 對于指令1(修改X):它是第一個修改X的事務(wù),它依賴于之前的所有事務(wù)。它的
last_committed值會被設(shè)為上一個全局事務(wù)的序號(比如0)。 - 對于指令2(修改Y):智能算法發(fā)現(xiàn)Y之前沒人修改過,它和指令1沒有沖突。因此,它的
last_committed值會被設(shè)置為和指令1相同(也就是0)。 - 對于指令3(修改X):智能算法發(fā)現(xiàn)它修改了X,而最后一次修改X的是指令1。因此,它的
last_committed值會被設(shè)置為指令1的sequence_number(比如1)。
從庫的協(xié)調(diào)線程看到的是:
事務(wù)1: last_committed=0, sequence_number=1 事務(wù)2: last_committed=0, sequence_number=2 // 與事務(wù)1的last_committed相同! 事務(wù)3: last_committed=1, sequence_number=3 // 必須等seq_num=1的事務(wù)完成
協(xié)調(diào)規(guī)則沒變:last_committed相同的事務(wù)可以并行。
- 所以,事務(wù)1和事務(wù)2可以并行執(zhí)行。
- 事務(wù)3必須等待
sequence_number <= 1的事務(wù)(即事務(wù)1)完成后才能開始。(事務(wù)2是否完成不影響事務(wù)3的開始)
到此這篇關(guān)于詳解Mysql并行復(fù)制的原理的文章就介紹到這了,更多相關(guān)Mysql并行復(fù)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql 8.0.18各版本安裝及安裝中出現(xiàn)的問題(精華總結(jié))
這篇文章主要介紹了mysql 8.0.18各版本安裝及安裝中出現(xiàn)的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12
MySQL實現(xiàn)merge?into四種方法代碼實例
Merge?into是一個數(shù)據(jù)庫操作術(shù)語,通常用于將兩個或多個表中的數(shù)據(jù)合并到一個表中,這篇文章主要給大家介紹了關(guān)于MySQL實現(xiàn)merge?into四種方法的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07
mysql日志文件General_log和Binlog開啟及詳解
MySQL中的數(shù)據(jù)變化會體現(xiàn)在上面日志中,下面這篇文章主要給大家介紹了關(guān)于mysql日志文件General_log和Binlog開啟及詳解的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
mysql中ALTER AGGREGATE使用場景小結(jié)
ALTER AGGREGATE?是 SQL 中用于修改已定義聚合函數(shù)的語法,本文主要介紹了mysql中ALTER AGGREGATE使用場景小結(jié),具有一定的的參考價值,感興趣的可以了解一下2025-05-05
用批處理實現(xiàn)自動備份和清理mysql數(shù)據(jù)庫的代碼
有網(wǎng)友問我在win2003下如何自動備份MySQL數(shù)據(jù)庫,既然是自動備份,那肯定得寫腳本,當(dāng)然我們也可以利用軟件實現(xiàn)2013-08-08
MySQL9.0(innovation)安裝及配置詳細(xì)教程
MySQL對于開發(fā)者來說,不但體積小,速度也很可觀,最最重要的是開源,所以非常受開發(fā)者們的歡迎,這篇文章主要給大家介紹了關(guān)于MySQL9.0(innovation)安裝及配置的詳細(xì)教程,需要的朋友可以參考下2024-08-08

