摘要:也就是說(shuō)線程能夠獨(dú)立于線程之前工作。復(fù)制使用了三個(gè)線程。的日志線程,將事件寫(xiě)入,的線程獲取,并將其寫(xiě)入,線程重放日志。
1. 復(fù)制概述
MySQL 內(nèi)置的復(fù)制功能是構(gòu)建基于 MySQL 的大規(guī)模、高性能應(yīng)用的基礎(chǔ),復(fù)制解決的基本問(wèn)題是讓一臺(tái)服務(wù)器的數(shù)據(jù)與其他服務(wù)器保持同步。接下來(lái),我們將從復(fù)制概述及原理、復(fù)制的配置、常見(jiàn)的問(wèn)題及解決方法來(lái)學(xué)習(xí) MySQL 的復(fù)制功能。
1.1 復(fù)制解決的問(wèn)題下面是復(fù)制常見(jiàn)的用途:
數(shù)據(jù)分布。Mysql 復(fù)制通常不會(huì)對(duì)帶寬造成很大壓力,但在 5.1 版本中引入的基于行的復(fù)制會(huì)比傳統(tǒng)的基于語(yǔ)句的復(fù)制模式產(chǎn)生更大的帶寬壓力。你可以隨意地停止或開(kāi)始復(fù)制,并在不同的地理位置來(lái)分布數(shù)據(jù)備份,例如不同的數(shù)據(jù)中心。另外,即使在不穩(wěn)定的網(wǎng)絡(luò)環(huán)境下,遠(yuǎn)程復(fù)制也可以工作。但如果未來(lái)保存很低的復(fù)制延遲,最好有一個(gè)穩(wěn)定、低延遲的連接。
負(fù)載均衡。通過(guò) Mysql 復(fù)制,可以將讀操作分布到多個(gè)服務(wù)器上,實(shí)現(xiàn)對(duì)讀密集型應(yīng)用的優(yōu)化,并且很容易實(shí)現(xiàn),通過(guò)簡(jiǎn)單的代碼修改就能實(shí)現(xiàn)基本的負(fù)載均衡。對(duì)應(yīng)小規(guī)模的應(yīng)用,可以簡(jiǎn)單的使用 DNS 輪詢(將一個(gè)機(jī)器名指向多個(gè) IP 地址)。
備份。對(duì)于備份來(lái)說(shuō),負(fù)載是一項(xiàng)很有意義的技術(shù)補(bǔ)充。
高可用性和故障切換。負(fù)載能夠幫助應(yīng)用避免 Mysql 單點(diǎn)失敗,一個(gè)使用復(fù)制的設(shè)計(jì)良好的系統(tǒng)能夠顯著的縮短宕機(jī)時(shí)間。
Mysql 升級(jí)測(cè)試。這是比較常見(jiàn)的做法,在更新 Mysql 版本前,先使用將要更新的版本作為備庫(kù),保證更新版本不會(huì)對(duì)系統(tǒng)造成影響。
1.2 復(fù)制是如何工作的?在詳細(xì)介紹如何設(shè)置復(fù)制之前,讓我們先看看 Mysql 實(shí)際上是如何進(jìn)行數(shù)據(jù)復(fù)制的。
總的來(lái)說(shuō),復(fù)制有三個(gè)步驟:
在主庫(kù)上把數(shù)據(jù)更改寫(xiě)入到二進(jìn)制日志(Binary Log)中(這些記錄被稱為二進(jìn)制日志事件)。
備庫(kù)將主庫(kù)上的日志復(fù)制到自己的中繼日志(Relay Log)中。
備庫(kù)讀取中繼日志中的事件,將其更改同步到備庫(kù)。
以上是復(fù)制的簡(jiǎn)單概述,下圖描述了復(fù)制的細(xì)節(jié):
整體復(fù)制過(guò)程:
在主庫(kù)上記錄二進(jìn)制日志。在每次準(zhǔn)備提交事務(wù)完成 數(shù)據(jù)更新前,主庫(kù)將數(shù)據(jù)更新的事件記錄到二進(jìn)制日志中。Mysql 會(huì)按事務(wù)提交的順序而非每條語(yǔ)句的執(zhí)行順序來(lái)記錄二進(jìn)制日志。在記錄二進(jìn)制日志后,主庫(kù)會(huì)告訴存儲(chǔ)引擎可以提交事務(wù)了。
備庫(kù)將主庫(kù)的二進(jìn)制日志復(fù)制到其本地的中繼日志中。首先,備庫(kù)會(huì)啟動(dòng)一個(gè)工作線程,稱為 I/O 線程,I/O 線程跟主庫(kù)建立一個(gè)普通的客戶端連接,然后在主庫(kù)上啟動(dòng)一個(gè)特殊的二進(jìn)制轉(zhuǎn)儲(chǔ)(binlog dump)線程,這個(gè)二進(jìn)制轉(zhuǎn)儲(chǔ)線程會(huì)讀取主庫(kù)二進(jìn)制日志中的事件。它不會(huì)對(duì)時(shí)間進(jìn)行輪詢。如果該線程“追趕”上了主庫(kù),它將進(jìn)入睡眠狀態(tài),直到主庫(kù)發(fā)送信號(hào)量通知它有新的事件產(chǎn)生才會(huì)被換新,備庫(kù) I/O 線程會(huì)將接收到的事件記錄到中繼日志中。
備庫(kù)啟動(dòng) SQL 線程,執(zhí)行最后一步。該線程從中繼日志中讀取事件并在備庫(kù)執(zhí)行,從而實(shí)現(xiàn)備庫(kù)數(shù)據(jù)的更新。當(dāng) SQL 線程追趕上 I/O 線程時(shí),中繼日志通常已經(jīng)在系統(tǒng)緩存中,所以中繼日志的開(kāi)銷(xiāo)很低。SQL 線程執(zhí)行的事件也可以通過(guò)配置項(xiàng)來(lái)決定是否寫(xiě)入自身的二進(jìn)制日志中,這對(duì)于備庫(kù)再配置備庫(kù)的常見(jiàn)非常有用。
這種復(fù)制架構(gòu)實(shí)現(xiàn)了獲取事件和重放事件的解耦,允許這兩個(gè)過(guò)程異步進(jìn)行。也就是說(shuō) I/O 線程能夠獨(dú)立于 SQL 線程之前工作。但是,這種架構(gòu)也限制了復(fù)制的過(guò)程,其中最重要的一點(diǎn)是,在主庫(kù)上并發(fā)運(yùn)行的查詢?cè)趥鋷?kù)上只能串行化執(zhí)行,因?yàn)橹挥幸粋€(gè) SQL 線程來(lái)重放中繼日志中的事件。
不過(guò)值得高興的是,5.7 版本已經(jīng)支持從庫(kù)的并行復(fù)制了?;诙M(jìn)制日志的并行復(fù)制,是在日志內(nèi)容中新增了 last_committed 和 sequence_number,分別 表示事務(wù)提交的時(shí)間和上次事務(wù)提交的編號(hào)。如果事務(wù)具有相同的時(shí)間,表示這些事務(wù)是在一組內(nèi),可以進(jìn)行并行回放。
2. 復(fù)制的原理我們已經(jīng)了解了復(fù)制的一些基本概念,接下來(lái)我們要更深入的了解復(fù)制,看看復(fù)制究竟是如何工作的,有哪些優(yōu)缺點(diǎn)。
2.1 基于語(yǔ)句的復(fù)制在 Mysql 5.0 及之前的版本中只支持基于語(yǔ)句的復(fù)制(也稱為邏輯復(fù)制)?;谡Z(yǔ)句的復(fù)制模式,主庫(kù)會(huì)記錄那些造成數(shù)據(jù)更改的 SQL 語(yǔ)句,當(dāng)備庫(kù)讀取并重放這些事件時(shí),實(shí)際上只是把主庫(kù)執(zhí)行過(guò)的 SQL 再執(zhí)行一遍。這種方式既有優(yōu)點(diǎn),也有缺點(diǎn)。
優(yōu)點(diǎn)是:
實(shí)現(xiàn)簡(jiǎn)單。理論上來(lái)說(shuō),只要簡(jiǎn)單地記錄和執(zhí)行 SQL 語(yǔ)句,就能夠讓主備保持同步。
二進(jìn)制日志不會(huì)對(duì)帶寬產(chǎn)生較大影響。二進(jìn)制日志里的事件更加緊湊,占用帶寬較小。
但事實(shí)上,基于語(yǔ)句的方式可能并不如其看起來(lái)那么便利,其缺點(diǎn)是:
主庫(kù)上的數(shù)據(jù)除了執(zhí)行的語(yǔ)句外,可能還依賴其他因素。當(dāng)主庫(kù)使用 CURRENT_USER() 函數(shù)的語(yǔ)句,存儲(chǔ)過(guò)程和觸發(fā)器在使用基于語(yǔ)句的復(fù)制模式時(shí)就可能會(huì)出現(xiàn)問(wèn)題。
2.2 基于行的復(fù)制Mysql 5.1 開(kāi)始支持基于行的復(fù)制。這種方式會(huì)將實(shí)際數(shù)據(jù)記錄在二進(jìn)制日志中。同樣的,它也有其自身的優(yōu)缺點(diǎn)。
它的優(yōu)點(diǎn)是可以更加準(zhǔn)確的復(fù)制數(shù)據(jù),而缺點(diǎn),則是可能造成較大的開(kāi)銷(xiāo)。比如一個(gè)工資表中有一萬(wàn)個(gè)用戶,我們把每個(gè)用戶的工資+1000,那么基于行的復(fù)制則要復(fù)制一萬(wàn)行的內(nèi)容,由此造成的開(kāi)銷(xiāo)比較大,而基于語(yǔ)句的復(fù)制僅僅一條語(yǔ)句就可以了。
由于沒(méi)有哪種模式是對(duì)所有情況都是完美的,Mysql 就使復(fù)制模式可以動(dòng)態(tài)切換。默認(rèn)情況下使用的是基于語(yǔ)句的復(fù)制方式,但如果發(fā)現(xiàn)語(yǔ)句無(wú)法被正確地復(fù)制,就切換到基于行的復(fù)制模式。還可以根據(jù)需要來(lái)設(shè)置會(huì)話級(jí)別的變量 binlog_format,控制二進(jìn)制日志格式。
2.3 復(fù)制文件解讀復(fù)制過(guò)程中會(huì)使用到一些文件。前面已經(jīng)介紹了二進(jìn)制日志文件和中繼日志文件,除此之外,還有其他的文件會(huì)被用到。
mysql-bin.index:當(dāng)在服務(wù)器上開(kāi)啟二進(jìn)制日志時(shí),同時(shí)會(huì)生成一個(gè)和二進(jìn)制日志同名,但以 .index 作為后綴的文件,該文件用于記錄磁盤(pán)上的二進(jìn)制日志文件。這里的 index 并不是表的索引,而是說(shuō)這個(gè)文件的每一行包含了二進(jìn)制文件的文件名。Mysql 依賴這個(gè)文件識(shí)別二進(jìn)制日志文件。
mysql-relay-bin-index:中繼日志的索引文件,和 mysql-bin.index 的作用類似。
master.info:保存?zhèn)鋷?kù)連接主庫(kù)所需要的信息文件。格式為純文本(每行一個(gè)值),不同的 Mysql 版本,記錄的信息也可能不太。此文件不能刪除,否則備庫(kù)再重啟后不能連接主庫(kù)。這個(gè)文件以文本的方式記錄了復(fù)制用戶的密碼,所以要注意此文件的權(quán)限控制。
relay-log.info:記錄當(dāng)前備庫(kù)復(fù)制的二進(jìn)制日志和中繼日志位置文件。
使用這些文件來(lái)記錄 Mysql 復(fù)制和日志狀態(tài)是一種非常粗糙的方式。更不幸的是,它們不是同步寫(xiě)的。如果服務(wù)器斷電并且文件數(shù)據(jù)沒(méi)有被刷新到磁盤(pán),在重啟服務(wù)器后,文件中記錄的數(shù)據(jù)可能是錯(cuò)誤。不過(guò)好在這些問(wèn)題以及在 5.5 版本里做了改進(jìn)。
2.4 發(fā)送復(fù)制事件到其它備庫(kù)log_slave_update 選項(xiàng)可以讓備庫(kù)編程其它服務(wù)器的主庫(kù)。在設(shè)置該選項(xiàng)后,Mysql 會(huì)將其執(zhí)行過(guò)的事件記錄到它自己的二進(jìn)制日志中。這樣它的備庫(kù)就可以從其日志中檢索并執(zhí)行事件。下圖闡述了這一過(guò)程:
在這種場(chǎng)景下,主庫(kù)將數(shù)據(jù)更新事件寫(xiě)入二進(jìn)制日志,第一個(gè)備庫(kù)提取并執(zhí)行這個(gè)事件。這個(gè)時(shí)候一個(gè)事件的生命周期應(yīng)該已經(jīng)結(jié)束了。但由于設(shè)置了 log_slave_updates,備庫(kù)會(huì)將這個(gè)事件寫(xiě)到它自己的二進(jìn)制日志中。這樣第二個(gè)備庫(kù)就可以從第一個(gè)備庫(kù)中,將事件提取到它的中繼日志中并執(zhí)行。
這意味著作為源服務(wù)器的主庫(kù)可以將其數(shù)據(jù)變化傳遞給沒(méi)有與其直接相連的備庫(kù)上。默認(rèn)情況下,這個(gè)選項(xiàng)是被打開(kāi)的,這樣在連接到備庫(kù)時(shí)就不需要重啟服務(wù)器。
當(dāng)?shù)谝粋€(gè)備庫(kù)把自主庫(kù)獲得的事件寫(xiě)入到其它二進(jìn)制日志中時(shí),這個(gè)事件在備庫(kù)二進(jìn)制日志中的位置與其主庫(kù)二進(jìn)制日志中的位置幾乎肯定是不相同的,可能在不同的日志文件或文件內(nèi)不同的位置。這意味著你不能假定所有擁有同一邏輯復(fù)制點(diǎn)的服務(wù)器擁有相同的日志坐標(biāo)。
小結(jié)復(fù)制功能是 MySQL 高擴(kuò)展性的基礎(chǔ),常見(jiàn)的讀寫(xiě)分離就使用了復(fù)制。
復(fù)制使用了三個(gè)線程。master 的日志線程,將事件寫(xiě)入 binlog,slave 的 IO 線程獲取 binlog,并將其寫(xiě)入 relaylog,SQL 線程重放 relaylog 日志。
復(fù)制有基于語(yǔ)句復(fù)制和基于行的復(fù)制。
參考:
高性能 MySQL - 第 3 版;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/31138.html
摘要:也就是說(shuō)線程能夠獨(dú)立于線程之前工作。復(fù)制使用了三個(gè)線程。的日志線程,將事件寫(xiě)入,的線程獲取,并將其寫(xiě)入,線程重放日志。 1. 復(fù)制概述 MySQL 內(nèi)置的復(fù)制功能是構(gòu)建基于 MySQL 的大規(guī)模、高性能應(yīng)用的基礎(chǔ),復(fù)制解決的基本問(wèn)題是讓一臺(tái)服務(wù)器的數(shù)據(jù)與其他服務(wù)器保持同步。接下來(lái),我們將從復(fù)制概述及原理、復(fù)制的配置、常見(jiàn)的問(wèn)題及解決方法來(lái)學(xué)習(xí) MySQL 的復(fù)制功能。 1.1 復(fù)制解決...
摘要:配置主庫(kù)和備庫(kù)。主庫(kù)當(dāng)前的二進(jìn)制日志文件,和獲得數(shù)據(jù)快照時(shí)在該二進(jìn)制日志文件中的偏移量。它能夠在備份時(shí)不阻塞服務(wù)器的操作,因此可以在不影響主庫(kù)的情況下設(shè)置備庫(kù)。 showImg(https://segmentfault.com/img/bVbqOEk?w=720&h=480); 正所謂理論造航母,現(xiàn)實(shí)小帆船。單有理論,不動(dòng)手實(shí)踐,學(xué)到的知識(shí)猶如空中樓閣。接下來(lái),我們一起來(lái)看下如何一步步...
摘要:配置主庫(kù)和備庫(kù)。主庫(kù)當(dāng)前的二進(jìn)制日志文件,和獲得數(shù)據(jù)快照時(shí)在該二進(jìn)制日志文件中的偏移量。它能夠在備份時(shí)不阻塞服務(wù)器的操作,因此可以在不影響主庫(kù)的情況下設(shè)置備庫(kù)。 showImg(https://segmentfault.com/img/bVbqOEk?w=720&h=480); 正所謂理論造航母,現(xiàn)實(shí)小帆船。單有理論,不動(dòng)手實(shí)踐,學(xué)到的知識(shí)猶如空中樓閣。接下來(lái),我們一起來(lái)看下如何一步步...
閱讀 3606·2021-10-11 10:58
閱讀 2094·2021-09-24 09:47
閱讀 573·2019-08-30 14:19
閱讀 1858·2019-08-30 13:58
閱讀 1508·2019-08-29 15:26
閱讀 689·2019-08-26 13:45
閱讀 2206·2019-08-26 11:53
閱讀 1832·2019-08-26 11:30