1刹帕、MVCC
- 簡單講講你對 MVCC 的理解。
MVCC在MySQL InnoDB中的實(shí)現(xiàn)主要是為了提高數(shù)據(jù)庫并發(fā)性能谎替,用更好的方式去處理讀-寫沖突偷溺,做到即使有讀寫沖突時(shí),也能做到不加鎖钱贯,做到非阻塞并發(fā)讀挫掏。
- MVCC多版本并發(fā)控制的原理
通過undo_log多版本鏈條,加上開啟事務(wù)時(shí)產(chǎn)生的readView(不同隔離級(jí)別有不同產(chǎn)生策略),然后再有一個(gè)查詢的時(shí)候,根據(jù)readView進(jìn)行判斷的機(jī)制秩命,來決定讀取哪個(gè)版本的數(shù)據(jù)尉共。實(shí)現(xiàn)了多事務(wù)并發(fā)執(zhí)行,保證只能讀開啟事務(wù)前提交的數(shù)據(jù)和當(dāng)前事務(wù)修改的數(shù)據(jù)弃锐,其他情況都不會(huì)讀到袄友。
也就是說,不管事務(wù)執(zhí)行多長時(shí)間霹菊,事務(wù)內(nèi)部看到的數(shù)據(jù)是不受其它事務(wù)影響的剧蚣,根據(jù)事務(wù)開始的時(shí)間不同,不同事務(wù)對同一張表浇辜,同一時(shí)刻看到的數(shù)據(jù)可能是不一樣的券敌。
MVCC實(shí)現(xiàn)
隱式字段
在表中,除了我們自定義的列柳洋,實(shí)際上MySQL會(huì)隱式的定義三個(gè)字段
DB_TRX_ID
:事務(wù)ID待诅,創(chuàng)建這條記錄/最后一次修改該記錄的事務(wù)IDDB_ROLL_PTR
:回滾指針,指向這條記錄的上一個(gè)版本DB_ROW_ID:隱含的自增ID(隱藏主鍵)熊镣,如果數(shù)據(jù)表沒有主鍵卑雁,InnoDB會(huì)自動(dòng)以
DB_ROW_ID`產(chǎn)生一個(gè)聚簇索引
undo_log 日志版本鏈
undo_log 版本鏈?zhǔn)侵敢恍袛?shù)據(jù)被多個(gè)事務(wù)依次修改過后募书,在每個(gè)事務(wù)修改完后,Mysql會(huì)保留修改前的數(shù)據(jù)undo回滾日志测蹲,并且用兩個(gè)隱藏字段trx_id和roll_pointer把這些undo日志串聯(lián)起來形成一個(gè)歷史記錄版本鏈
insert undo log:代表事務(wù)在insert新紀(jì)錄時(shí)產(chǎn)生的undo_log莹捡,只在事務(wù)回滾時(shí)需要,并且在事務(wù)提交后可以被立即拋棄扣甲。
update undo log:事務(wù)在update或者delete時(shí)產(chǎn)生的undo log篮赢,不僅在事務(wù)回滾時(shí)需要,在快照讀時(shí)也需要琉挖;所以不能隨便刪除启泣,只要在快速讀或者事務(wù)回滾不涉及該日志時(shí),對應(yīng)的日志才會(huì)被purge線程統(tǒng)一清除示辈。
Read View
Read View是事務(wù)進(jìn)行快照讀
操作時(shí)產(chǎn)生的讀視圖(RV),在該事務(wù)執(zhí)行快照讀的那一刻寥茫,會(huì)生成數(shù)據(jù)庫系統(tǒng)的當(dāng)前的一個(gè)快照,記錄并維護(hù)當(dāng)前活躍事務(wù)的ID
(當(dāng)每個(gè)事務(wù)開啟時(shí)矾麻,都會(huì)被分配一個(gè)ID纱耻,這個(gè)ID是自增的,所以最新的事務(wù)险耀,ID值越大)
RV主要是用來做可見行判斷的弄喘,即當(dāng)我們某個(gè)事務(wù)執(zhí)行快照讀的時(shí)候,對該記錄創(chuàng)建一個(gè)RV讀視圖胰耗,把它比作條件來判斷當(dāng)前事務(wù)能夠看到哪個(gè)版本的數(shù)據(jù)限次,既可能是當(dāng)前最新的數(shù)據(jù),也有可能是該行記錄的undo log里面的某個(gè)版本的數(shù)據(jù)柴灯。
RV遵循一個(gè)可見性算法卖漫,主要是將要被修改的數(shù)據(jù)的最新記錄的DB_TRX_ID(即當(dāng)前事務(wù)ID),與系統(tǒng)當(dāng)前其他活躍事務(wù)的ID去對比(由RV維護(hù)),如果DB_TRX_ID跟RV的屬性做了某些對比赠群,不符合可見性羊始,那么就由DB_ROLL_PTR回滾指針去取出undo log中的DB_TRX_ID再比較,即遍歷鏈表的DB_TRX_ID(從鏈表頭到尾查描,即從最近的一次修改查起)突委,直到找到滿足特定條件的DB_TRX_ID,那么這個(gè)DB_TRX_ID所在的舊記錄就是當(dāng)前事務(wù)能看見的最新老版本
實(shí)現(xiàn)流程
事務(wù)隔離級(jí)別與MVCC的關(guān)系
- REPEATABLE READ(可重復(fù)讀) REPEATABLE READ級(jí)別會(huì)使用MVCC冬三,只有在第一次進(jìn)行快照讀會(huì)生成read view匀油,之后的快照讀都會(huì)沿用第一次生成的read view,所以每次快照讀讀到的數(shù)據(jù)都是一樣的勾笆,這樣就可以解決臟讀問題以及快照讀的不可重復(fù)讀敌蚜、幻讀問題。
這就是上面說的窝爪,只能讀開啟事務(wù)前提交的數(shù)據(jù)和當(dāng)前事務(wù)修改的數(shù)據(jù)弛车,其他情況都不會(huì)讀到齐媒。
當(dāng)前讀與快照讀
- 當(dāng)前讀
像select lock in share mode(共享鎖); select for update, update,delete纷跛,insert(排它鎖)這些操作就是一種當(dāng)前讀喻括,因?yàn)樗x取的是數(shù)據(jù)的最新版本,讀取時(shí)還要保證其他事務(wù)不能修改當(dāng)前記錄贫奠,會(huì)對記錄進(jìn)行加鎖唬血。
- 快照讀
不加鎖的select就是快照讀,即不加鎖的非阻塞讀叮阅;(快照讀的前提是隔離級(jí)別不是串行化刁品,串行化的隔離級(jí)別下快照讀會(huì)退化成當(dāng)前讀) 之所以出現(xiàn)快照讀的情況,是基于提高并發(fā)性能的考慮浩姥,快照讀的實(shí)現(xiàn)是基于多版本并發(fā)控制,即MVCC状您,可以認(rèn)為MVCC是行鎖的一個(gè)變種勒叠,但是它在很多情況下避免了加鎖操作,降低了開銷膏孟,既然是基于多版本眯分,所以快照讀可能讀到的不一定是數(shù)據(jù)的最新版本,而有可能是之前的歷史版本
2柒桑、Mysql主從復(fù)制三大模式
sync :全同步
當(dāng)主庫執(zhí)行完一個(gè)事務(wù)弊决,所有的從庫都執(zhí)行了該事務(wù)才會(huì)將結(jié)果返回給客戶端。這樣保證了數(shù)據(jù)的安全性魁淳,但是因?yàn)樾枰却袕膸靾?zhí)行完該事務(wù)才能返回客戶端結(jié)果飘诗,所以全同步復(fù)制的性能必然會(huì)受到很大的影響。
對于全同步復(fù)制而言界逛,當(dāng)主庫提交一個(gè)事務(wù)后昆稿,要求所有從庫節(jié)點(diǎn)必須收到,執(zhí)行并提交這些事務(wù)息拜,然后主庫線程才能繼續(xù)做后續(xù)操作溉潭,而因此帶來的問題就是主庫完成一個(gè)事務(wù)的時(shí)間被大幅度拉長,性能降低少欺。
async : 異步
主庫在執(zhí)行完客戶端提交的事務(wù)后會(huì)立刻將執(zhí)行結(jié)果返回給客戶端喳瓣,并不關(guān)心從庫是否已經(jīng)接收處理,這樣帶來的問題就是當(dāng)主死掉了赞别,此時(shí)主上提交的事務(wù)可能還沒有傳到從上畏陕。而強(qiáng)行將從提升為主就會(huì)導(dǎo)致新主上的數(shù)據(jù)不完整。
semi-sync : 半同步
介于異步復(fù)制和全同步復(fù)制之間氯庆,主庫在執(zhí)行完客戶端提交的事務(wù)后不是立刻返回給客戶端蹭秋,而是等待至少一個(gè)從庫接收并寫到relay log中才返回給客戶端扰付。相對于異步復(fù)制,半同步復(fù)制提高了數(shù)據(jù)的安全性仁讨,同時(shí)也會(huì)造成一定程度的延遲羽莺,這個(gè)延遲為一個(gè)TCP/IP往返的時(shí)間。所以半同步復(fù)制需要在低延時(shí)的網(wǎng)絡(luò)中使用洞豁。
對于半同步復(fù)制而言盐固,是介于同步復(fù)制和異步復(fù)制之間的一種,主庫需要等待至少一個(gè)從庫節(jié)點(diǎn)收到并且刷新binlog到relay日志中丈挟,主庫不需要等待所有從庫給主庫反饋刁卜,同時(shí)這里只是收到反饋而不死和完全執(zhí)行并且提交事務(wù)的反饋,這樣會(huì)節(jié)省很多的時(shí)間曙咽。
總結(jié):實(shí)際業(yè)務(wù)中蛔趴,一般都是配置使用半同步的,全同步高并發(fā)下有性能問題例朱,異步有數(shù)據(jù)丟失的可能孝情,所以,還是使用半同步洒嗤。