Mysql的主從同步/復(fù)制的原理分析
為什么要主從同步?
- 數(shù)據(jù)容災(zāi)、備份。當(dāng)我們的數(shù)據(jù)庫只使用一臺(tái)服務(wù)時(shí),如果我們的數(shù)據(jù)庫遭到破壞,例如黑客的攻擊、人為操作的失誤等等情況。這時(shí)候我們就可以在一定程度上保障我們數(shù)據(jù)庫的恢復(fù)。
- 緩解 MySQL 主服務(wù)的壓力。主服務(wù)器寫數(shù)據(jù),從服務(wù)器讀數(shù)據(jù)(讀寫分離)。
Mysql主從同步架構(gòu)有哪些?
一主一從/多從架構(gòu)
- 適用于讀多寫少
雙主/多主
- 適用于讀寫均勻,同時(shí)整體的并發(fā)量也不算低,至少超出了單庫的承載閾值
多主一從
- 適用于寫大于讀
級(jí)聯(lián)復(fù)制架構(gòu)
- 存在兩層從庫,這實(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ù)載過高,因此這種級(jí)聯(lián)復(fù)制架構(gòu)要解決的問題,也就是多個(gè)從庫會(huì)對(duì)主庫造成太大壓力的問題。
- 下面會(huì)根據(jù)原理介紹為什么級(jí)聯(lián)復(fù)制架構(gòu)更好
主從架構(gòu),都會(huì)存在致命硬傷,同時(shí)也會(huì)存在些許問題需要解決:
- 硬傷:木桶效應(yīng),一個(gè)主從集群中所有節(jié)點(diǎn)的容量,受限于存儲(chǔ)容量最低的哪臺(tái)服務(wù)器。
- 數(shù)據(jù)一致性問題:由于同步復(fù)制數(shù)據(jù)的過程是基于網(wǎng)絡(luò)傳輸完成的,所以存儲(chǔ)延遲性。
- 腦裂問題:從節(jié)點(diǎn)會(huì)通過心跳機(jī)制,發(fā)送網(wǎng)絡(luò)包來判斷主機(jī)是否存活,網(wǎng)絡(luò)故障情況下會(huì)產(chǎn)生多主。
Mysql主從復(fù)制的原理/整體流程
- master 服務(wù)器會(huì)將 SQL 記錄通過多 dump 線程寫入到 binary log 中。
- 主庫會(huì)為每個(gè)從庫創(chuàng)建一個(gè)專屬的 dump 線程。
- slave 服務(wù)器開啟一個(gè) io thread 線程向服務(wù)器發(fā)送請(qǐng)求,向 master 服務(wù)器請(qǐng)求 binary log。master 服務(wù)器在接收到請(qǐng)求之后,根據(jù)偏移量將新的 binary log 發(fā)送給 slave 服務(wù)器。
- slave 服務(wù)器收到新的 binary log 之后,寫入到自身的 relay log 中,這就是所謂的中繼日志。
- slave 服務(wù)器,單獨(dú)開啟一個(gè) sql thread 讀取 relay log 之后,寫入到自身數(shù)據(jù)中。
級(jí)聯(lián)復(fù)制架構(gòu)為什么好?
級(jí)聯(lián)復(fù)制架構(gòu)好的原因大家可以從這個(gè)圖中可以看出,主庫會(huì)為每個(gè)從庫建立一個(gè)Dump線程,而Dump線程又擔(dān)負(fù)著重要的作用:將監(jiān)聽到的數(shù)據(jù)通過網(wǎng)絡(luò)傳輸發(fā)送給從庫。可想而知如果從庫過多對(duì)給主庫帶來巨大的IO壓力,那如果只給一個(gè)從庫發(fā)送數(shù)據(jù),并且這個(gè)從庫又擔(dān)任其他從庫的復(fù)制職責(zé),這樣就會(huì)減輕我們主庫的壓力,從而提高我們主庫的性能。
Mysql主從復(fù)制注意點(diǎn)
從庫 I/O 線程主要職責(zé)是“接收 + 寫 relay log”
- 連接到主庫并請(qǐng)求binlog內(nèi)容
- 接收主庫dump線程發(fā)送的binlog事件
- 將接收到的binlog事件寫入從庫的relay log(中繼日志)
- 更新從庫的master info信息(記錄已讀取的主庫binlog位置)
- 斷點(diǎn)續(xù)傳:如果連接中斷,IO線程會(huì)按照配置的重試策略定期嘗試重新連接
主庫 dump 線程負(fù)責(zé)從 binlog 中讀取變更數(shù)據(jù),并“源源不斷推送”給從庫。
- 等待從庫連接并發(fā)送binlog位置請(qǐng)求
- 根據(jù)從庫請(qǐng)求的binlog文件名和位置(或GTID)定位讀取點(diǎn)
- 以事件(event)為單位讀取binlog內(nèi)容
- 將事件發(fā)送給從庫的I/O線程
- 在沒有新事件時(shí)進(jìn)入等待狀態(tài)(不是持續(xù)推送)
- 即使主庫沒有數(shù)據(jù)變化,主庫 dump 線程 也會(huì)根據(jù) master_heartbeat_period 發(fā)送一個(gè) Heartbeat log event 給 從庫 IO 線程,作為 binlog 的一部分傳輸,用來維持連接活躍、防止超時(shí)斷線。
- 主庫是怎么判斷從庫有沒有數(shù)據(jù)?
- 主庫不判斷!是從庫告訴主庫它需要從哪個(gè)位置開始同步!
MySQL 支持三種 binlog 格式(也就是傳輸給從庫的數(shù)據(jù)格式)
STATEMENT (不推薦,有風(fēng)險(xiǎn))
- 最早期的方式,記錄執(zhí)行的原始 SQL 語句
- 優(yōu)點(diǎn):可讀(看得懂)、日志體積小、性能開銷小
- 缺點(diǎn):有副作用可能不一致(如 UUID、now())
ROW(依舊是邏輯日志)
- 不記錄 SQL,而是記錄每一行數(shù)據(jù)的變更
對(duì)比redolog
- redolog:表空間X,頁號(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)確,幾乎無副作用問題
- 缺點(diǎn):日志體積大、不可讀(二進(jìn)制)、性能開銷大(行變更多則更慢)
MIXED
- 自動(dòng)在 STATEMENT 和 ROW 之間切換,MySQL 自行判斷
主從復(fù)制數(shù)據(jù)的模式(重點(diǎn))
相信大家看有的博客說Mysql主從模式三種或有四種模式的,錯(cuò)大錯(cuò)特錯(cuò),其實(shí)就兩種模式,其他兩種是基于第二個(gè)模式配置出來的,下面給大家具體介紹一下:
異步復(fù)制(默認(rèn))
- 客戶端發(fā)送請(qǐng)求先寫入主庫并返回客戶端,然后再異步同步給從庫
- 優(yōu)點(diǎn):返回給客戶端快,不會(huì)因?yàn)橥綇膸鞄碜枞?/li>
- 缺點(diǎn):主從數(shù)據(jù)不一致的風(fēng)險(xiǎn)
半同步模式(推薦)
- 在異步同步的基礎(chǔ)上等待從庫返回結(jié)果再返回給客戶端
- 優(yōu)點(diǎn):極大的保證了主庫和從庫的數(shù)據(jù)一致性
- 缺點(diǎn):對(duì)客戶端的阻塞帶來影響
內(nèi)部細(xì)節(jié)
- 如果從庫相應(yīng)時(shí)間過長(zhǎng)默認(rèn)10秒,會(huì)切換為異步同步模式
同時(shí)為了避免網(wǎng)絡(luò)延遲造成主庫長(zhǎng)時(shí)間收不到從庫的ACK,因此在配置半同步式復(fù)制時(shí),會(huì)有一個(gè)rpl_semi_sync_master_timeout參數(shù)來控制超時(shí)時(shí)間,其默認(rèn)值是10000ms/10s,如若主庫在10s內(nèi)依舊未收到從庫的ACK,則會(huì)將復(fù)制模式切換成異步模式,切成異步模式后,會(huì)在后續(xù)網(wǎng)絡(luò)正常后再次切回半同步模式。
- 對(duì)于多個(gè)從庫節(jié)點(diǎn)可以配置有多少個(gè)從庫返回就給客戶端響應(yīng)
5.7版本后對(duì)主從一致性保障策略
AFTER_SYNC(默認(rèn),增強(qiáng)半同步復(fù)制)【其他博客的第三種模式】
當(dāng)主庫未收到從庫的ACK之前,也不會(huì)在主庫上提交事務(wù),也就是保證了主從節(jié)點(diǎn)的數(shù)據(jù)強(qiáng)一致性,解決了after-commit中存在的問題。
AFTER_COMMIT(傳統(tǒng)半同步復(fù)制,可能出現(xiàn)數(shù)據(jù)不一致)
- 主庫在未收到從庫的ACK之前,雖然不會(huì)給客戶端返回寫入成功,但本質(zhì)上在MySQL中會(huì)提交事務(wù),也就是主庫中的其他事務(wù)是可以看見對(duì)應(yīng)數(shù)據(jù)的,當(dāng)此時(shí)出現(xiàn)宕機(jī)時(shí),就會(huì)導(dǎo)致舊主上能查詢出的數(shù)據(jù),在新主(原本的從庫)上無法查詢出來了。
- 兩者之間的區(qū)別就在于:對(duì)主從節(jié)點(diǎn)的數(shù)據(jù)嚴(yán)格性不同,一般情況下,無損復(fù)制會(huì)比傳統(tǒng)半同步復(fù)制開銷更大一些,因?yàn)槭聞?wù)遲遲不提交,會(huì)導(dǎo)致對(duì)應(yīng)的鎖資源不會(huì)主動(dòng)釋放,其他需要獲取對(duì)應(yīng)鎖資源的事務(wù)只能阻塞等待,這會(huì)造成主庫的整體性能出現(xiàn)一定影響。
同步復(fù)制(本身不支持,需通過半同步復(fù)制設(shè)置為等待所有從庫)【其他博客中第四種模式】
- 對(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ì)于從庫的一些優(yōu)化/策略
- 從庫的執(zhí)行策略
延遲復(fù)制
延遲復(fù)制通常用于一些特殊場(chǎng)景,它可以支持從庫數(shù)據(jù)的延遲同步,也就是當(dāng)從庫上的I/O線程,將主庫的Bin-log日志請(qǐng)求回來后,從節(jié)點(diǎn)的SQL線程并不會(huì)立刻解析日志執(zhí)行,而是等待一段時(shí)間后再解析日志執(zhí)行,這個(gè)等待的時(shí)間可以由開發(fā)者來配置,一般建議設(shè)為3~6小時(shí)之間。
那延遲復(fù)制的好處在于什么呢?
可以防止誤刪操作,如若在主庫上不小心誤刪了大量數(shù)據(jù)、表、庫或其他數(shù)據(jù)庫對(duì)象,因?yàn)閺膸觳⒉皇橇⒓磮?zhí)行同步過去的記錄,因此可以及時(shí)通過從節(jié)點(diǎn)上的數(shù)據(jù)回滾數(shù)據(jù)。除此之外,也能對(duì)一些線上Bug進(jìn)行實(shí)時(shí)觀測(cè),比如一個(gè)無法復(fù)現(xiàn)的故障問題發(fā)生時(shí),如果發(fā)現(xiàn)時(shí)還在配置的延遲復(fù)制時(shí)間內(nèi),則可以去到從庫上觀察。
- 從庫的優(yōu)化手段并行復(fù)制(mysql8.0更完善)
GTID復(fù)制(為什么要先說GTID,因?yàn)椴⑿袕?fù)制是基于組復(fù)制,而組復(fù)制是基于GTID)
- 在傳統(tǒng)的主從架構(gòu)中,當(dāng)需要發(fā)生主從切換時(shí),需要開發(fā)/運(yùn)維人員手動(dòng)找到Bin-log的POS同步點(diǎn),然后執(zhí)行change master to [new-master-pos]命令,將其他從節(jié)點(diǎn)指向新主庫,但每個(gè)從節(jié)點(diǎn)可能同步數(shù)據(jù)的進(jìn)度都不一致,因此每個(gè)從節(jié)點(diǎn)都需要去找到它上次的POS點(diǎn),然后指向新主庫,這個(gè)工作是不是聽起來就比較繁雜?答案是Yes,不過到了MySQL5.6版本后,開啟了GTID復(fù)制后,則無需手動(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ī)制》中聊過的事務(wù)ID嘛?MySQL會(huì)對(duì)每一個(gè)寫事務(wù)都分配一個(gè)順序遞增的值作為事務(wù)ID,而GTID則是由這兩玩意兒組成的,格式為server_uuid:trx_id。
- 當(dāng)主庫的事務(wù)有了這個(gè)全局事務(wù)標(biāo)識(shí)后,再發(fā)生主從切換時(shí)就無需手動(dòng)尋點(diǎn)了,僅需要執(zhí)行change master to master_auto_position = 1這條命令即可,它會(huì)自動(dòng)去新主庫上尋找數(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),但此刻問題就來了:原本slave2、slave3的POS同步點(diǎn)是基于master中的日志而言的,但現(xiàn)在主節(jié)點(diǎn)變成了slave1,這時(shí)slave2、slave3如何去尋找自己在slave1中的POS點(diǎn)呢?顯然MySQL無法自己完成該工作,因此需要人工指定同步點(diǎn)才行。
而GTID出現(xiàn)的原因,就是為了解決上述這個(gè)問題,但具體怎么解決的呢?
GTID的工作過程
master在更新數(shù)據(jù)時(shí),會(huì)為每一個(gè)寫事務(wù)分配一個(gè)全局的GTID,并記錄到Bin-log中。
slave節(jié)點(diǎn)的I/O線程拉取數(shù)據(jù)時(shí),會(huì)將讀到的記錄寫到relay-log中,并設(shè)置gtid_next值。
slave節(jié)點(diǎn)的SQL線程執(zhí)行前,會(huì)讀取gtid_next值得知接下來該解析哪條日志并執(zhí)行。
slave節(jié)點(diǎn)的SQL線程在執(zhí)行時(shí),會(huì)先比對(duì)自身的Bin-log日志中是否有對(duì)應(yīng)的GTID:
- 有:意味著該GTID對(duì)應(yīng)的事務(wù)已經(jīng)執(zhí)行過了,slave會(huì)自動(dòng)忽略掉這條記錄。
- 沒有:SQL解析該GTID對(duì)應(yīng)的relay-log記錄并執(zhí)行,再將GTID記錄到Bin-log。
GTID自動(dòng)尋找同步點(diǎn)的原理
- 開啟GTID后,從庫會(huì)基于它來復(fù)制主庫的數(shù)據(jù),此時(shí)發(fā)生了主從切換,假設(shè)這時(shí)主從集群中有多個(gè)從節(jié)點(diǎn),MySQL首先會(huì)選擇距離master的GTID最近的從節(jié)點(diǎn)作為新主,然后將其他從節(jié)點(diǎn)轉(zhuǎn)變?yōu)樾轮鞯膹膸?,其他從庫?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)。
- 不過由于GTID復(fù)制是基于事務(wù)來實(shí)現(xiàn)的,這也就代表不支持事務(wù)的存儲(chǔ)引擎無法使用這種機(jī)制,在之前的章節(jié)中也聊過,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通過逗號(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ù)來處理相關(guān)工作,其函數(shù)執(zhí)行的邏輯流程圖如下:
當(dāng)一個(gè)事務(wù)提交時(shí)都會(huì)調(diào)用ordered_commit函數(shù),首先會(huì)將事務(wù)加入等待事務(wù)組,接著會(huì)經(jīng)過三個(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)來完成。
- ③如上圖中的「事務(wù)1」則是隊(duì)長(zhǎng),后續(xù)的都是隊(duì)員,但隊(duì)長(zhǎng)不會(huì)無限制等待隊(duì)員到來:
從隊(duì)長(zhǎng)加入的時(shí)間點(diǎn)開始,當(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ù)之間通過,逗號(hào)分隔(實(shí)際過程更為復(fù)雜,這里只做簡(jiǎn)單講解)。
并行復(fù)制
在MySQL5.6之前的版本中,從庫同步數(shù)據(jù)時(shí),所有數(shù)據(jù)同步工作都是基于單線程完成的,也就是不管主庫上的數(shù)據(jù)是不是多線程并發(fā)寫入的,從庫上只會(huì)有一條SQL線程來執(zhí)行解析執(zhí)行工作。
到了MySQL5.6之后,引入了并行復(fù)制的思想,但5.6中的并行復(fù)制極其雞肋,基本無人問津,因?yàn)槭腔趲旒?jí)別的并行復(fù)制,也就是一個(gè)從節(jié)點(diǎn)對(duì)應(yīng)多個(gè)主節(jié)點(diǎn)時(shí),有幾個(gè)主節(jié)點(diǎn)就開幾條SQL線程去解析并寫入數(shù)據(jù),即多主一從架構(gòu)中才會(huì)用到。
因?yàn)楣俜阶畛踉趯?shí)現(xiàn)并行復(fù)制時(shí),一直糾結(jié)鎖沖突的問題,所以為了防止并行執(zhí)行時(shí)出現(xiàn)數(shù)據(jù)沖突,就造出了上面那種庫級(jí)別的并行復(fù)制,為啥要糾結(jié)鎖/數(shù)據(jù)沖突呢?
比如從庫I/O線程在主庫中請(qǐng)求了100條記錄回去,從庫中開100條SQL線程解析并執(zhí)行這些記錄,如果其中有兩條記錄操作的是同一條數(shù)據(jù),就會(huì)出現(xiàn)鎖沖突問題。
- 但上述原因不是最主要的,最主要的是并發(fā)執(zhí)行的順序問題,如果主庫上對(duì)于一條數(shù)據(jù)是先改后刪,從庫在并發(fā)執(zhí)行時(shí),因?yàn)槎嗑€程執(zhí)行的無序性,把執(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ì)是不存在鎖沖突的,所以可以開啟多條線程同時(shí)執(zhí)行一個(gè)組中不同的事務(wù),但這個(gè)思想是從MariaDB中照抄過來的~
一句話來總結(jié)就是:主庫上是咋樣并發(fā)寫入數(shù)據(jù)的,從庫也會(huì)開啟對(duì)應(yīng)的線程數(shù)去并發(fā)寫入。
在5.7中官方為這種機(jī)制命名為enhanced multi-threaded slave,簡(jiǎn)稱MTS機(jī)制,同時(shí)為了兼容5.6版本中的并行復(fù)制,又多加入了一個(gè)slave-parallel-type參數(shù):
- DATABASE:默認(rèn)的并行復(fù)制模式,表示基于庫級(jí)別的來完成并行復(fù)制。
- LOGICAL_CLOCK:表示基于組提交的方式來完成并行復(fù)制。
并行復(fù)制出現(xiàn)的意義是什么?
能夠在很大程度上提升從庫復(fù)制數(shù)據(jù)的速度,也就是能夠讓從庫的數(shù)據(jù)實(shí)時(shí)性提升,尤其是無損復(fù)制模式中,主節(jié)點(diǎn)需要等待從節(jié)點(diǎn)的ACK才會(huì)真正提交事務(wù),從庫使用并行復(fù)制后,能夠在一定程度上解決從庫的復(fù)制延遲問題。
不過雖然5.7中的并行復(fù)制,在一定程度上解決了原有的從庫延遲問題,但如果一個(gè)新的從節(jié)點(diǎn)加入集群時(shí),因?yàn)橐獜念^開始同步數(shù)據(jù),這種并行復(fù)制的模式依舊存在效率問題,而到了MySQL8.0中,對(duì)于并行復(fù)制技術(shù)提出了真正的解決之道,也就是基于writeset的MTS技術(shù)。
主從數(shù)據(jù)一致性的解決方案
讀寫分離數(shù)據(jù)一致性場(chǎng)景:一個(gè)用戶將個(gè)人信息修改后,然后再次查看時(shí),發(fā)現(xiàn)個(gè)人信息依舊是修改之前的原數(shù)據(jù),這時(shí)用戶就有可能再次修改,經(jīng)過反反復(fù)復(fù)多次修改后,用戶發(fā)現(xiàn)依舊未生效
想要解決上述這種讀寫分離導(dǎo)致的數(shù)據(jù)不一致性,主要有四種解決方案:
業(yè)務(wù)邏輯做改變、復(fù)制方式做更改、數(shù)據(jù)庫架構(gòu)做調(diào)整、引入第三方中間件。
改變業(yè)務(wù)邏輯
- 對(duì)業(yè)務(wù)做一定更改,比如當(dāng)用戶立即修改數(shù)據(jù)后,因?yàn)樵趶膸熳x不到數(shù)據(jù),所以先顯示一個(gè)審核狀態(tài),這樣能夠給出用戶的反饋,從而避免用戶再次重復(fù)操作
- 這種方式屬于和數(shù)據(jù)不一致妥協(xié)的方案,接受一定的數(shù)據(jù)延遲,不過這種方式并不適用于一些對(duì)數(shù)據(jù)實(shí)時(shí)性要求較高的場(chǎng)景
更改復(fù)制方式
- 在之前曾聊過MySQL四種數(shù)據(jù)同步復(fù)制的方式,即全同步、異步、半同步與無損復(fù)制,MySQL默認(rèn)會(huì)是異步復(fù)制模式,即主節(jié)點(diǎn)寫入數(shù)據(jù)后會(huì)立即返回成功的狀態(tài)給客戶端,這樣能夠確保性能達(dá)到最佳,但如果對(duì)實(shí)時(shí)性要求較高,可以將其改為全同步或半同步模式。
調(diào)整數(shù)據(jù)庫架構(gòu)
- 如果無法接受主從架構(gòu)帶來的短期數(shù)據(jù)不一致,那可以升級(jí)服務(wù)器硬件,并將架構(gòu)恢復(fù)成單庫架構(gòu),所有讀寫操作都走單庫完成,這就自然不會(huì)出現(xiàn)數(shù)據(jù)不一致問題。
- 但如果升級(jí)硬件配置后,無法承載客戶端的訪問壓力時(shí),可將整體架構(gòu)升級(jí)到分庫分表架構(gòu),制定好合適的分片策略和路由鍵,每次讀寫數(shù)據(jù)都根據(jù)業(yè)務(wù)不同,操作不同的庫。
引入第三方中間件
- 前面聊到的三種方案,多多少少都存在一些局限性,因?yàn)橐唇邮軘?shù)據(jù)不一致、要么損失性能、要么使用更高規(guī)模的架構(gòu)處理,但這些方案似乎都存在令人不能接受的后患,那有沒有一種萬全之策來解決這個(gè)問題呢?答案是有的,就是引入Canal中間件來監(jiān)控主節(jié)點(diǎn)的Bin-log日志。
- 在之前講主從同步數(shù)據(jù)原理時(shí),曾講到過,主節(jié)點(diǎn)上存在一個(gè)log dump線程會(huì)監(jiān)聽Bin-log日志,當(dāng)日志出現(xiàn)變更時(shí)會(huì)通知從節(jié)點(diǎn)來拉取數(shù)據(jù),而Canal的思想也是一樣的,會(huì)監(jiān)控主節(jié)點(diǎn)的Bin-log日志,當(dāng)發(fā)生變更時(shí),就直接去拉取數(shù)據(jù),然后直接推送給從節(jié)點(diǎn)寫入。
- 但這種方式也無法做到真正的數(shù)據(jù)實(shí)時(shí)性,畢竟Canal監(jiān)聽變更、拉取數(shù)據(jù)、推送數(shù)據(jù)都需要時(shí)間,這部分的時(shí)間開銷必然存在,只是它會(huì)比從庫去主庫上拉取,速度會(huì)更快一些罷了。
- 一般企業(yè)內(nèi)部都會(huì)引入Canal來解決數(shù)據(jù)不一致問題,因?yàn)樗粌H僅只能解決主從延遲問題,還能解決MySQL-ES、MySQL-Redis.....等多種數(shù)據(jù)不一致的場(chǎng)景
- 也可以制定某些敏感數(shù)據(jù)走主庫查詢,這樣能夠確保數(shù)據(jù)的實(shí)時(shí)性,但容易模糊讀寫分離的界限,不過因?yàn)椴恍枰腩~外的技術(shù),所以在某些情況下也是個(gè)不錯(cuò)的方案。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
簡(jiǎn)單聊一聊SQL中的union和union?all
在寫SQL的時(shí)候,偶爾會(huì)用到兩個(gè)表的數(shù)據(jù)結(jié)合在一起返回的,就需要用到UNION 和 UNION ALL,這篇文章主要給大家介紹了關(guān)于SQL中union和union?all的相關(guān)資料,需要的朋友可以參考下2023-02-02Centos 6.4源碼安裝mysql-5.6.28.tar.gz教程
這篇文章主要為大家詳細(xì)介紹了Centos 6.4源碼安裝mysql-5.6.28.tar.gz教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01mysql中ALTER AGGREGATE使用場(chǎng)景小結(jié)
ALTER AGGREGATE?是 SQL 中用于修改已定義聚合函數(shù)的語法,本文主要介紹了mysql中ALTER AGGREGATE使用場(chǎng)景小結(jié),具有一定的的參考價(jià)值,感興趣的可以了解一下2025-05-05MySQL數(shù)據(jù)庫手冊(cè)DATABASE操作與編碼(小白入門篇)
這篇文章主要介紹了MySQL數(shù)據(jù)庫手冊(cè)DATABASE操作與編碼的小白入門篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05MySQL查詢in操作 查詢結(jié)果按in集合順序顯示
MySQL 查詢in操作,查詢結(jié)果按in集合順序顯示的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-12-12