MySQL 復制原理詳解[轉載]

轉載:https://cloud.tencent.com/developer/article/1005270

導語

mysql作為一個開源的數據庫慌植,有著廣泛的應用甚牲。本文主要講述了mysql復制的原理,以及異步復制涤浇,同步復制和并行復制。

1魔慷、mysql復制的原理

Mysql有兩種復制原理:基于行的復制和基于語句的復制只锭。最早出現的是基于語句的復制,而基于行的復制方式在5.1版本中才被引入院尔。這兩種方式都是通過在主庫上記錄二進制日志(binlog)蜻展、在備庫上重放日志的方式來實現異步的數據復制。這意味著邀摆、在同一時間點備庫上的數據可能和主庫不一致纵顾,并且無法保證主庫備庫之間的延遲。

1.1 栋盹、基于語句的復制

基于語句的復制模式下施逾,主庫會記錄那些造成數據更改的查詢,當備庫讀取并重放這些事件時,實際上只把主庫上執(zhí)行過的SQL再執(zhí)行一遍汉额。

優(yōu)點:

最明顯的好處是實現相當簡單曹仗。理論上講,簡單地記錄和執(zhí)行這些語句蠕搜,能夠讓備庫保持同步怎茫。另外好處是binlog日志里的事件更加緊湊,所以相對而言妓灌,基于語句的模式不會使用太多帶寬轨蛤。一條更新好幾兆數據的語句在二進制日志里可能只占用幾十字節(jié)。

缺點:

有些數據更新語句虫埂,可能依賴其他因素祥山。例如,同一條sql在主庫和備庫上執(zhí)行的時間可能稍微或很不相同告丢,因此在傳輸的binlog日志中枪蘑,除了查詢語句,還包括一些元數據信息岖免,如當前的時間戳岳颇。即便如此,還存在著一些無法被正確復制的SQL颅湘,例如话侧,使用CURRENT_USER()函數語句。存儲過程和觸發(fā)器在使用基于語句的復制模式時也可能存在問題闯参。另外一個問題是更新必須是串行的瞻鹏。這需要更多的鎖。并且不是所有的存儲引擎都支持這種復制模式鹿寨。

1.2新博、基于行的復制

MySQL5.1開始支持基于行的復制,這種方式會將實際數據記錄在二進制日志中脚草,跟其他數據庫的實現比較相像赫悄。

優(yōu)點:

最大的好處是可以正確的復制每一行,一些語句可以唄更加有效地復制馏慨。由于無需重放更新主庫數據的查詢埂淮,使用基于行的復制模式能夠更高效地復制數據。重放一些查詢的代價會很高写隶。例如倔撞,下面有一個查詢將數據從一個大表中匯總到小表

<pre class="prism-token token language-javascript">mysql> INSERT INTO summary_table(col1,col2,sum_col3)

     ->SELECT col1,col2,sum(col3) from enormous_table GROUP BY col1,col2;

</pre>

缺點:

但是另外一方面,下面這條語句使用基于語句的復制方式代價會小很多:

<pre class="prism-token token language-javascript">mysql> UPDATE enormous_table SET col1 =0 ;
</pre>

由于這條語句做了全表更行慕趴,使用基于行的復制開銷會大很多痪蝇,因為每一行的數據都會唄記錄到二進制日志中鄙陡,這使得二進制日志時間非常龐大。另外由于語句并沒有在日志里記錄霹俺,因此無法判斷執(zhí)行了哪些sql,除了需要知道行的變化外柔吼,這在很多情況下很重要。執(zhí)行基于行的過程像一個黑盒子丙唧,你無法知道服務器正在做什么愈魏。

由于沒有哪一種模式對所有情況都是完善的莹规,mysql能夠在這兩種復制模式間動態(tài)切換歌馍。默認情況下使用的是基于語句的復制方式棉饶,但如果發(fā)現語句無法唄正確地復制专甩,就切換基于行的復制模式五续。還可以根據需要來設置會話級別的變量binlog_format,控制二進制日志格式坠宴。

2蒋歌、異步復制過程

