欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mysql的主從同步/復(fù)制的原理分析

 更新時(shí)間:2025年06月06日 14:39:26   作者:奇怪的爪哇島開(kāi)發(fā)  
這篇文章主要介紹了Mysql的主從同步/復(fù)制的原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

為什么要主從同步?

  • 數(shù)據(jù)容災(zāi)、備份。當(dāng)我們的數(shù)據(jù)庫(kù)只使用一臺(tái)服務(wù)時(shí),如果我們的數(shù)據(jù)庫(kù)遭到破壞,例如黑客的攻擊、人為操作的失誤等等情況。這時(shí)候我們就可以在一定程度上保障我們數(shù)據(jù)庫(kù)的恢復(fù)。
  • 緩解 MySQL 主服務(wù)的壓力。主服務(wù)器寫(xiě)數(shù)據(jù),從服務(wù)器讀數(shù)據(jù)(讀寫(xiě)分離)。

Mysql主從同步架構(gòu)有哪些?

一主一從/多從架構(gòu)

  • 適用于讀多寫(xiě)少

雙主/多主

  • 適用于讀寫(xiě)均勻,同時(shí)整體的并發(fā)量也不算低,至少超出了單庫(kù)的承載閾值

多主一從

  • 適用于寫(xiě)大于讀

級(jí)聯(lián)復(fù)制架構(gòu)

  • 存在兩層從庫(kù),這實(shí)際上屬于一主多從架構(gòu)的升級(jí)版,畢竟如果一個(gè)主節(jié)點(diǎn)存在多個(gè)從節(jié)點(diǎn)時(shí),多個(gè)從節(jié)點(diǎn)都會(huì)同時(shí)去主節(jié)點(diǎn)拉取新數(shù)據(jù),如果數(shù)據(jù)量較大,就會(huì)導(dǎo)致主節(jié)點(diǎn)的I/O負(fù)載過(guò)高,因此這種級(jí)聯(lián)復(fù)制架構(gòu)要解決的問(wèn)題,也就是多個(gè)從庫(kù)會(huì)對(duì)主庫(kù)造成太大壓力的問(wèn)題。
  • 下面會(huì)根據(jù)原理介紹為什么級(jí)聯(lián)復(fù)制架構(gòu)更好

主從架構(gòu),都會(huì)存在致命硬傷,同時(shí)也會(huì)存在些許問(wèn)題需要解決:

  • 硬傷:木桶效應(yīng),一個(gè)主從集群中所有節(jié)點(diǎn)的容量,受限于存儲(chǔ)容量最低的哪臺(tái)服務(wù)器。
  • 數(shù)據(jù)一致性問(wèn)題:由于同步復(fù)制數(shù)據(jù)的過(guò)程是基于網(wǎng)絡(luò)傳輸完成的,所以存儲(chǔ)延遲性。
  • 腦裂問(wèn)題:從節(jié)點(diǎn)會(huì)通過(guò)心跳機(jī)制,發(fā)送網(wǎng)絡(luò)包來(lái)判斷主機(jī)是否存活,網(wǎng)絡(luò)故障情況下會(huì)產(chǎn)生多主。

Mysql主從復(fù)制的原理/整體流程

  • master 服務(wù)器會(huì)將 SQL 記錄通過(guò)多 dump 線(xiàn)程寫(xiě)入到 binary log 中。
  • 主庫(kù)會(huì)為每個(gè)從庫(kù)創(chuàng)建一個(gè)專(zhuān)屬的 dump 線(xiàn)程。
  • slave 服務(wù)器開(kāi)啟一個(gè) io thread 線(xiàn)程向服務(wù)器發(fā)送請(qǐng)求,向 master 服務(wù)器請(qǐng)求 binary log。master 服務(wù)器在接收到請(qǐng)求之后,根據(jù)偏移量將新的 binary log 發(fā)送給 slave 服務(wù)器。
  • slave 服務(wù)器收到新的 binary log 之后,寫(xiě)入到自身的 relay log 中,這就是所謂的中繼日志。
  • slave 服務(wù)器,單獨(dú)開(kāi)啟一個(gè) sql thread 讀取 relay log 之后,寫(xiě)入到自身數(shù)據(jù)中。

級(jí)聯(lián)復(fù)制架構(gòu)為什么好?

級(jí)聯(lián)復(fù)制架構(gòu)好的原因大家可以從這個(gè)圖中可以看出,主庫(kù)會(huì)為每個(gè)從庫(kù)建立一個(gè)Dump線(xiàn)程,而Dump線(xiàn)程又擔(dān)負(fù)著重要的作用:將監(jiān)聽(tīng)到的數(shù)據(jù)通過(guò)網(wǎng)絡(luò)傳輸發(fā)送給從庫(kù)??上攵绻麖膸?kù)過(guò)多對(duì)給主庫(kù)帶來(lái)巨大的IO壓力,那如果只給一個(gè)從庫(kù)發(fā)送數(shù)據(jù),并且這個(gè)從庫(kù)又擔(dān)任其他從庫(kù)的復(fù)制職責(zé),這樣就會(huì)減輕我們主庫(kù)的壓力,從而提高我們主庫(kù)的性能。

