1. 程式人生 > >[MySQL高階](七) MySQL主從複製及讀寫分離實戰

[MySQL高階](七) MySQL主從複製及讀寫分離實戰

1. 簡介

  隨著技術的發展,在實際的生產環境中,由單臺MySQL資料庫伺服器不能滿足實際的需求。此時資料庫叢集就很好的解決了這個問題。採用MySQL分散式叢集,能夠搭建一個高併發、負載均衡的叢集伺服器。在此之前我們必須要保證每臺MySQL伺服器裡的資料同步。資料同步我們可以通過MySQL內部配置就可以輕鬆完成,主要有主從複製和主主複製。    MySQL資料庫自身提供的主從複製功能可以方便的實現資料的多處自動備份,實現資料庫的拓展。多個數據備份不僅可以加強資料的安全性,通過實現讀寫分離還能進一步提升資料庫的負載效能。  下圖就描述了一個多個數據庫間主從複製與讀寫分離的模型(來源網路):   

  在一主多從的資料庫體系中,多個從伺服器採用非同步的方式更新主資料庫的變化,業務伺服器在執行寫或者相關修改資料庫的操作是在主伺服器上進行的,讀操作則是在各從伺服器上進行。如果配置了多個從伺服器或者多個主伺服器又涉及到相應的負載均衡問題,關於負載均衡具體的技術細節還沒有研究過,今天就先簡單的實現一主一從的主從複製功能。

1.1 為什麼要做主從複製?

  • 讀寫分離。在業務複雜的系統中,有這麼一個情景,有一句sql語句需要鎖表,導致暫時不能使用讀的服務,那麼就很影響執行中的業務,使用主從複製,讓主庫負責寫,從庫負責讀,這樣,即使主庫出現了鎖表的情景,通過讀從庫也可以保證業務的正常運作。
  • 做資料的熱備
  • 架構的擴充套件。業務量越來越大,I/O訪問頻率過高,單機無法滿足,此時做多庫的儲存,降低磁碟I/O訪問的頻率,提高單個機器的I/O效能。

1.2 主從複製的原理是什麼?

  MySQL的主從複製是一個非同步的複製過程(雖然一般情況下感覺是實時的),資料將從一個MySQL資料庫(Master)複製到另一個MySQL資料庫(Slave),在Master和Slave之間實現整個主從複製的過程是由三個執行緒參與完成的。其中兩個執行緒(SQL執行緒和IO執行緒)在Slave端,另一個執行緒(I/O執行緒)在Master端。    要實現MySQL的主從複製,首先必須開啟Master端的binlog記錄功能,否則就無法實現。binlog: binary log,是主庫中儲存所有更新事件日誌的二進位制檔案。因為整個複製過程實際上就是Slave從Master端獲取binlog日誌,然後在Slave上以相同順序執行獲取的binlog日誌中的記錄的各種SQL操作。   

   我們根據上圖來分析一下整個主從複製的過程:  (1)在Slave伺服器上執行start slave命令開啟主從複製開關,開始進行主從複製。  (2)此時,Slave伺服器的IO執行緒會通過在master上已經授權的複製使用者許可權請求連線Master伺服器,並請求從執行binlog日誌檔案中的指定位置(日誌檔名和位置就是在配置主從複製服務時執行change master命令指定的)之後開始傳送binlog日誌內容。  (3)Master伺服器接收來自Slave伺服器的IO執行緒的請求後,其上負責複製的IO執行緒會根據Slave伺服器的IO執行緒請求的資訊分批讀取指定binlog日誌檔案指定位置之後的binlog日誌資訊,然後返回給Slave端的IO執行緒。返回的資訊中除了binlog日誌內容外,還有在Master伺服器端記錄的IO執行緒。返回的資訊中除了binlog中的下一個指定更新位置。  (4)當Slave伺服器的IO執行緒獲取到Master伺服器上IO執行緒傳送的日誌內容、日誌檔案及位置點後,會將binlog日誌內容依次寫到Slave端自身的Relay Log(即中繼日誌)檔案(Mysql-relay-bin.xxx)的最末端,並將新的binlog檔名和位置記錄到master-info檔案中,以便下一次讀取master端新binlog日誌時能告訴Master伺服器從新binlog日誌的指定檔案及位置開始讀取新的binlog日誌內容  (5)Slave伺服器端的SQL執行緒會實時檢測本地Relay Log 中IO執行緒新增的日誌內容,然後及時把Relay LOG 檔案中的內容解析成sql語句,並在自身Slave伺服器上按解析SQL語句的位置順序執行應用這樣sql語句,並在relay-log.info中記錄當前應用中繼日誌的檔名和位置點