總體來說歧蕉,復制有3個步驟:

1侧甫、主服務器把數據更改記錄到二進制日志中珊佣。(這叫做二進制日志事件)

2、從服務器把主服務器的二進制日志拷貝到自己的中繼日志中披粟。

3咒锻、從服務器重放中繼日志中的事件,把更改應用到自己的數據上守屉。

這只是概述惑艇,每一個步驟都很復雜。下圖更清晰描述了復制的過程拇泛。

image

第一步滨巴、在主服務器上記錄二進制日志。在每個更新數據的事務完成之前俺叭,主服務器都會將數據更改記錄到二進制日志中恭取。即使事務在執(zhí)行期間是交錯的,mysql也會串行地將事務寫入到二進制日志中熄守。在把事件寫入二進制日志之后蜈垮,主服務器告訴存儲引擎提交事務。

第二步柠横、從服務器把主服務器的二進制日志拷貝到自己的硬盤上窃款,進入所謂的“中繼日志”中课兄。首先牍氛,它啟動一個工作線程,叫I/O線程烟阐,這個I/O線程開啟一個普通的客戶端連接搬俊,然后啟動一個特殊的二進制日志轉儲進程(它沒有相應的SQL命令)紊扬。這個轉儲進程從主服務器的二進制日志中讀取數據。它不會對事件進行輪詢唉擂。如果3跟上了主服務器餐屎,就會進入休眠狀態(tài)并等待有新的事件發(fā)生時主服務器發(fā)出的信號。I/O線程把數據寫入從服務器的中繼日志中玩祟。

第三步腹缩、SQL線程讀取中繼日志,并且重放其中的事件空扎,然后更新從服務器的數據藏鹊。由于這個線程能跟上I/O線程,中繼日志通常在操作系統(tǒng)的緩存中转锈,所以中繼日志的開銷很低盘寡。SQL線程執(zhí)行事件也可以被寫入從服務器自己的二進制日志中,它對于有些場景很實用撮慨。

3竿痰、半同步復制

一般情況下,異步復制就已經足夠應付了砌溺,但由于是異步復制影涉,備庫極有可能是落后于主庫,特別是極端情況下抚吠,我們無法保證主備數據是嚴格一致的常潮。比如,當用戶發(fā)起commit命令時楷力,Master并不關心Slave的執(zhí)行狀態(tài)喊式,執(zhí)行成功后,立即返回給用戶萧朝。試想下岔留,若一個事務提交后,Master成功返回給用戶后crash检柬,這個事務的binlog還沒來得及傳遞到Slave献联,那么Slave相對于Master而言就少了一個事務,此時主備就不一致了何址。對于要求強一致的業(yè)務是不可以接受的里逆,半同步復制就是為了解決數據一致性而產生的。

為什么叫半同步復制用爪?先說說同步復制原押,所謂同步復制就是一個事務在Master和Slave都執(zhí)行后,才返回給用戶執(zhí)行成功偎血。這里核心是說Master和Slave要么都執(zhí)行诸衔,要么都不執(zhí)行盯漂,涉及到2PC(2 Phrase Commit)。而MySQL只實現了本地redo-log和binlog的2PC笨农,但并沒有實現Master和Slave的2PC就缆,所以不是嚴格意義上的同步復制。而MySQL半同步復制不要求Slave執(zhí)行谒亦,而僅僅是接收到日志后竭宰,就通知Master可以返回了。這里關鍵點是Slave接受日志后是否執(zhí)行份招,若執(zhí)行后才通知Master則是同步復制羞延,若僅僅是接受日志成功,則是半同步復制脾还。對于Mysql而言伴箩,我們談到的日志都是binlog,對于其他的關系型數據庫可能是redo log或其他日志鄙漏。

半同步復制如何實現嗤谚?半同步復制實現的關鍵點是Master對于事務提交過程特殊處理。目前實現半同步復制主要有兩種模式怔蚌,AFTER_SYNC模式和AFTER_COMMIT模式巩步。兩種方式的主要區(qū)別在于是否在存儲引擎提交后等待Slave的ACK。先來看看AFTER_COMMIT模式桦踊,如下圖椅野,Start和End分別表示用戶發(fā)起Commit命令和Master返回給用戶的時間點,中間部分就是整個Commit過程Master和Slave做的事情籍胯。