Mysql主從復(fù)制注意點(diǎn)

從庫(kù) I/O 線(xiàn)程主要職責(zé)是“接收 + 寫(xiě) relay log

  • 連接到主庫(kù)并請(qǐng)求binlog內(nèi)容
  • 接收主庫(kù)dump線(xiàn)程發(fā)送的binlog事件
  • 將接收到的binlog事件寫(xiě)入從庫(kù)的relay log(中繼日志)
  • 更新從庫(kù)的master info信息(記錄已讀取的主庫(kù)binlog位置)
  • 斷點(diǎn)續(xù)傳:如果連接中斷,IO線(xiàn)程會(huì)按照配置的重試策略定期嘗試重新連接

主庫(kù) dump 線(xiàn)程負(fù)責(zé)從 binlog 中讀取變更數(shù)據(jù),并“源源不斷推送”給從庫(kù)。

  • 等待從庫(kù)連接并發(fā)送binlog位置請(qǐng)求
  • 根據(jù)從庫(kù)請(qǐng)求的binlog文件名和位置(或GTID)定位讀取點(diǎn)
  • 以事件(event)為單位讀取binlog內(nèi)容
  • 將事件發(fā)送給從庫(kù)的I/O線(xiàn)程
  • 在沒(méi)有新事件時(shí)進(jìn)入等待狀態(tài)(不是持續(xù)推送)
  • 即使主庫(kù)沒(méi)有數(shù)據(jù)變化,主庫(kù) dump 線(xiàn)程 也會(huì)根據(jù) master_heartbeat_period 發(fā)送一個(gè) Heartbeat log event 給 從庫(kù) IO 線(xiàn)程,作為 binlog 的一部分傳輸,用來(lái)維持連接活躍、防止超時(shí)斷線(xiàn)。
  • 主庫(kù)是怎么判斷從庫(kù)有沒(méi)有數(shù)據(jù)?
  • 主庫(kù)不判斷!是從庫(kù)告訴主庫(kù)它需要從哪個(gè)位置開(kāi)始同步!

MySQL 支持三種 binlog 格式(也就是傳輸給從庫(kù)的數(shù)據(jù)格式)

STATEMENT (不推薦,有風(fēng)險(xiǎn))

  • 最早期的方式,記錄執(zhí)行的原始 SQL 語(yǔ)句
  • 優(yōu)點(diǎn):可讀(看得懂)、日志體積小、性能開(kāi)銷(xiāo)小
  • 缺點(diǎn):有副作用可能不一致(如 UUID、now())

ROW(依舊是邏輯日志)

  • 不記錄 SQL,而是記錄每一行數(shù)據(jù)的變更

對(duì)比redolog

  • redolog:表空間X,頁(yè)號(hào)Y,偏移量Z處的數(shù)據(jù)從0x1234改為0x5678
  • redolog記錄的是具體的物理存儲(chǔ)位置而ROW僅存儲(chǔ)表信息以及數(shù)據(jù)因此依舊是邏輯日志(這里大家不要混淆以為記錄數(shù)據(jù)就是物理日志)
  • 記錄信息:表的 database name + table name、表的 列結(jié)構(gòu)、對(duì)應(yīng)數(shù)據(jù)行的變化
  • 優(yōu)點(diǎn):準(zhǔn)確,幾乎無(wú)副作用問(wèn)題
  • 缺點(diǎn):日志體積大、不可讀(二進(jìn)制)、性能開(kāi)銷(xiāo)大(行變更多則更慢)

MIXED

  • 自動(dòng)在 STATEMENT 和 ROW 之間切換,MySQL 自行判斷

主從復(fù)制數(shù)據(jù)的模式(重點(diǎn))

相信大家看有的博客說(shuō)Mysql主從模式三種或有四種模式的,錯(cuò)大錯(cuò)特錯(cuò),其實(shí)就兩種模式,其他兩種是基于第二個(gè)模式配置出來(lái)的,下面給大家具體介紹一下:

異步復(fù)制(默認(rèn))

  • 客戶(hù)端發(fā)送請(qǐng)求先寫(xiě)入主庫(kù)并返回客戶(hù)端,然后再異步同步給從庫(kù)
  • 優(yōu)點(diǎn):返回給客戶(hù)端快,不會(huì)因?yàn)橥綇膸?kù)帶來(lái)阻塞
  • 缺點(diǎn):主從數(shù)據(jù)不一致的風(fēng)險(xiǎn)

半同步模式(推薦)

  • 在異步同步的基礎(chǔ)上等待從庫(kù)返回結(jié)果再返回給客戶(hù)端
  • 優(yōu)點(diǎn):極大的保證了主庫(kù)和從庫(kù)的數(shù)據(jù)一致性
  • 缺點(diǎn):對(duì)客戶(hù)端的阻塞帶來(lái)影響