1.3 複製的基本原則

  • 每個Slave只有一個Master
  • 每個Slave只能有一個唯一的服務ID
  • 每個Master可以有多個Slave

1.4 複製的最大問題

延時  主從同步延遲原理和解決方案:  https://www.cnblogs.com/cnmenglang/p/6393769.html

2. 實戰MySQL主從複製

2.1 環境說明

  • 兩個CentOS7虛擬機器
  • MySQL 5.6.4
  • Master_IP:192.168.131.140
  • Slave_IP:192.168.131.141

注意:MySQL版本號最好一致,為了方便學習測試,建議關閉防火牆

2.2 故障避免

我的mysql安裝過程是在一臺虛擬機器上安裝好MySQL後,克隆虛擬機器得到的兩個環境,所以在後面會報一個錯:Fatal error: The slave I/O thread stops because master and slave have equal MySQL server    原因是:mysql 5.6的複製引入了uuid的概念,各個複製結構中的server_uuid得保證不一樣,但是檢視到直接copy data資料夾後server_uuid是相同的,show variables like ‘%server_uuid%’;

解決方法:  mysql 5.6的複製引入了uuid的概念,各個複製結構中的server_uuid得保證不一樣,但是檢視到server_uuid是相同的,

show variables like '%server_uuid%';

找到/var/lib/mysql資料夾下的auto.cnf檔案,修改裡面的uuid值,保證各個db的uuid不一樣,重啟db即可

systemctl restart mysqld.service

https://blog.csdn.net/cug_jiang126com/article/details/46846031

2.3 MySQL主從複製的複製方式

MySQL的主從複製並不完美,存在著幾個由來已久的問題,首先一個問題是複製方式:

  • 基於SQL語句的複製(statement-based replication,SBR)
  • 基於行的複製(row-based replication,RBR)
  • 混合模式複製(mixed-based replication,MBR)
  • 全域性事務識別符號 GTID(Global Transaction Identifier,GTID)

基於SQL語句的方式是最古老的方式,也是目前預設的複製方式,後來的三種是MySQL 5以後才出現的複製方式。

2.3.1 SBR方式的優缺點

SBR的優點

  • 歷史悠久,技術成熟
  • binlog檔案較小
  • binlog中包含了所有資料庫更改資訊,可以據此來稽核資料庫的安全等情況
  • binlog可以用於實時的還原,而不僅僅用於複製
  • 主從版本可以不一樣,從伺服器版本可以比主伺服器版本高

SBR的缺點:

  • 不是所有的UPDATE語句都能被複制,尤其是包含不確定操作的時候
  • 複製需要進行全表掃描(WHERE 語句中沒有使用到索引)的 UPDATE 時,需要比 RBR 請求更多的行級鎖
  • 對於一些複雜的語句,在從伺服器上的耗資源情況會更嚴重,而 RBR 模式下,只會對那個發生變化的記錄產生影響
  • 資料表必須幾乎和主伺服器保持一致才行,否則可能會導致複製出錯
  • 執行復雜語句如果出錯的話,會消耗更多資源

2.3.2 RBR方式的優缺點

RBR的優點

  • 任何情況都可以被複制,這對複製來說是最安全可靠的
  • 和其他大多數資料庫系統的複製技術一樣
  • 多數情況下,從伺服器上的表如果有主鍵的話,複製就會快了很多

RBR 的缺點:

  • binlog 大了很多
  • 複雜的回滾時 binlog 中會包含大量的資料
  • 主伺服器上執行 UPDATE 語句時,所有發生變化的記錄都會寫到 binlog 中,而 SBR 只會寫一次,這會 
  • 導致頻繁發生 binlog 的併發寫問題
  • 無法從 binlog 中看到都複製了寫什麼語句

2.3.3 混合方式

混合方式就是有mysql自動選擇RBR方式和SBR方式,能夠充分發揮兩種方式的優點,一般情況下都使用該種方式實現主從複製

2.3.4 全域性事務識別符號 GTID