image

Master提交時竟闪,會首先將該事務的redo log刷入磁盤,然后將事務的binlog刷入磁盤(這里其實還涉及到兩階段提交的問題杖狼,這里不展開講)炼蛤,然后進入innodb commit流程,這個步驟主要是釋放鎖蝶涩,標記事務為提交狀態(tài)(其他用戶可以看到該事務的更新)理朋,這個過程完成后,等待Slave發(fā)送的ACK消息绿聘,等到Slave的響應后嗽上,Master才成功返回給用戶∠ㄈ粒看到圖中紅色虛線部分兽愤,這段是Master和Slave的同步邏輯,是Master-Slave一致性的保證。

半同步復制是否能保證不丟數據烹看?我們通過幾種場景來簡單分析下。第一種情況:假設Master第1洛史,2步執(zhí)行成功后惯殊,binlog還沒來得及傳遞給Slave,此時Master掛了也殖,Slave作為新Master提供服務土思,那么備庫比主庫要少一個事務(因為主庫的redo 和binlog已經落盤),但是不影響用戶忆嗜,對于用戶而言己儒,這個事務沒有成功返回,那么提交與否捆毫,用戶都可以接受闪湾,用戶一定會進行異常捕獲而重試。第二種情況绩卤,假設第3步innodb commit執(zhí)行成功后途样,binlog還沒來得及傳遞給Slave,此時Master掛了濒憋,此時與第一種情況一樣何暇,備庫比主庫少一個事務,但是其他用戶在3執(zhí)行完后凛驮,可以看到該事務的更新裆站,而切換到備庫后,卻發(fā)現再次讀這個更新又沒了黔夭,這個就發(fā)生了“幻讀”宏胯,如果其他事務依賴于這個更新,則會對業(yè)務邏輯產生影響本姥。當然這僅僅是極端情況胳嘲。

對于第二種情況產生的影響,AFTER_SYNC模式可以解決這一問題扣草。與AFTER_COMMIT相比了牛,master在AFTER_SYNC模式下,Fsync binlog后辰妙,就開始等待SLAVE同步鹰祸。那么在進行第5步innodbcommit后,即其它事務能看到該事務的更新時密浑,Slave已經成功接收到binlog蛙婴,即使發(fā)生切換,Slave擁有與Master同樣的數據尔破,不會發(fā)生“幻讀”現象街图。但是對于上面描述的第一種情況浇衬,結果是一樣的。

所以餐济,在極端情況下耘擂,半同步復制的Master-Slave會有一個事務不一致,但是對于用戶而言絮姆,由于這個事務并沒有成功返回給用戶醉冤,所以無論事務提交與否都是可以接受的,用戶有必要進行查詢或重試篙悯,判讀是否更新成功蚁阳。或者我們想想鸽照,對于單機而言螺捐,若事務執(zhí)行成功后,返回給用戶時矮燎,網絡斷了归粉,用戶也是面臨一樣的問題,所以漏峰,這不是半同步復制的問題糠悼。對于提交返回成功的事務,版同步復制保證Master-Slave一定是一致的浅乔,從這個角度來看倔喂,半同步復制不會丟數據,可以保證Master-Slave的強一致性靖苇。下圖是AFTER_SYNC模式席噩,事務提交過程。

image

4贤壁、并行復制

半同步復制解決了Master-Slave的強一致問題悼枢,那么性能問題呢?從圖1中可以看到參與復制的主要有兩個線程:IO線程和SQL線程脾拆,分別用于拉取和回放binlog馒索。對于Slave而言,所有拉取和解析binlog的動作都是串行的名船,相對于Master并發(fā)處理用戶請求绰上,在高負載下, 若Master產生binlog的速度超過Slave消費binlog的速度渠驼,導致Slave出現延遲蜈块。如下圖,可以看到,Users和Master之間的管道遠遠大于Master和Slave之間的管道百揭。