內(nèi)部細(xì)節(jié)

  • 如果從庫(kù)相應(yīng)時(shí)間過(guò)長(zhǎng)默認(rèn)10秒,會(huì)切換為異步同步模式

同時(shí)為了避免網(wǎng)絡(luò)延遲造成主庫(kù)長(zhǎng)時(shí)間收不到從庫(kù)的ACK,因此在配置半同步式復(fù)制時(shí),會(huì)有一個(gè)rpl_semi_sync_master_timeout參數(shù)來(lái)控制超時(shí)時(shí)間,其默認(rèn)值是10000ms/10s,如若主庫(kù)在10s內(nèi)依舊未收到從庫(kù)的ACK,則會(huì)將復(fù)制模式切換成異步模式,切成異步模式后,會(huì)在后續(xù)網(wǎng)絡(luò)正常后再次切回半同步模式。

  • 對(duì)于多個(gè)從庫(kù)節(jié)點(diǎn)可以配置有多少個(gè)從庫(kù)返回就給客戶(hù)端響應(yīng)

5.7版本后對(duì)主從一致性保障策略

AFTER_SYNC(默認(rèn),增強(qiáng)半同步復(fù)制)【其他博客的第三種模式】

當(dāng)主庫(kù)未收到從庫(kù)的ACK之前,也不會(huì)在主庫(kù)上提交事務(wù),也就是保證了主從節(jié)點(diǎn)的數(shù)據(jù)強(qiáng)一致性,解決了after-commit中存在的問(wèn)題。

AFTER_COMMIT(傳統(tǒng)半同步復(fù)制,可能出現(xiàn)數(shù)據(jù)不一致)

  • 主庫(kù)在未收到從庫(kù)的ACK之前,雖然不會(huì)給客戶(hù)端返回寫(xiě)入成功,但本質(zhì)上在MySQL中會(huì)提交事務(wù),也就是主庫(kù)中的其他事務(wù)是可以看見(jiàn)對(duì)應(yīng)數(shù)據(jù)的,當(dāng)此時(shí)出現(xiàn)宕機(jī)時(shí),就會(huì)導(dǎo)致舊主上能查詢(xún)出的數(shù)據(jù),在新主(原本的從庫(kù))上無(wú)法查詢(xún)出來(lái)了。
  • 兩者之間的區(qū)別就在于:對(duì)主從節(jié)點(diǎn)的數(shù)據(jù)嚴(yán)格性不同,一般情況下,無(wú)損復(fù)制會(huì)比傳統(tǒng)半同步復(fù)制開(kāi)銷(xiāo)更大一些,因?yàn)槭聞?wù)遲遲不提交,會(huì)導(dǎo)致對(duì)應(yīng)的鎖資源不會(huì)主動(dòng)釋放,其他需要獲取對(duì)應(yīng)鎖資源的事務(wù)只能阻塞等待,這會(huì)造成主庫(kù)的整體性能出現(xiàn)一定影響。

同步復(fù)制(本身不支持,需通過(guò)半同步復(fù)制設(shè)置為等待所有從庫(kù)【其他博客中第四種模式】

  • 對(duì)于同步復(fù)制而言,Master主機(jī)將事件發(fā)送給Slave主機(jī)后會(huì)觸發(fā)一個(gè)等待,直到所有Slave節(jié)點(diǎn)(如果有多個(gè)Slave)返回?cái)?shù)據(jù)復(fù)制成功的信息給Master。這種復(fù)制方式最安
  • 全,但是同時(shí),效率也是最差的。

Mysql對(duì)于從庫(kù)的一些優(yōu)化/策略

  • 從庫(kù)的執(zhí)行策略

延遲復(fù)制

延遲復(fù)制通常用于一些特殊場(chǎng)景,它可以支持從庫(kù)數(shù)據(jù)的延遲同步,也就是當(dāng)從庫(kù)上的I/O線(xiàn)程,將主庫(kù)的Bin-log日志請(qǐng)求回來(lái)后,從節(jié)點(diǎn)的SQL線(xiàn)程并不會(huì)立刻解析日志執(zhí)行,而是等待一段時(shí)間后再解析日志執(zhí)行,這個(gè)等待的時(shí)間可以由開(kāi)發(fā)者來(lái)配置,一般建議設(shè)為3~6小時(shí)之間。

那延遲復(fù)制的好處在于什么呢?