這種方式雖然能夠大大提高主從複製的效率,減小主從複製的延時,但也存在問題,具體請參看下面的部落格。  https://blog.csdn.net/guotao521/article/details/45483833  http://hamilton.duapp.com/detail?articleId=47

2.4 實現MySQL主從複製需要進行的配置

  • 主伺服器Master
  1. 開啟二進位制日誌 binlog
  2. 配置唯一的server-id
  3. 獲得master二進位制檔名及位置
  4. 建立一個用於slave和master通訊的使用者賬號
  • 從伺服器Slave
  1. 配置唯一的server-id
  2. 使用master分配的使用者賬號讀取master二進位制日誌
  3. 啟動slave服務

2.5 修改master配置

  • 找到主資料庫的配置檔案my.cnf(或者my.ini),我的在/etc/my.cnf,在[mysqld]部分插入如下:

[mysqld] #開啟二進位制日誌 log-bin=mysql-bin  #設定server-id,建議使用ip最後3位 server-id=140

  • 找到從資料庫的配置檔案my.cnf(或者my.ini),我的在/etc/my.cnf,在[mysqld]部分插入如下:

#開啟中繼日誌 relay-log=mysql-relay #設定server-id,建議使用ip最後3位 server-id=141

  • 重啟mysql服務

systemctl restart mysqld.service

2.6 在主機上建立賬戶並授權slave

GRANT REPLICATION SLAVE ON *.* TO 'mysql141'@'192.168.131.141' IDENTIFIED BY 'mysql141';

flush privileges;

--查詢master的狀態 show master status\G

記錄上圖結果中File和Position的值。  注意:執行完此步驟後不要再操作主伺服器MySQL,防止主伺服器狀態發生狀態值變化。

2.7 告知從伺服器二進位制檔名與位置

這裡要根據上面主伺服器的狀態來填寫,不要直接用下面的SQL,需要根據實際值修改。

CHANGE MASTER TO master_host = '192.168.131.140',  master_user = 'mysql141',  master_password = 'mysql141',  master_log_file = 'mysql-bin.000001',  master_log_pos = 120;

2.8 檢視從伺服器狀態

//開啟複製 start slave;

//檢視主從複製是否配置成功 SHOW SLAVE STATUS\G

當看到Slave_IO_State:Waiting for master ot send event 、Slave_IO_Running: YES、Slave_SQL_Running: YES才表明狀態正常。

2.9 測試主從複製是否成功

  • Master中和Slave中執行SQL

 SHOW DATABASES;

  • 在Master中建立資料庫並建立資料表並插入一條資料

create database test; use test; create table tab1(id int auto_increment,name varchar(10),primary key(id)); insert into tab1(id,name) values (1,'why');

  • 在Slave中查詢這條資料
  •  

至此,MySQL主從複製就實現了。

2.10 常用語句

show master status: 檢視master的狀態,尤其是當前的日誌及位置 show slave status 檢視slave的狀態 reset slave 重置slave狀態 start slave 啟動slave狀態 stop slave 暫停slave狀態

3. 讀寫分離實踐

  絕大多數的企業的應用場景對於資料庫來說都是讀多寫少,比如微博,明星發一條微博,上千萬人讀。所以為了分擔資料庫壓力,做負載均衡,首先考慮到的就是讀寫分離,讀寫分離基於上面實現的主從複製,使用主庫作為寫庫,從庫為讀庫,提高資料庫效能,提高IO效能。

3.1 讀寫分離的實現方式

  為了實現讀寫分離,出現了很多解決方案,其中比較流行的是採用中介軟體做為Proxy,保持應用層程式碼不隨資料庫的變動而發生變化,這裡包括Amoeba、Atlas、Cobar、Mycat、MySQL Proxy等,而Mycat是目前開源的資料庫中介軟體中比較成熟的解決方案。可以說Mycat真的非常強大,但是建議慎重考慮使用,具體原因請自行百度mycat發起人和Mycat社群現狀。    但我們以學習的目的進行使用還是非常好的,Mycat確實非常強大,我們可以學習他的思想和技術。所以我們使用Mycat中介軟體作為讀寫分離的實現方式。    《Mycat權威指南》和《分散式資料庫架構及企業實踐-基於mycat中介軟體》兩本書都介紹的非常詳細。

3.2 使用Mycat實現讀寫分離

3.2.1 下載安裝Mycat

