阿里二面:聊聊 MySQL 主從同步方案的優(yōu)缺點
大家好,我是君哥。今天來聊一聊 MySQL 主從架構(gòu)。
MySQL Replication 是 MySQL 官方提供的主從同步方案,用于將 MySQL 主庫的數(shù)據(jù)同步到從庫中,從庫可以供應(yīng)用程序讀取數(shù)據(jù)。
1.簡介
Replication 是目前 MySQL 使用最多的災(zāi)備方案,主要有 3 個作用:
- 讀寫分離,寫主庫讀從庫。這樣大大降低主庫的負載,即使主庫出現(xiàn)類似鎖表之類的情況,也不影響應(yīng)用讀取數(shù)據(jù)。
- 實現(xiàn)災(zāi)備,當主庫發(fā)生故障時,可以方便地把從庫切換成主庫,實現(xiàn)高可用(HA)。
- 水平擴展,當應(yīng)用訪問量導致數(shù)據(jù)庫 I/O 高時,可以通過水平擴展的方式將降低單機負載,降低磁盤 I/O。
下面是一個 MySQL Replication 的案例。
圖片
在上面的例子中,有一個主庫,三個從庫,通過 Replication,主庫生成 events 的 binlog 發(fā)給 slave,Slave 將收到的 binlog 拷貝到 relaylog,然后解析 relaylog 中的命令進行執(zhí)行,實現(xiàn)主從數(shù)據(jù)同步。
2.同步原理
MySQL 通過 binlog 實現(xiàn)同步過程中,會用到 3 個線程:
- IO thread: 從庫執(zhí)行 START SLAVE 語句時,會創(chuàng)建一個 IO thread,負責連接主節(jié)點,請求更新的 binlog,接收到 binlog 后寫入 relaylog;
- dump thread:主庫接收到從庫的 binlog 請求后,創(chuàng)建一個 dump thread,把 binlog 同步給從庫;
- sql thread:讀取 relaylog,解析 relaylog 的命令并執(zhí)行,將數(shù)據(jù)落庫。
整個同步流程如下:
圖片
- 在從庫上執(zhí)行 change master 命令,設(shè)置要連接主庫的用戶名、密碼、ip、端口以及請求同步的 binlog 中的位置,這個位置包含文件名和binlog offset;
- 從庫執(zhí)行 start slave 命令,這時會啟動上面的 IO thread 和 sql thread,其中 IO thread 負責跟主庫建立連接;
- 主庫收到從庫的連接請求后,校驗用戶名密碼;
- 主庫校驗通過后創(chuàng)建 dump thread,按照從庫請求 binlog 的 offset 將 binlog 發(fā)給從庫;
- 從庫收到主庫發(fā)送的 binlog 后,將日志寫入 relaylog;
- sql thread 讀取 relaylog,解析出命令后執(zhí)行。
3.優(yōu)缺點
前面講到,主從同步有讀寫分離、實現(xiàn)災(zāi)備、水平擴展等優(yōu)點。那主從同步有哪些缺點呢?最大的缺點就是主從延遲。
導致主從延遲的主要原因如下:
- 從庫所在機器性能差,命令執(zhí)行慢;
- 從庫查詢壓力大,消耗了大量 CPU 資源,影響了 sql thread 執(zhí)行;
- 主庫有大事務(wù)(比如大表DDL),這個事務(wù)里面執(zhí)行的 sql 比較多,一方面主庫需要等待事務(wù)執(zhí)行完成才能寫入 binlog,另一方面同步到從庫和在從庫執(zhí)行都需要花費很多時間,導致主從延遲;
- 數(shù)據(jù)庫版本低,在 MySQL 5.6 之前,只支持單線程復制,效率比較低;
- 表上無主鍵,主庫利用索引更改數(shù)據(jù),從庫只能用全表掃描。
要解決主備延遲的問題,可以考慮下面方法:
- 優(yōu)化業(yè)務(wù)邏輯,避免使用大事務(wù),或者大事務(wù)場景盡量放在業(yè)務(wù)低峰期執(zhí)行;
- 提高從庫所在機器的性能;
- 保障網(wǎng)絡(luò)性能,避免網(wǎng)絡(luò)延遲;
- 引入 semi-sync 半同步復制,配合異步復制。
主從同步的第二個缺點就是數(shù)據(jù)丟失。
MySQL 有 3 種主從復制方式:
- 異步復制:主庫執(zhí)行完客戶端提交的事務(wù)后立即將結(jié)果返回給客戶端,不關(guān)心從庫是否同步完成。這種方式很容易發(fā)生數(shù)據(jù)丟失,比如主庫的日志還未同步給從庫就宕機了,這時需要在從庫中選擇一個作為新主庫,之前未同步完成的數(shù)據(jù)就丟失了;
- 全同步復制:主庫執(zhí)行完客戶端提交的事務(wù)并且等待從庫也執(zhí)行完成數(shù)據(jù)同步后再把結(jié)果返回給客戶端。這種方式能夠保證不丟失數(shù)據(jù),但是數(shù)據(jù)庫的性能會受到影響;
- 半同步復制:是介于全同步和異步復制的一種方式,主庫至少等待一個從庫接收 binlog 并成功寫入到 relaylog 后給客戶端返回結(jié)果。主庫不需要等待所有從庫返回 ACK。
MySQL 中默認采用異步復制,這樣很容易導致數(shù)據(jù)丟失。一個好的方式就是采用 semi-sync 半同步復制插件。不過 semi-sync 存在一個問題,主庫寫數(shù)據(jù)到 binlog 后執(zhí)行 commit,才會給從庫同步數(shù)據(jù)。如果從庫還沒有返回 ACK,主庫發(fā)生了宕機,從庫還沒有寫完 relaylog 就被選擇為主庫,也會發(fā)生數(shù)據(jù)丟失。
為了解決這個問題,MySQL 5.7 引入了增強版半同步復制。主庫寫入數(shù)據(jù)到 binlog 后,就給從庫進行同步,直到至少一個從庫返回給主庫 ACK,主庫才會進行 commit 操作。
4.總結(jié)
本文介紹了 MySQL 主從同步方案的優(yōu)缺點,希望能對你使用和理解 MySQL 有所幫助。



