可以防止誤刪操作,如若在主庫(kù)上不小心誤刪了大量數(shù)據(jù)、表、庫(kù)或其他數(shù)據(jù)庫(kù)對(duì)象,因?yàn)閺膸?kù)并不是立即執(zhí)行同步過(guò)去的記錄,因此可以及時(shí)通過(guò)從節(jié)點(diǎn)上的數(shù)據(jù)回滾數(shù)據(jù)。除此之外,也能對(duì)一些線(xiàn)上Bug進(jìn)行實(shí)時(shí)觀(guān)測(cè),比如一個(gè)無(wú)法復(fù)現(xiàn)的故障問(wèn)題發(fā)生時(shí),如果發(fā)現(xiàn)時(shí)還在配置的延遲復(fù)制時(shí)間內(nèi),則可以去到從庫(kù)上觀(guān)察。

  • 從庫(kù)的優(yōu)化手段并行復(fù)制(mysql8.0更完善)

GTID復(fù)制(為什么要先說(shuō)GTID,因?yàn)椴⑿袕?fù)制是基于組復(fù)制,而組復(fù)制是基于GTID)

  • 在傳統(tǒng)的主從架構(gòu)中,當(dāng)需要發(fā)生主從切換時(shí),需要開(kāi)發(fā)/運(yùn)維人員手動(dòng)找到Bin-log的POS同步點(diǎn),然后執(zhí)行change master to [new-master-pos]命令,將其他從節(jié)點(diǎn)指向新主庫(kù),但每個(gè)從節(jié)點(diǎn)可能同步數(shù)據(jù)的進(jìn)度都不一致,因此每個(gè)從節(jié)點(diǎn)都需要去找到它上次的POS點(diǎn),然后指向新主庫(kù),這個(gè)工作是不是聽(tīng)起來(lái)就比較繁雜?答案是Yes,不過(guò)到了MySQL5.6版本后,開(kāi)啟了GTID復(fù)制后,則無(wú)需手動(dòng)尋找POS點(diǎn)!
  • GTID(Global Transaction ID)也就是全局事務(wù)標(biāo)識(shí)符的意思,它由節(jié)點(diǎn)UUID+事務(wù)ID兩部分組成,MySQL在第一次啟動(dòng)時(shí)都會(huì)利用UUID隨機(jī)生成一個(gè)server_id,還記得在之前的《MVCC機(jī)制》中聊過(guò)的事務(wù)ID嘛?MySQL會(huì)對(duì)每一個(gè)寫(xiě)事務(wù)都分配一個(gè)順序遞增的值作為事務(wù)ID,而GTID則是由這兩玩意兒組成的,格式為server_uuid:trx_id。
  • 當(dāng)主庫(kù)的事務(wù)有了這個(gè)全局事務(wù)標(biāo)識(shí)后,再發(fā)生主從切換時(shí)就無(wú)需手動(dòng)尋點(diǎn)了,僅需要執(zhí)行change master to master_auto_position = 1這條命令即可,它會(huì)自動(dòng)去新主庫(kù)上尋找數(shù)據(jù)的同步點(diǎn),也就是MySQL自身就具備斷點(diǎn)復(fù)制的功能。

為什么需要用GTID代替POS同步點(diǎn)呢?

因?yàn)橥粋€(gè)主從集群中,所有節(jié)點(diǎn)加入集群的時(shí)間可能會(huì)不同

假設(shè)這個(gè)集群中每個(gè)節(jié)點(diǎn)加入的時(shí)間都不一致

  • master:日志文件中的同步點(diǎn)POS=1200。
  • slave1:日志文件中的同步點(diǎn)POS=1100。
  • slave2:日志文件中的同步點(diǎn)POS=800。
  • slave3:日志文件中的同步點(diǎn)POS=200。

此時(shí)假設(shè)master節(jié)點(diǎn)宕機(jī)或故障了,slave1成為了新主,那么slave2、slave3也應(yīng)該成為新主slave1的從節(jié)點(diǎn),但此刻問(wèn)題就來(lái)了:原本slave2、slave3的POS同步點(diǎn)是基于master中的日志而言的,但現(xiàn)在主節(jié)點(diǎn)變成了slave1,這時(shí)slave2、slave3如何去尋找自己在slave1中的POS點(diǎn)呢?顯然MySQL無(wú)法自己完成該工作,因此需要人工指定同步點(diǎn)才行。

而GTID出現(xiàn)的原因,就是為了解決上述這個(gè)問(wèn)題,但具體怎么解決的呢?

GTID的工作過(guò)程

master在更新數(shù)據(jù)時(shí),會(huì)為每一個(gè)寫(xiě)事務(wù)分配一個(gè)全局的GTID,并記錄到Bin-log中。

slave節(jié)點(diǎn)的I/O線(xiàn)程拉取數(shù)據(jù)時(shí),會(huì)將讀到的記錄寫(xiě)到relay-log中,并設(shè)置gtid_next值。

slave節(jié)點(diǎn)的SQL線(xiàn)程執(zhí)行前,會(huì)讀取gtid_next值得知接下來(lái)該解析哪條日志并執(zhí)行。