原文連結:https://www.cnblogs.com/joylee/p/7513038.html

  • Mycat官網:http://www.mycat.io/ 可以瞭解下Mycat的背景和應用情況,這樣使用起來比較有信心。
  • Mycat下載地址:http://dl.mycat.io/ 官網有個文件,屬於詳細的介紹,初次入門,看起來比較花時間。

下載:  建議大家選擇 1.6-RELEASE 版本,畢竟是比較穩定的版本。

安裝:  根據不同的系統選擇不同的版本。包括linux、windows、mac,作者考慮還是非常周全的,當然,也有原始碼版的。 

Mycat的安裝其實只要解壓下載的目錄就可以了,非常簡單。 安裝完成後,目錄如下:

配置  Mycat的配置檔案都在conf目錄裡面,這裡介紹幾個常用的檔案:

Mycat的架構其實很好理解,Mycat是代理,Mycat後面就是物理資料庫。和Web伺服器的Nginx類似。對於使用者來說,訪問的都是Mycat,不會接觸到後端的資料庫。  我們現在做一個主從、讀寫分離,簡單分表的示例。結構如下圖:      Mycat作為主資料庫中介軟體,肯定是與程式碼弱關聯的,所以程式碼是不用修改的,使用Mycat後,連線資料庫是不變的,預設埠是8066。連線方式和普通資料庫一樣,如:jdbc:mysql://192.168.0.2:8066/。

3.2.2 配置Mycat

  我們只針對mycat實現簡單的讀寫分離,更多其他特性如分庫分表切片的功能請參看上面推薦的書,這裡只針對簡單的讀寫分離的配置。    我們真實的物理資料庫名稱為 itoo_cloud,包含一個表 ta_user,以免大家對後面的配置不明白。

  • server.xml

    <user name="root">         <property name="password">root</property>         <property name="schemas">itoo</property>         <property name="readOnly">false</property>         <!-- 表級 DML 許可權設定 -->         <!--                 <privileges check="false">             <schema name="TESTDB" dml="0110" >                 <table name="tb01" dml="0000"></table>                 <table name="tb02" dml="1111"></table>             </schema>         </privileges>                 -->     </user>

重點關注下面這段,其他預設即可 

我這裡配置了一個賬號root密碼也是root,針對邏輯資料庫itoo(自己定義別名,不是真實的物理資料庫),讀寫許可權都有,沒有針對表做任何特殊的許可權。

  • schema.xml 

schema.xml是最主要的配置項,首先看我的配置檔案。

<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="itoo" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>

    <dataNode name="dn1" dataHost="auth" database="itoo_cloud" />

    <dataHost name="auth" maxCon="1000" minCon="10" balance="3"               writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">         <heartbeat>select user()</heartbeat>         <writeHost host="hostM" url="192.168.131.140:3306" user="root" password="root">             <readHost host="hostS1" url="192.168.131.141:3306" user="test" password="test" />         </writeHost>     </dataHost> </mycat:schema>

注意:讀庫的使用者test是新增的mysql使用者,只具有讀許可權的使用者:

GRANT Select ON *.* TO 'test'@'%' IDENTIFIED BY "test"

下面是關於每個節點的配置說明; 

3.2.3 啟動mycat

Mycat的啟動也非常簡單,進入到bin目錄下:

##啟動 ./mycat start

##停止 ./mycat stop

##重啟 ./mycat restart

如果在啟動時發現異常,在logs目錄中檢視日誌。

  • wrapper.log 為程式啟動的日誌,啟動時的問題看這個
  • mycat.log 為指令碼執行時的日誌,SQL指令碼執行報錯後的具體錯誤內容,檢視這個檔案。mycat.log是最新的錯誤日誌,歷史日誌會根據時間生成目錄儲存。

mycat啟動後,執行命令不成功,可能實際上配置有錯誤,導致後面的命令沒有很好的執行。

3.3 測試讀寫分離

使用navicat連線mycat,如下圖所示,注意埠為8066。 

  • 測試寫,插入一條資料,檢視是否成功,檢視從庫是否資料已經同步過去
  • 測試讀,這裡為了確保讀的是從庫,我們用root賬號登入從庫,將剛才插入的資料name值改為別的,然後再次執行查詢,看查詢出的資料是否為從庫的資料。(因為此時主庫的name值為原來insert的,而從庫的改為了別的)。

---------------------