MySQL 內(nèi)建的復制功能是構建基于 Mysql 的大規(guī)模、高性能應用的基礎,同時也是高可用性、可擴展性、災難恢復、備份及數(shù)據(jù)倉庫等工作的基礎。通過本章內(nèi)容,可以更好地理解主從復制的實現(xiàn)機制。
復制解決的問題
- 高可用,避免單點問題,主庫出現(xiàn)故障時,應用依然可以從從庫查詢數(shù)據(jù),不影響查詢業(yè)務,另外通過故障切換功能,可以將從庫切換為主庫,縮短系統(tǒng)宕機時間。
- 數(shù)據(jù)備份,數(shù)據(jù)在系統(tǒng)中存在多份,其中一個機器出現(xiàn)故障,還可以從其它機器獲取數(shù)據(jù)及修復數(shù)據(jù),但是復制不能取代備份。
- 負載均衡,應用系統(tǒng)可以通過讀寫分離實現(xiàn)分流,減輕數(shù)據(jù)庫訪問壓力。
- 升級測試,需要升級 Mysql 版本時,可以先升級從庫的版本,保證查詢業(yè)務可以在高版本的從庫中正常運行,之后再全面升級所有實例。
復制方式
Mysql 支持兩種復制方式:基于語句的復制 和 基于行的復制。兩種方式都是通過在主庫上記錄二進制日志,在從庫重放日志的方式來實現(xiàn)異步的數(shù)據(jù)復制。這意味著,同一時間點,從庫可能與主庫的數(shù)據(jù)不一致,并且無法保證延遲時間,一些大的語句可能導致從庫產(chǎn)生幾秒、幾分鐘甚至幾小時的延遲。
- 基于語句的復制
主庫會將造成數(shù)據(jù)變更的語句記錄到二進制日志,然后到從庫重放,本質(zhì)上就是把主庫執(zhí)行過的語句到從庫再執(zhí)行一遍。實現(xiàn)簡單、事件緊湊,占用帶寬小。
- 基于行的復制
主庫會將實際數(shù)據(jù)記錄到二進制日志,由于無須重放更新主庫數(shù)據(jù)的語句,基于行的復制模式能夠更高效地復制數(shù)據(jù)。
有的語句執(zhí)行開銷比較大,如下面的語句,最終只在目標表上增加三條記錄,如果使用基于行的復制模式,在從庫上開銷就小很多。
insert into summary(col1, col2, col3)
select col1, col2, sum(col3)
from enormous
group by col1, col2;
下面的語句,進行了全表更新,使用基于行的復制模式開銷就很大,因為每一行的數(shù)據(jù)都會被記錄到二進制日志,這使得二進制日志非常龐大,占用大量磁盤空間。
update enormous set cole = 0;
理論上基于行的復制整體上更優(yōu)。

復制工作原理
1、主庫把數(shù)據(jù)更新記錄到二進制日志(Binary Log)中。
每次提交事務完成數(shù)據(jù)更新前,主庫將數(shù)據(jù)更新的事件記錄到二進制日志中。Mysql 會按事務提交順序而非每條語句的執(zhí)行順序來記錄二進制日志。記錄完二進制日志后,主庫會通知存儲引擎執(zhí)行事務提交。
2、從庫將主庫上的日志復制到從庫的中繼日志(Relay Log)中。
從庫啟動一個工作線程,稱為IO線程,IO線程與主庫建立一個普通的客戶端連接,然后在主庫上啟動一個特殊的二進制轉(zhuǎn)儲(binlog dump)線程,這個二進制轉(zhuǎn)儲線程會讀取主庫上二進制日志中的事務,但它不會對事件進行輪詢。如果該線程追趕上了主庫,它將進入睡眠狀態(tài),直到主庫發(fā)送信號量通知其有新的事件產(chǎn)生時才會被喚醒,從庫IO線程會將接收到的事件記錄到從庫的中繼日志中。
3、從庫讀取中繼日志中的事件,將其重放到從庫數(shù)據(jù)之上。
從庫啟動一個SQL線程,讀取中繼日志中的事件并在從庫執(zhí)行,實現(xiàn)從庫數(shù)據(jù)更新。當SQL線程追趕上IO線程時,中繼日志通常已經(jīng)在系統(tǒng)緩存中,所以中繼日志的開銷很低。
具體工作流程如下圖所示:

這種架構實現(xiàn)了獲取事件與重放事件的解耦,允許這兩個過程異步執(zhí)行,也就是說 IO 線程可以獨立于 SQL 線程之外工作。
多級復制
log_slave_updates 選項可以讓從庫變成其它服務器的主庫,該選項默認是打開的,這樣就會形成級聯(lián)的復制。
具體工作流程如下圖所示:

結束語:
Mysql 主從復制并沒有使用輪詢的方式從主庫請求事件,而是主庫通知從庫新的事件,因為前者低效且緩慢,從主庫讀取一個二進制日志事件是一個阻塞型網(wǎng)絡調(diào)用,當主庫記錄事件后,馬上就開始發(fā)送,因此可以說,只要復制線程被喚醒并且能夠通過網(wǎng)絡傳輸數(shù)據(jù),事件就會很快到達從庫,大多數(shù)小查詢在主庫的執(zhí)行時間與在備庫的執(zhí)行時間間隔小于 0.3 毫秒。