slave節(jié)點(diǎn)的SQL線(xiàn)程在執(zhí)行時(shí),會(huì)先比對(duì)自身的Bin-log日志中是否有對(duì)應(yīng)的GTID:

  • 有:意味著該GTID對(duì)應(yīng)的事務(wù)已經(jīng)執(zhí)行過(guò)了,slave會(huì)自動(dòng)忽略掉這條記錄。
  • 沒(méi)有:SQL解析該GTID對(duì)應(yīng)的relay-log記錄并執(zhí)行,再將GTID記錄到Bin-log。

GTID自動(dòng)尋找同步點(diǎn)的原理

  • 開(kāi)啟GTID后,從庫(kù)會(huì)基于它來(lái)復(fù)制主庫(kù)的數(shù)據(jù),此時(shí)發(fā)生了主從切換,假設(shè)這時(shí)主從集群中有多個(gè)從節(jié)點(diǎn),MySQL首先會(huì)選擇距離master的GTID最近的從節(jié)點(diǎn)作為新主,然后將其他從節(jié)點(diǎn)轉(zhuǎn)變?yōu)樾轮鞯膹膸?kù),其他從庫(kù)會(huì)根據(jù)自身gtid_next值,去新主的日志文件中做對(duì)比,然后找到各自的同步點(diǎn),繼續(xù)從新主中復(fù)制數(shù)據(jù)。
  • 因?yàn)镸ySQL挑選的是和舊主GTID值,最接近的從節(jié)點(diǎn)作為新主,也就意味著作為新主的從節(jié)點(diǎn),絕對(duì)會(huì)比其他從節(jié)點(diǎn)的數(shù)據(jù)要完善,因此新主中的GTID值也是最大的!同時(shí),每個(gè)從節(jié)點(diǎn)中都存在一個(gè)gtid_next值,記錄著自身下一次要同步數(shù)據(jù)的GTID值,此時(shí)剩下的從節(jié)點(diǎn)就可以根據(jù)該值,直接去新主中尋找到自己的同步點(diǎn)位置,從而避免了之前那種手動(dòng)介入的尷尬場(chǎng)景出現(xiàn)。
  • 不過(guò)由于GTID復(fù)制是基于事務(wù)來(lái)實(shí)現(xiàn)的,這也就代表不支持事務(wù)的存儲(chǔ)引擎無(wú)法使用這種機(jī)制,在之前的章節(jié)中也聊過(guò),MySQL眾多存儲(chǔ)引擎中,基本上只有InnoDB支持事務(wù),所以GTID機(jī)制基本上只對(duì)InnoDB引擎生效。
  • 組復(fù)制

GTID復(fù)制則是組復(fù)制的實(shí)現(xiàn)基礎(chǔ),而組復(fù)制則是并行復(fù)制的基礎(chǔ),那么什么叫做組復(fù)制呢?組復(fù)制是指將一組并行執(zhí)行的事務(wù),全部放入到一個(gè)GTID中記錄,后續(xù)從節(jié)點(diǎn)同步數(shù)據(jù)時(shí),會(huì)一次性讀取這一組事務(wù)解析并執(zhí)行,與傳統(tǒng)的GTID區(qū)別如下:

  • 傳統(tǒng)的GTID值由節(jié)點(diǎn)ID+事務(wù)ID組成:12EEA4RD6-45AC-667B-33DD-CCC55EF718D:88。
  • 組復(fù)制的GTID通過(guò)逗號(hào)分隔:12EEA4RD6-45AC-667B-33DD-CCC55EF718D:89, 12EEA4RD6-45AC-667B-33DD-CCC55EF718D:89-94, ......。

MySQL如何實(shí)現(xiàn)事務(wù)分組的呢?

  • MySQL提交事務(wù)時(shí)內(nèi)部會(huì)調(diào)用ordered_commit函數(shù)來(lái)處理相關(guān)工作,其函數(shù)執(zhí)行的邏輯流程圖如下:

當(dāng)一個(gè)事務(wù)提交時(shí)都會(huì)調(diào)用ordered_commit函數(shù),首先會(huì)將事務(wù)加入等待事務(wù)組,接著會(huì)經(jīng)過(guò)三個(gè)核心步驟:FLUSH、SYNC、COMMIT,對(duì)應(yīng)的也會(huì)有三個(gè)隊(duì)列,它們?nèi)叩墓ぷ髟矶即笾孪嗤?/p>

  • ①如果某個(gè)事務(wù)進(jìn)入FLUSH隊(duì)列時(shí),該隊(duì)列還是空的,則這個(gè)事務(wù)會(huì)擔(dān)任“隊(duì)長(zhǎng)”的角色。
  • ②當(dāng)后續(xù)其他事務(wù)進(jìn)入隊(duì)列時(shí),發(fā)現(xiàn)隊(duì)列不為空,則會(huì)將提交工作委托給隊(duì)長(zhǎng)來(lái)完成。
  • ③如上圖中的「事務(wù)1」則是隊(duì)長(zhǎng),后續(xù)的都是隊(duì)員,但隊(duì)長(zhǎng)不會(huì)無(wú)限制等待隊(duì)員到來(lái):