image

那么如何并行化爽哎,并行IO線程,還是并行SQL線程器一?其實兩方面都可以并行课锌,但是并行SQL線程的收益更大,因為SQL線程做的事情更多(解析盹舞,執(zhí)行)。并行IO線程隘庄,可以將從Master拉取和寫Relay log分為兩個線程踢步;并行SQL線程則可以根據需要做到庫級并行,表級并行丑掺,事務級并行获印。庫級并行在mysql官方版本5.6已經實現。如下圖街州,并行復制框架實際包含了一個協(xié)調線程和若干個工作線程兼丰,協(xié)調線程負責分發(fā)和解決沖突,工作線程只負責執(zhí)行唆缴。圖中鳍征,DB1,DB2和DB3的事務就可以并發(fā)執(zhí)行面徽,提高了復制的性能艳丛。有時候庫級并發(fā)可能不夠,需要做表級并發(fā)趟紊,或更細粒度的事務級并發(fā)氮双。

image

并行復制如何處理沖突?并發(fā)的世界是美好的霎匈,但不能亂并發(fā)戴差,否則數據就亂了。Master上面通過鎖機制來保證并發(fā)的事務有序進行铛嘱,那么并行復制呢暖释?Slave必需保證回放的順序與Master上事務執(zhí)行順序一致,因此只要做到順序讀取binlog墨吓,將不沖突的事務并發(fā)執(zhí)行即可饭入。對于庫級并發(fā)而言,協(xié)調線程要保證執(zhí)行同一個庫的事務放在一個工作線程串行執(zhí)行肛真;對于表級并發(fā)而言谐丢,協(xié)調線程要保證同一個表的事務串行執(zhí)行;對于事務級而言,則是保證操作同一行的事務串行執(zhí)行乾忱。

是否粒度越細讥珍,性能越好?這個并不是一定的窄瘟。相對于串行復制而言衷佃,并行復制多了一個協(xié)調線程。協(xié)調線程一個重要作用是解決沖突蹄葱,粒度越細的并發(fā)氏义,可能會有更多的沖突,最終可能也是串行執(zhí)行的图云,但消耗了大量的沖突檢測代價惯悠。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市竣况,隨后出現的幾起案子克婶,更是在濱河造成了極大的恐慌,老刑警劉巖丹泉,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件情萤,死亡現場離奇詭異,居然都是意外死亡摹恨,警方通過查閱死者的電腦和手機筋岛,發(fā)現死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晒哄,“玉大人泉蝌,你說我怎么就攤上這事】纾” “怎么了勋陪?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長硫兰。 經常有香客問我诅愚,道長,這世上最難降的妖魔是什么劫映? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任违孝,我火速辦了婚禮,結果婚禮上泳赋,老公的妹妹穿的比我還像新娘雌桑。我一直安慰自己,他們只是感情好祖今,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布校坑。 她就那樣靜靜地躺著拣技,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耍目。 梳的紋絲不亂的頭發(fā)上膏斤,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音邪驮,去河邊找鬼莫辨。 笑死,一個胖子當著我的面吹牛毅访,可吹牛的內容都是我干的沮榜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼喻粹,長吁一口氣:“原來是場噩夢啊……” “哼蟆融!你這毒婦竟也來了?” 一聲冷哼從身側響起磷斧,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤振愿,失蹤者是張志新(化名)和其女友劉穎捷犹,沒想到半個月后弛饭,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡萍歉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年侣颂,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枪孩。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡憔晒,死狀恐怖,靈堂內的尸體忽然破棺而出蔑舞,到底是詐尸還是另有隱情拒担,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布攻询,位于F島的核電站从撼,受9級特大地震影響,放射性物質發(fā)生泄漏钧栖。R本人自食惡果不足惜低零,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拯杠。 院中可真熱鬧掏婶,春花似錦、人聲如沸潭陪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茎芭,卻和暖如春揖膜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梅桩。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工壹粟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宿百。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓趁仙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親垦页。 傳聞我的和親對象是個殘疾皇子雀费,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容