C-18.主從複製
1.主從複製概述
1.1 如何提升資料庫併發能力
在實際工作中,我們常常將Redis
作為快取與MySQL
配合來使用,當有請求的時候,首先會從快取中進行查詢,如果存在就直接取出。如果不存在再方法資料庫,這樣就提升了讀取的效率
,也減少了對後端資料庫的訪問壓力
。Redis的快取架構是高併發架構
中非常重要的一環。
此外,一般應用對資料庫而言都是“讀多寫少
”,也就說對資料庫讀取資料的壓力比較大,有一個思路就是採用資料庫叢集的方案,做主從架構
、進行讀寫分離
,這樣同樣可以提升資料庫的併發處理能力。但並不是所有的應用都需要對資料庫進行主從架構的設定,畢竟設定架構本身是有成本的。
如果我們的目的在於提升資料庫高併發訪問的效率,那麼首先考慮的是如何最佳化SQL和索引
,這種方式簡單有效;其次才是採用快取的策略
,比如使用Redis將熱點資料儲存在記憶體資料庫中,提升讀取的效率最後才是對資料庫採用主從架構
,進行讀寫分離。
按照上面的方式進行最佳化,使用和維護的成本是由低到高的。
1.2 主從複製的作用
主從同步設計不僅可以提高資料庫的吞吐量,還有以下3個方面的作用。
第1個作用:讀寫分離。我們可以透過主從複製的方式來同步資料
,然後透過讀寫分離提高資料庫併發處理能力。
其中一個是Master主庫,負責寫入資料,我們稱之為:寫庫。
其它都是slave從庫,負責讀取資料,我們稱之為:讀庫。
當主庫進行更新的時候,會自動將資料複製到從庫中,而我們在客戶端讀取資料的時候,會從從庫中進行讀取。
面對“讀多寫少
”的需求,採用讀寫分離的方式,可以實現更高的併發訪問
。同時,我們還能對從伺服器進行負載均衡
,讓不同的讀請求按照策略均勻地分發到不同的從伺服器上,讓讀取更加順暢
。讀取順暢的另一個原因,就是減少了鎖表
的影響,比如我們讓主庫負責寫,當主庫出現寫鎖的時候,不會影響到從庫進行SELECT的讀取。
第2個作用就是資料備份。我們透過主從複製將主庫上的資料複製到了從庫上,相當於是一種熱備份機制
,也就是在主庫正常執行的情況下進行的備份,不會影響到服務。
第3個作用是具有高可用性。資料備份實際上是一種冗餘的機制,透過這種冗餘的方式可以換取資料庫的高可用性,也就是當伺服器出現故障
或當機
的情況下,可以切換
到從伺服器上,保證服務的正常執行。
關於高可用性的程度,我們可以用一個指標衡量,即正常可用時間/全年時間。比如要達到全年99.999%的時間都可用,就意味著系統在一年中的不可用時間不得超過365*24*60+ (1-99.999%)=5.256
分鐘(含系統崩潰的時間、日常維護操作導致的停機時間等),其他時間都需要保持可用的狀態。
實際上,更高的高可用性,意味著需要付出更高的成本代價。在現實中我們需要結合業務需求和成本來進行選擇。
2.主從複製的原理
Slave
會從Master
讀取binlog
來進行資料同步。
2.1 原理剖析
實際上主從同步的原理就是基於binlog 進行資料同步的。在主從複製過程中,會基於3個執行緒
來操作,一個主庫執行緒,兩個從庫執行緒。
二進位制日誌轉儲執行緒
(Binlog dump thread)是一個主庫執行緒。當從庫執行緒連線的時候,主庫可以將二進位制日誌傳送給從庫,當主庫讀取事件(Event)的時候,會在Binlog上加鎖
,讀取完成之後,再將鎖釋放掉。
從庫I/O執行緒
會連線到主庫,向主庫傳送請求更新Binlog。這時從庫的I/O執行緒就可以讀取到主庫的二進位制日誌轉儲執行緒,傳送的Binlog 更新部分,並且複製到本地的中繼日誌(Relay log)。
從庫SQL執行緒
會讀取從庫中的中繼日誌,並且執行日誌中的事件,將從庫中的資料與主庫保持同步。
注意:
不是所有版本的MySQL都預設開啟伺服器的二進位制日誌。在進行主從同步的時候,我們需要先檢查伺服器是否已經開啟了二進位制日誌。
除非特殊指定,預設情況下從伺服器會執行所有主伺服器中儲存的事件。也可以透過配置,使從伺服器執行特定的事件。
複製三步驟
步驟1: Master
將寫操作記錄到二進位制日誌(binlog
)。這些記錄叫做二進位制日誌事件(binary log events);
步驟2: Slave
將Master
的binary log everkts複製到它的中繼日誌(relay log
) ;
步驟3: Slave
重做中繼日誌中的事件,將改變應用到自己的資料庫中。MySQL複製是非同步的且序列化的,而且重啟後從接入點
開始複製。
複製的問題
複製的最大問題:延時
。
2.2 複製的基本原則
- 每個
Slave
只能有一個Master
。 - 每個
Slave
只能有一個唯一的伺服器ID。 - 每個
Master
可以有多個Slave
。
3.一主一從架構搭建
一臺主機用於處理所有寫請求,一臺從機負責所有讀請求,架構圖如下:
3.1 準備工作
1、準備2臺
CentOS虛擬機器
2、每臺虛擬機器上需要安裝好MySQL(可以是8.0.x)
說明:前面我們講過如何克隆一臺CentOS。大家可以在一臺CentOS上安裝好MySQL,進而透過克隆的方式複製出1臺包含MySQL的虛擬機器。
注意:克隆的方式需要修改新克隆出來主機的:① MAC地址
② hostname
③ IP 地址
④ UUID
。
此外,克隆的方式生成的虛擬機器(包含MySQL Server),則克隆的虛擬機器MySQL Server的UUID相同,必須修改,否則在有些場景會報錯。比如: show slave status\G
,報如下的錯誤:
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
修改MySQL Server 的UUID方式:
vim /var/lib/mysql/auto.cnf#修改uuid
systemctl restart mysqld#重新啟動MySQL服務
3.2 主機配置檔案
建議mysql版本一致且後臺以服務執行,主從所有配置項都配置在[mysqld]
節點下,且都是小寫字母。
具體引數配置如下:
- 必選
#[必須]主伺服器唯一ID
server-id=1
#[必須]啟動二進位制日誌,指明路徑,比如 '/var/lib/mysql/'
log-bin=binlog
- 可選
#[可選] 0(預設)表示讀寫(主機),1表示只讀(從機)
read-only=0
#設定日誌檔案保留的時長,單位是秒
binlog_expire_logs_seconds=6000
#控制單個二進位制日誌大小。此引數的最大和預設值是1GB
max_binlog_size=200M
#[可選]設定不要複製的資料庫
binlog-ignore-db=test
#[可選]設定需要複製的資料庫,預設全部記錄。比如:binlog-do-db=atguigu_master_slave
binlog-do-db=需要複製的主資料庫名字
#[可選]設定binlog格式
binlog_format=STATEMENT
重啟後臺mysql服務,使配置生效
注意:
先建立完主從複製,再建立資料庫。
MySQL主從複製起始時,從機不繼承主機資料。
binlog格式設定:
①STATEMENT模式(基於SQL語句的複製(statement-based replication, SBR))
binlog_format=STATEMENT
每一條會修改資料的sql語句會記錄到binlog中。這是預設的binlog格式。
- SBR 的優點:
- 歷史悠久,技術成熟
- 不需要記錄每一行的變化,減少了binlog日誌量,檔案較小
- binlog中包含了所有資料庫更改資訊,可以據此來稽核資料庫的安全等情況
- binlog可以用於實時的還原,而不僅僅用於複製
- 主從版本可以不一樣,從伺服器版本可以比主伺服器版本高
- SBR 的缺點:
- 不是所有的UPDATE語句都能被複制,尤其是包含不確定操作的時候
- 使用以下函式的語句也無法被複制:LOAD_FILE()、UUID()、USER()、FOUND_ROWS()、SYSDATE() (除非啟動時啟用了 --sysdate-is-now 選項)
- INSERT ... SELECT 會產生比 RBR 更多的行級鎖
- 複製需要進行全表掃描(WHERE 語句中沒有使用到索引)的 UPDATE 時,需要比 RBR 請求更多的行級鎖
- 對於有 AUTO_INCREMENT 欄位的 InnoDB表而言,INSERT 語句會阻塞其他 INSERT 語句
- 對於一些複雜的語句,在從伺服器上的耗資源情況會更嚴重,而 RBR 模式下,只會對那個發生變化的記錄產生影響
- 執行復雜語句如果出錯的話,會消耗更多資源
- 資料表必須幾乎和主伺服器保持一致才行,否則可能會導致複製出錯
②ROW模式(基於行的複製(row-based replication,RBR))
binlog_format=ROW
5.1.5版本的MySQL才開始支援,不記錄每條sql語句的上下文資訊,僅記錄哪條資料被修改了,修改成什麼樣了。
-
RBR 的優點:
-
任何情況都可以被複制,這對複製來說是最
安全可靠
的。(比如:不會出現某些特定情況下的儲存過程、function、trigger的呼叫和觸發無法被正確複製的問題) -
多數情況下,從伺服器上的表如果有主鍵的話,複製就會快了很多
-
複製以下幾種語句時的行鎖更少:INSERT ... SELECT、包含 AUTO_INCREMENT 欄位的 INSERT、沒有附帶條件或者並沒有修改很多記錄的 UPDATE 或 DELETE 語句
-
執行 INSERT,UPDATE,DELETE 語句時鎖更少
-
從伺服器上採用
多執行緒
來執行復製成為可能
-
-
RBR 的缺點:
-
binlog 大了很多
-
複雜的回滾時 binlog 中會包含大量的資料
-
主伺服器上執行 UPDATE 語句時,所有發生變化的記錄都會寫到 binlog 中,而 SBR 只會寫一次,這會導致頻繁發生 binlog 的併發寫問題
-
無法從 binlog 中看到都複製了些什麼語句
-
③MIXED模式(混合模式複製(mixed-based replication,MBR))
binlog_format=MIXED
從5.1.8版本開始,MySQL提供了Mixed格式,實際上就是Statement與Row的結合。
在Mixed模式下,一般的語句修改使用statment格式儲存binlog。如一些函式,statement無法完成主從複製的操作,則採用row格式儲存binlog。
MySQL會根據執行的每一條具體的sql語句來區分對待記錄的日誌形式,也就是在Statement和Row之間選擇一種。
3.3 從機配置檔案
要求主從所有配置項都配置在my.cnf
的[mysqld]
欄位下,且都是小寫字母。
- 必選
#[必須]從伺服器唯一ID
server-id=2
- 可選
#[可選]啟用中繼日誌
relay-log=mysql-relay
重啟MySQL服務,使配置生效
注意:主從機都關閉防火牆
service iptables stop #CentOS 6
systemctl stop firewalld.service #CentOS 7
3.4 主機:建立賬戶並授權
#在主機MySQL裡執行授權主從複製的命令
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'從機器資料庫IP' IDENTIFIED BY 'abc123';
#5.5,5.7
注意:如果使用的是MySQL8,需要如下的方式建立賬戶,並授權slave:
CREATE USER 'slave1'@'%' IDENTIFIED BY 'ming6688';
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';
#此語句必須執行。否則見下面。
ALTER USER 'slave1'@'%' IDENTIFIED WITH mysql_native_password BY 'ming6688';
flush privileges;
查詢Master的狀態,並記錄下File和Position的值。
show master status;
- 記錄下File和Position的值
注意:執行完此步驟後不要再操作主伺服器MySQL,防止主伺服器狀態值變化。
3.5 從機:配置需要複製的主機
步驟1:從機上覆制主機的命令
CHANGE MASTER TO
MASTER_HOST='主機的IP地址',
MASTER_USER='主機使用者名稱',
MASTER_PASSWORD='主機使用者名稱的密碼',
MASTER_LOG_FILE='mysql-bin.具體數字',
MASTER_LOG_POS=具體值;
舉例:
CHANGE MASTER TO
MASTER_HOST='192.168.200.132',
MASTER_USER='slave1',
MASTER_PASSWORD='ming6688',
MASTER_LOG_FILE='binlog.000067',
MASTER_LOG_POS=2058;
步驟2:
#啟動slave同步
START SLAVE;
如果報錯:
可以執行如下操作,刪除之前的relay_log資訊。然後重新執行 CHANGE MASTER TO ...語句即可。
mysql> reset slave; #刪除SLAVE資料庫的relaylog日誌檔案,並重新啟用新的relaylog檔案
接著,檢視同步狀態
SHOW SLAVE STATUS\G;
上面兩個引數都是Yes,則說明主從配置成功!
顯示如下的情況,就是不正確的。可能錯誤的原因有
1. 網路不通
2. 賬戶密碼錯誤
3. 防火牆
4. mysql配置檔案問題
5. 連線伺服器時語法
6. 主伺服器mysql許可權
3.6 測試
主機新建庫、新建表、insert記錄,從機複製:
CREATE DATABASE test_master_slave;
CREATE TABLE mytbl(id INT,NAME VARCHAR(16));
INSERT INTO mytbl VALUES(1, 'zhang3');
INSERT INTO mytbl VALUES(2,@@hostname);
3.7 停止主從同步
- 停止主從同步命令
stop slave;
- 如何重新配置主從
如果停止從伺服器複製功能,再使用需要重新配置主從。否則會報錯如下:
重新配置主從,需要在從機上執行
stop slave;
reset master;#刪除Master中所有的binglog檔案,並將日誌索引檔案清空,重新開始所有新的日誌檔案(慎用)
3.8 後續
搭建主從複製:雙主雙從
4.同步資料一致性問題
主從同步的要求:
- 讀庫和寫庫的資料一致(最終一致);
- 寫資料必須寫到寫庫;
- 讀資料必須到讀庫(不一定);
4.1 理解主從延遲問題
進行主從同步的內容是二進位制日誌,它是一個檔案,在進行網路傳輸
的過程中就一定會存在主從延遲
(比如 500ms),這樣就可能造成使用者在從庫上讀取的資料不是最新的資料,也就是主從同步中的資料不一致性
問題。
4.2 主從延遲問題原因
在網路正常的時候,日誌從主庫傳給從庫所需的時間是很短的,即T2-T1的值是非常小的。即,網路正常情況下,主備延遲的主要來源是備庫接收完binlog和執行完這個事務之間的時間差。
主備延遲最直接的表現是,從庫消費中繼日誌(relay log)的速度,比主庫生產binlog的速度要慢。
造成原因:
1、從庫的機器效能比主庫要差
2、從庫的壓力大
3、大事務的執行
舉例1:一次性用delete語句刪除太多資料
結論:後續再刪除資料的時候,要控制每個事務刪除的資料量,分成多次刪除。
舉例2:一次性用insert...select插入太多資料
舉例3:大表DDL
比如在主庫對一張500W的表新增一個欄位耗費了10分鐘,那麼從節點上也會耗費10分鐘。
4.3 如何減少主從延遲
若想要減少主從延遲的時間,可以採取下面的辦法:
- 降低多執行緒大事務併發的機率,最佳化業務邏輯
- 最佳化SQL,避免慢SQL,
減少批次操作
,建議寫指令碼以update-sleep這樣的形式完成。 提高從庫機器的配置
,減少主庫寫binlog和從庫讀binlog的效率差。- 儘量採用
短的鏈路
,也就是主庫和從庫伺服器的距離儘量要短,提升埠頻寬,減少binlog傳輸的網路延時。 - 實時性要求的業務讀強制走主庫,從庫只做災備,備份
4.4 如何解決一致性問題
如果操作的資料儲存在同一個資料庫中,那麼對資料進行更新的時候,可以對記錄加寫鎖,這樣在讀取的時候就不會發生資料不一致的情況。但這時從庫的作用就是備份
,並沒有起到讀寫分離
,分擔主庫讀壓力
的作用。
讀寫分離情況下,解決主從同步中資料不一致的問題, 就是解決主從之間資料複製方式
的問題,如果按照資料一致性從弱到強
來進行劃分,有以下 3 種複製方式。
方法1:非同步複製
非同步模式就是客戶端提交COMMIT之後不需要等從庫返回任何結果,而是直接將結果返回給客戶端,這樣做的好處是不會影響主庫寫的效率,但可能會存在主庫當機,而Binlog還沒有同步到從庫的情況,也就是此時的主庫和從庫資料不一致。這時候從從庫中選擇一個作為新主,那麼新主則可能缺少原來主伺服器中已提交的事務。所以,這種複製模式下的資料一致性是最弱的。
方法2:半同步複製
MySQL5.5版本之後開始支援半同步複製的方式。原理是在客戶端提交COMMIT之後不直接將結果返回給客戶端,而是等待至少有一個從庫接收到了Binlog,並且寫入到中繼日誌中,再返回給客戶端。
這樣做的好處就是提高了資料的一致性,當然相比於非同步複製來說,至少多增加了一個網路連線的延遲,降低了主庫寫的效率。
在MySQL5.7版本中還增加了一個rpl_semi_sync_master_wait_for_slave_count
引數,可以對應答的從庫數量進行設定,預設為1
,也就是說只要有1個從庫進行了響應,就可以返回給客戶端。如果將這個引數調大,可以提升資料一致性的強度,但也會增加主庫等待從庫響應的時間。
方法3:組複製
非同步複製和半同步複製都無法最終保證資料的一致性問題,半同步複製是透過判斷從庫響應的個數來決定是否返回給客戶端,雖然資料一致性相比於非同步複製有提升,但仍然無法滿足對資料一致性要求高的場景,比如金融領域。MGR 很好地彌補了這兩種複製模式的不足。
組複製技術,簡稱 MGR(MySQL Group Replication)。是 MySQL 在 5.7.17 版本中推出的一種新的資料複製技術,這種複製技術是基於 Paxos 協議的狀態機複製。
MGR 是如何工作的
首先我們將多個節點共同組成一個複製組,在執行讀寫(RW)事務
的時候,需要透過一致性協議層(Consensus 層)的同意,也就是讀寫事務想要進行提交,必須要經過組裡“大多數人”(對應 Node 節點)的同意,大多數指的是同意的節點數量需要大於 (N/2+1),這樣才可以進行提交,而不是原發起方一個說了算。而針對只讀(RO)事務
則不需要經過組內同意,直接 COMMIT 即可。
在一個複製組內有多個節點組成,它們各自維護了自己的資料副本,並且在一致性協議層實現了原子訊息和全域性有序訊息,從而保證組內資料的一致性。
MGR 將 MySQL 帶入了資料強一致性的時代,是一個劃時代的創新,其中一個重要的原因就是MGR 是基於 Paxos 協議的。Paxos 演算法是由 2013 年的圖靈獎獲得者 Leslie Lamport 於 1990 年提出的,有關這個演算法的決策機制可以搜一下。事實上,Paxos 演算法提出來之後就作為分散式一致性演算法
被廣泛應用,比如Apache 的 ZooKeeper 也是基於 Paxos 實現的。
5.知識延伸
在主從架構的配置中,如果想要採取讀寫分離的策略,我們可以 自己編寫程式 ,也可以透過第三方的中介軟體
來實現。
- 自己編寫程式的好處就在於比較自主,我們可以自己判斷哪些查詢在從庫上來執行,針對實時性要求高的需求,我們還可以考慮哪些查詢可以在主庫上執行。同時,程式直接連線資料庫,減少了中介軟體層,相當於減少了效能損耗。
- 採用中介軟體的方法有很明顯的優勢,
功能強大
,使用簡單
。但因為在客戶端和資料庫之間增加了中介軟體層會有一些效能損耗
,同時商業中介軟體也是有使用成本的。我們也可以考慮採取一些優秀的開源工具。
①Cobar
屬於阿里B2B事業群,始於2008年,在阿里服役3年多,接管3000+個MySQL資料庫的schema,叢集日處理線上SQL請求50億次以上。由於Cobar發起人的離職,Cobar停止維護。
② Mycat
是開源社群在阿里cobar基礎上進行二次開發,解決了cobar存在的問題,並且加入了許多新的功能在其中。青出於藍而勝於藍。
③ OneProxy
基於MySQL官方的proxy思想利用c語言進行開發的,OneProxy是一款商業收費
的中介軟體。捨棄了一些功能,專注在效能和穩定性上
。
④ kingshard
由小團隊用go語言開發,還需要發展,需要不斷完善。
⑤ Vitess
是Youtube生產在使用,架構很複雜。不支援MySQL原生協議,使用`需要大量改造成本 。
⑥ Atlas
是360團隊基於mysql proxy改寫,功能還需完善,高併發下不穩定。
⑦ MaxScale
是mariadb(MySQL原作者維護的一個版本) 研發的中介軟體
⑧ MySQLRoute
是MySQL官方Oracle公司釋出的中介軟體
只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。