從隊(duì)長(zhǎng)加入的時(shí)間點(diǎn)開(kāi)始,當(dāng)超出binlog_group_commit_sync_delay規(guī)定的時(shí)間后,就會(huì)進(jìn)行一次組提交。

  • 同一時(shí)刻只允許一組事務(wù)做這些工作,也就是當(dāng)有另外一組事務(wù)提交時(shí),需要等待上一組事務(wù)提交完成。
  • 在做組提交工作時(shí),會(huì)將當(dāng)前事務(wù)組的內(nèi)容記錄到Bin-log日志中,同時(shí)會(huì)將這組事務(wù)記錄成一個(gè)GTID,不同事務(wù)之間通過(guò),逗號(hào)分隔(實(shí)際過(guò)程更為復(fù)雜,這里只做簡(jiǎn)單講解)。

并行復(fù)制

在MySQL5.6之前的版本中,從庫(kù)同步數(shù)據(jù)時(shí),所有數(shù)據(jù)同步工作都是基于單線(xiàn)程完成的,也就是不管主庫(kù)上的數(shù)據(jù)是不是多線(xiàn)程并發(fā)寫(xiě)入的,從庫(kù)上只會(huì)有一條SQL線(xiàn)程來(lái)執(zhí)行解析執(zhí)行工作。

到了MySQL5.6之后,引入了并行復(fù)制的思想,但5.6中的并行復(fù)制極其雞肋,基本無(wú)人問(wèn)津,因?yàn)槭腔趲?kù)級(jí)別的并行復(fù)制,也就是一個(gè)從節(jié)點(diǎn)對(duì)應(yīng)多個(gè)主節(jié)點(diǎn)時(shí),有幾個(gè)主節(jié)點(diǎn)就開(kāi)幾條SQL線(xiàn)程去解析并寫(xiě)入數(shù)據(jù),即多主一從架構(gòu)中才會(huì)用到。

因?yàn)楣俜阶畛踉趯?shí)現(xiàn)并行復(fù)制時(shí),一直糾結(jié)鎖沖突的問(wèn)題,所以為了防止并行執(zhí)行時(shí)出現(xiàn)數(shù)據(jù)沖突,就造出了上面那種庫(kù)級(jí)別的并行復(fù)制,為啥要糾結(jié)鎖/數(shù)據(jù)沖突呢?

比如從庫(kù)I/O線(xiàn)程在主庫(kù)中請(qǐng)求了100條記錄回去,從庫(kù)中開(kāi)100條SQL線(xiàn)程解析并執(zhí)行這些記錄,如果其中有兩條記錄操作的是同一條數(shù)據(jù),就會(huì)出現(xiàn)鎖沖突問(wèn)題。

  • 但上述原因不是最主要的,最主要的是并發(fā)執(zhí)行的順序問(wèn)題,如果主庫(kù)上對(duì)于一條數(shù)據(jù)是先改后刪,從庫(kù)在并發(fā)執(zhí)行時(shí),因?yàn)槎嗑€(xiàn)程執(zhí)行的無(wú)序性,把執(zhí)行順序改為了先刪后改,這顯然就會(huì)導(dǎo)致數(shù)據(jù)沖突,因此變更操作很難實(shí)現(xiàn)并行復(fù)制。
  • 到了MySQL5.7中,才基于組復(fù)制技術(shù)實(shí)現(xiàn)了真正意義上的并行復(fù)制,因?yàn)槟軌蛟谕粫r(shí)間內(nèi)提交的事務(wù),絕對(duì)是不存在鎖沖突的,所以可以開(kāi)啟多條線(xiàn)程同時(shí)執(zhí)行一個(gè)組中不同的事務(wù),但這個(gè)思想是從MariaDB中照抄過(guò)來(lái)的~

一句話(huà)來(lái)總結(jié)就是:主庫(kù)上是咋樣并發(fā)寫(xiě)入數(shù)據(jù)的,從庫(kù)也會(huì)開(kāi)啟對(duì)應(yīng)的線(xiàn)程數(shù)去并發(fā)寫(xiě)入。

在5.7中官方為這種機(jī)制命名為enhanced multi-threaded slave,簡(jiǎn)稱(chēng)MTS機(jī)制,同時(shí)為了兼容5.6版本中的并行復(fù)制,又多加入了一個(gè)slave-parallel-type參數(shù):

  • DATABASE:默認(rèn)的并行復(fù)制模式,表示基于庫(kù)級(jí)別的來(lái)完成并行復(fù)制。
  • LOGICAL_CLOCK:表示基于組提交的方式來(lái)完成并行復(fù)制。

并行復(fù)制出現(xiàn)的意義是什么?

能夠在很大程度上提升從庫(kù)復(fù)制數(shù)據(jù)的速度,也就是能夠讓從庫(kù)的數(shù)據(jù)實(shí)時(shí)性提升,尤其是無(wú)損復(fù)制模式中,主節(jié)點(diǎn)需要等待從節(jié)點(diǎn)的ACK才會(huì)真正提交事務(wù),從庫(kù)使用并行復(fù)制后,能夠在一定程度上解決從庫(kù)的復(fù)制延遲問(wèn)題。

不過(guò)雖然5.7中的并行復(fù)制,在一定程度上解決了原有的從庫(kù)延遲問(wèn)題,但如果一個(gè)新的從節(jié)點(diǎn)加入集群時(shí),因?yàn)橐獜念^開(kāi)始同步數(shù)據(jù),這種并行復(fù)制的模式依舊存在效率問(wèn)題,而到了MySQL8.0中,對(duì)于并行復(fù)制技術(shù)提出了真正的解決之道,也就是基于writeset的MTS技術(shù)。

主從數(shù)據(jù)一致性的解決方案

讀寫(xiě)分離數(shù)據(jù)一致性場(chǎng)景:一個(gè)用戶(hù)將個(gè)人信息修改后,然后再次查看時(shí),發(fā)現(xiàn)個(gè)人信息依舊是修改之前的原數(shù)據(jù),這時(shí)用戶(hù)就有可能再次修改,經(jīng)過(guò)反反復(fù)復(fù)多次修改后,用戶(hù)發(fā)現(xiàn)依舊未生效

想要解決上述這種讀寫(xiě)分離導(dǎo)致的數(shù)據(jù)不一致性,主要有四種解決方案:

業(yè)務(wù)邏輯做改變、復(fù)制方式做更改、數(shù)據(jù)庫(kù)架構(gòu)做調(diào)整、引入第三方中間件。

改變業(yè)務(wù)邏輯

  • 對(duì)業(yè)務(wù)做一定更改,比如當(dāng)用戶(hù)立即修改數(shù)據(jù)后,因?yàn)樵趶膸?kù)讀不到數(shù)據(jù),所以先顯示一個(gè)審核狀態(tài),這樣能夠給出用戶(hù)的反饋,從而避免用戶(hù)再次重復(fù)操作
  • 這種方式屬于和數(shù)據(jù)不一致妥協(xié)的方案,接受一定的數(shù)據(jù)延遲,不過(guò)這種方式并不適用于一些對(duì)數(shù)據(jù)實(shí)時(shí)性要求較高的場(chǎng)景

更改復(fù)制方式

  • 在之前曾聊過(guò)MySQL四種數(shù)據(jù)同步復(fù)制的方式,即全同步、異步、半同步與無(wú)損復(fù)制,MySQL默認(rèn)會(huì)是異步復(fù)制模式,即主節(jié)點(diǎn)寫(xiě)入數(shù)據(jù)后會(huì)立即返回成功的狀態(tài)給客戶(hù)端,這樣能夠確保性能達(dá)到最佳,但如果對(duì)實(shí)時(shí)性要求較高,可以將其改為全同步或半同步模式。

調(diào)整數(shù)據(jù)庫(kù)架構(gòu)

  • 如果無(wú)法接受主從架構(gòu)帶來(lái)的短期數(shù)據(jù)不一致,那可以升級(jí)服務(wù)器硬件,并將架構(gòu)恢復(fù)成單庫(kù)架構(gòu),所有讀寫(xiě)操作都走單庫(kù)完成,這就自然不會(huì)出現(xiàn)數(shù)據(jù)不一致問(wèn)題。
  • 但如果升級(jí)硬件配置后,無(wú)法承載客戶(hù)端的訪(fǎng)問(wèn)壓力時(shí),可將整體架構(gòu)升級(jí)到分庫(kù)分表架構(gòu),制定好合適的分片策略和路由鍵,每次讀寫(xiě)數(shù)據(jù)都根據(jù)業(yè)務(wù)不同,操作不同的庫(kù)。

引入第三方中間件

  • 前面聊到的三種方案,多多少少都存在一些局限性,因?yàn)橐唇邮軘?shù)據(jù)不一致、要么損失性能、要么使用更高規(guī)模的架構(gòu)處理,但這些方案似乎都存在令人不能接受的后患,那有沒(méi)有一種萬(wàn)全之策來(lái)解決這個(gè)問(wèn)題呢?答案是有的,就是引入Canal中間件來(lái)監(jiān)控主節(jié)點(diǎn)的Bin-log日志。
  • 在之前講主從同步數(shù)據(jù)原理時(shí),曾講到過(guò),主節(jié)點(diǎn)上存在一個(gè)log dump線(xiàn)程會(huì)監(jiān)聽(tīng)Bin-log日志,當(dāng)日志出現(xiàn)變更時(shí)會(huì)通知從節(jié)點(diǎn)來(lái)拉取數(shù)據(jù),而Canal的思想也是一樣的,會(huì)監(jiān)控主節(jié)點(diǎn)的Bin-log日志,當(dāng)發(fā)生變更時(shí),就直接去拉取數(shù)據(jù),然后直接推送給從節(jié)點(diǎn)寫(xiě)入。
  • 但這種方式也無(wú)法做到真正的數(shù)據(jù)實(shí)時(shí)性,畢竟Canal監(jiān)聽(tīng)變更、拉取數(shù)據(jù)、推送數(shù)據(jù)都需要時(shí)間,這部分的時(shí)間開(kāi)銷(xiāo)必然存在,只是它會(huì)比從庫(kù)去主庫(kù)上拉取,速度會(huì)更快一些罷了。
  • 一般企業(yè)內(nèi)部都會(huì)引入Canal來(lái)解決數(shù)據(jù)不一致問(wèn)題,因?yàn)樗粌H僅只能解決主從延遲問(wèn)題,還能解決MySQL-ES、MySQL-Redis.....等多種數(shù)據(jù)不一致的場(chǎng)景
  • 也可以制定某些敏感數(shù)據(jù)走主庫(kù)查詢(xún),這樣能夠確保數(shù)據(jù)的實(shí)時(shí)性,但容易模糊讀寫(xiě)分離的界限,不過(guò)因?yàn)椴恍枰腩~外的技術(shù),所以在某些情況下也是個(gè)不錯(cuò)的方案。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MySQL中如何將字符串替換簡(jiǎn)單示例

    MySQL中如何將字符串替換簡(jiǎn)單示例

    mysql是一種常用的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它提供了多種函數(shù)來(lái)處理和操作數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于MySQL中如何將字符串替換的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • 一文學(xué)習(xí)MySQL?意向共享鎖、意向排他鎖、死鎖

    一文學(xué)習(xí)MySQL?意向共享鎖、意向排他鎖、死鎖

    這篇文章主要介紹了MySQL?意向共享鎖、意向排他鎖、死鎖,包括InnoDB表級(jí)鎖,意向共享鎖和意向排他鎖及操作方法,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • mysql 設(shè)置查詢(xún)緩存

    mysql 設(shè)置查詢(xún)緩存

    查詢(xún)緩存絕不返回過(guò)期數(shù)據(jù)。當(dāng)數(shù)據(jù)被修改后,在查詢(xún)緩存中的任何相關(guān)詞條均被轉(zhuǎn)儲(chǔ)清除。
    2009-08-08
  • 查找MySQL中查詢(xún)慢的SQL語(yǔ)句方法

    查找MySQL中查詢(xún)慢的SQL語(yǔ)句方法

    這篇文章主要介紹了查找MySQL中查詢(xún)慢的SQL語(yǔ)句方法,需要的朋友可以參考下
    2017-05-05
  • MySQL數(shù)據(jù)庫(kù)表被鎖、解鎖以及刪除事務(wù)詳解

    MySQL數(shù)據(jù)庫(kù)表被鎖、解鎖以及刪除事務(wù)詳解

    這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫(kù)表被鎖、解鎖以及刪除事務(wù)的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • select?into?from和insert?into?select的區(qū)別舉例詳解

    select?into?from和insert?into?select的區(qū)別舉例詳解

    這篇文章主要介紹了SQL中的SELECT?INTO和INSERT?INTO?SELECT兩種語(yǔ)句的區(qū)別和用法,SELECT?INTO用于創(chuàng)建新表并復(fù)制數(shù)據(jù)到新表中,而INSERT?INTO?SELECT用于將數(shù)據(jù)從一個(gè)表插入到已存在的另一個(gè)表中,需要的朋友可以參考下
    2025-03-03
  • 把MySQL卸載干凈的超詳細(xì)步驟

    把MySQL卸載干凈的超詳細(xì)步驟

    這篇文章主要介紹了把MySQL卸載干凈的超詳細(xì)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)吧
    2024-02-02
  • MySQL  Lock wait timeout exceeded錯(cuò)誤解決

    MySQL  Lock wait timeout exceeded錯(cuò)誤

    “Lock wait timeout exceeded” 是一個(gè)常見(jiàn)的MySQL錯(cuò)誤,指示了潛在的性能問(wèn)題或死鎖,本文就來(lái)介紹一下如何解決,感興趣的可以了解一下
    2024-05-05
  • MySQL Event Scheduler(事件調(diào)度器)

    MySQL Event Scheduler(事件調(diào)度器)

    事件調(diào)度器是在 MySQL 5.1 中新增的另一個(gè)特色功能,可以作為定時(shí)任務(wù)調(diào)度器,取代部分原先只能用操作系統(tǒng)任務(wù)調(diào)度器才能完成的定時(shí)功能。
    2010-06-06
  • MySQL?常見(jiàn)時(shí)間字段設(shè)置小結(jié)

    MySQL?常見(jiàn)時(shí)間字段設(shè)置小結(jié)

    本文詳細(xì)探討了MySQL中常見(jiàn)時(shí)間字段的設(shè)置和處理,包括DATETIME、DATE、TIME和TIMESTAMP等類(lèi)型的介紹,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11

最新評(píng)論