本文作者:藍雄威,叩丁狼高級講師。原創文章,轉載請注明出處。
01前言
在上一篇文章中,我們基于CentOS7實現了MySQL的主從復制,我們需要把DML操作放在MySQL的主節點執行,需要把DQL操作放在MySQL的從節點執行.那在應用程序中我們怎么控制這個邏輯呢?
下面是一種可行的方案:
1.在項目中配置兩個數據源(一主一從),分別是A(主)和B(從)。
2.在程序中判斷是不是select操作,如果是就把數據源更換成B,如果不是select操作就更換成A,這樣就可以實現程序中的讀寫分離了.
3.關于步驟2的更換數據源,Spring中是提供了AbstarctRoutingDataSource
這個類在程序中實現數據源的切換的.
這種方案可行是可行,但是在應用程序端需要寫挺多代碼的,而且這些屬于非業務層面的東西,寫在項目中對項目來說是代碼侵入了.
所以對于讀寫分離我們可以使用Mycat數據庫中間件來完成.
02MyCat介紹
關于MyCat的詳細簡介,同學們可以去Mycat官網.下載Mycat權威指南.pdf
來看,文章中的前世今生寫得幽默有趣,挺有意思的,從描述來看都感覺看的不是本技術書,而是本小說哈.在這里我簡單的介紹一下Mycat:
2008年阿里開源了一款數據庫中間件Amoeba,隨著業務的增長,這塊產品不能支持目前已有的業務.阿里又開源了Cobar這款中間件,這款產品在阿里內部得到了很廣泛的應用.(應用在了3000多臺服務器,每天超過10億次的數據庫訪問),當時一開源就得到了開發者和運維人員的追捧. 開源之后,阿里就沒有對這款產品維護了,這款產品在生產環境中還是存在挺多問題的.在這樣的場景下MyCat誕生了,2013年MyCat社區在Cobar的基礎上進行了很大的改造和升級.
03Mycat優勢
優勢這個我就從官網上給同學們摘抄下來了:
基于阿里開源的Cobar產品而研發,Cobar的穩定性、可靠性、優秀的架構和性能以及眾多成熟的使用案例使得MYCAT一開始就擁有一個很好的起點,站在巨人的肩膀上,我們能看到更遠。業界優秀的開源項目和創新思路被廣泛融入到MYCAT的基因中,使得MYCAT在很多方面都領先于目前其他一些同類的開源項目,甚至超越某些商業產品。
MYCAT背后有一支強大的技術團隊,其參與者都是5年以上軟件工程師、架構師、DBA等,優秀的技術團隊保證了MYCAT的產品質量。
MYCAT并不依托于任何一個商業公司,因此不像某些開源項目,將一些重要的特性封閉在其商業產品中,使得開源項目成了一個擺設。
目前也有挺多公司在生產環境上使用Mycat的,使用案例,所以來說還是一款很不錯,很穩定的產品.
04主要作用
主要作為分布式數據庫系統的中間層
1.可以實現數據庫的讀寫分離
2.支持負載均衡
3.支持后端MySQL高可用
4.數據庫的垂直拆分
5.數據庫水平拆分
關于Mycat如何實現數據庫的分庫分表,我在之前的簡書中已經寫了案例,數據庫中間件Mycat+SpringBoot完成分庫分表.
05Mycat的基本概念
從上圖可以看到,我們應用程序不是直接連接真實數據庫的的,而是連接Mycat的.所以在Mycat的配置文件中我們就需要去定義
邏輯庫
、邏輯表
和真實庫
、真實表
的映射關系
06安裝JDK環境變量
0.我們Mycat的安裝是基于CentOS7環境來安裝的,所以同學們先把基礎環境搭建好哈.
1.Mycat是基于Java開發的一款中間件產品,所以要使用Mycat前需要把JDK的環境裝上.JDK1.8安裝包.
2.下載好jdk1.8安裝包后,通過工具上傳到服務器上.我們通常會把文件上傳到/usr/local/software
目錄下
3.然后使用解壓命令解壓到
/usr/local
目錄下
tar -zxvf jdk-8u161-linux-x64.tar.gz -C /usr/local
但是名字有些長,不方便我們設置環境變量,所以我們可以對這個文件夾重命名
mv jdk1.8.0_161/ jdk1.8
4.jdk解壓好之后,我們就可以來配置環境變量了.
vi /etc/profile
編輯界面如下:
需要在這個文件中添加這兩行配置:
export JAVA_HOME=/usr/local/jdk1.8
export PATH=.:$JAVA_HOME/bin:$PATH
編輯后如下圖所示:
然后保存退出即可.
然后需要通過這個命令來重新加載配置文件:
source /etc/profile
設置好之后,通過這個命令查看環境變量是否配置好了.
java -version
如果看到下面這個內容,說明已經配置好了.
07安裝Mycat
我們這次使用的是Mycat-server-1.6.7版本,下載好之后上傳到服務器上.
然后使用命令進行解壓
tar -zxvf Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz -C /usr/local/
這樣我們就已經裝好Mycat了,下一步就需要去配置Mycat的配置文件了.
08配置讀寫分離
我們可以先看看Mycat的文件目錄結構
bin目錄
:存放Mycat運行的腳本conf目錄
:存放Mycat的配置文件logs目錄
:存放Mycat啟動及運行的日志文件我們現在需要進入到
conf目錄
,修改配置文件.目前來說,我們只需要關心
server.xml
、schema.xml
、rule.xml
這三個文件.server.xml
:主要配置Mycat的啟動參數,連接密碼,白名單,黑名單,訪問權限控制等參數,我們暫時不修改,用默認的就可以了.schema.xml
:主要配置邏輯庫、邏輯表和真實庫、真實表之間的映射關系.rule.xml
:主要配置分庫分表時的分片規則,此次試驗中我們并不需要修改到.目前我們的環境是這樣的:
主機IP | 角色 |
---|---|
192.168.142.128 | MySQL主節點 |
192.168.142.129 | MySQL從節點 |
192.168.142.130 | MyCat服務器 |
然后我們需要修改schema.xml
文件,修改內容如下(建議直接復制我的,然后把Ip換一下就好了.):
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_order" dataNode="dn01"/>
</schema>
<dataNode name="dn01" dataHost="dh01" database="hello" />
<dataHost name="dh01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.142.128" url="192.168.142.128:3306" user="root" password="WolfCode_2017">
<readHost host="192.168.142.129" url="192.168.142.129:3306" user="root" password="WolfCode_2017"></readHost>
</writeHost>
<writeHost host="192.168.142.129" url="192.168.142.129:3306" user="root" password="WolfCode_2017"></writeHost>
</dataHost>
</mycat:schema>
一、schema 解釋
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
name屬性
:表示的是邏輯庫的名字,是應用程序連接的時候的數據庫名稱.
checkSQLschema屬性
:當該值設置為 true 時,如果我們執行語句select * from TESTDB.travelrecord;則 MyCat 會把語句修改
為select * from travelrecord;。即把表示 schema 的字符去掉,避免發送到后端數據庫執行時報(ERROR
1146 (42S02): Table ‘testdb.travelrecord’ doesn’t exist)。
不過,即使設置該值為 true ,如果語句所帶的是并非是 schema 指定的名字,例如:select * from
db1.travelrecord; 那么 MyCat 并不會刪除 db1 這個字段,如果沒有定義該庫的話則會報錯,所以在提供 SQL
語句的最好是不帶這個字段。
sqlMaxLimit屬性
:當該值設置為某個數值時。每條執行的 SQL 語句,如果沒有加上 limit 語句,MyCat 也會自動的加上所對應
的值。例如設置值為 100,執行select * from TESTDB.travelrecord;的效果為和執行select * from
TESTDB.travelrecord limit 100;相同。
設置該值的話,MyCat 默認會把查詢到的信息全部都展示出來,造成過多的輸出。所以,在正常使用中,還
是建議加上一個值,用于減少過多的數據返回。
當然 SQL 語句中也顯式的指定 limit 的大小,不受該屬性的約束。
需要注意的是,如果運行的 schema 為非拆分庫的,那么該屬性不會生效。需要手動添加 limit 語句
二、table標簽解釋
<table name="t_order" dataNode="dn01"/>
Table 標簽定義了 MyCat 中的邏輯表,所有需要拆分的表都需要在這個標簽中定義。
name 屬性
:定義邏輯表的表名,這個名字就如同我在數據庫中執行 create table 命令指定的名字一樣,同個 schema 標
簽中定義的名字必須唯一。
dataNode屬性
:定義這個邏輯表所屬的 dataNode, 該屬性的值需要和后面 dataNode 標簽中 name 屬性的值相互對應。
三、dataNode標簽解釋
<dataNode name="dn01" dataHost="dh01" database="hello" />
dataNode 標簽定義了 MyCat 中的數據節點,也就是我們通常說所的數據分片。一個 dataNode 標簽就是一個獨立的數據分片。
name 屬性
:定義數據節點的名字,這個名字需要是唯一的,我們需要在 table 標簽上應用這個名字,來建立表與分片對
應的關系。
dataHost 屬性
:該屬性用于定義該分片屬于哪個數據庫實例的,屬性值是引用 dataHost 標簽上定義的 name 屬性。
database 屬性
:該屬性用于定義該分片屬性哪個具體數據庫實例上的具體庫,因為這里使用兩個緯度來定義分片,就是:實例+具體的庫。因為每個庫上建立的表和表結構是一樣的。所以這樣做就可以輕松的對表進行水平拆分。
四、dataHost標簽解釋
<dataHost name="dh01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
作為 Schema.xml 中最后的一個標簽,該標簽在 mycat 邏輯庫中也是作為最底層的標簽存在,直接定義了具
體的數據庫實例、讀寫分離配置和心跳語句。
name 屬性
:唯一標識 dataHost 標簽,供上層的標簽使用
maxCon 屬性
:指定每個讀寫實例連接池的最大連接。也就是說,標簽內嵌套的 writeHost、readHost 標簽都會使用這個屬
性的值來實例化出連接池的最大連接數
minCon 屬性
:指定每個讀寫實例連接池的最小連接,初始化連接池的大小
balance 屬性
:
負載均衡類型,目前的取值有 3 種:
- balance="0", 不開啟讀寫分離機制,所有讀操作都發送到當前可用的 writeHost 上。
- balance="1",全部的 readHost 與 stand by writeHost參與 select 語句的負載均衡,簡單的說,當雙
主雙從模式(M1->S1,M2->S2,并且 M1 與 M2 互為主備),正常情況下,M2,S1,S2 都參與 select 語句的負載
均衡。 - balance="2",所有讀操作都隨機的在 writeHost、readhost 上分發。
- balance="3",所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,writerHost 不負擔讀壓力,
注意 balance=3 只在 1.4 及其以后版本有,1.3 沒有。
writeType 屬性
:
負載均衡類型,目前的取值有 3 種:
- writeType="0", 所有寫操作發送到配置的第一個 writeHost,第一個掛了切到還生存的第二個 writeHost,
重新啟動后已切換后的為準,切換記錄在配置文件中:dnindex.properties .
2.writeType="1",所有寫操作都隨機的發送到配置的 writeHost,1.5 以后廢棄不推薦。switchType 屬
性
- -1 表示不自動切換。
- 1 默認值,自動切換。
- 2 基于 MySQL 主從同步的狀態決定是否切換。
dbType 屬性
:指定后端連接的數據庫類型,目前支持二進制的 mysql 協議,還有其他使用 JDBC 連接的數據庫。例如:
mongodb、oracle、spark 等。
dbDriver 屬性
:指定連接后端數據庫使用的 Driver,目前可選的值有 native 和 JDBC。使用 native 的話,因為這個值執行的
是二進制的 mysql 協議,所以可以使用 mysql 和 maridb。其他類型的數據庫則需要使用 JDBC 驅動來支持。
從 1.6 版本開始支持 postgresql 的 native 原始協議。
如果使用 JDBC 的話需要將符合 JDBC 4 標準的驅動 JAR 包放到 MYCAT\lib 目錄下,并檢查驅動 JAR 包中
包括如下目錄結構的文件:META-INF\services\java.sql.Driver。在這個文件內寫上具體的 Driver 類名,例如:
com.mysql.jdbc.Driver。
五、heartbeat標簽解釋
<heartbeat>select user()</heartbeat>
這個標簽內指明用于和后端數據庫進行心跳檢查的語句。例如,MYSQL 可以使用 select user(),Oracle 可以
使用 select 1 from dual 等。
六、writeHost 標簽、readHost 標簽解釋
這兩個標簽都指定后端數據庫的相關配置給 mycat,用于實例化后端連接池。唯一不同的是,writeHost 指定寫實例、readHost 指定讀實例,組著這些讀寫實例來滿足系統的要求。在一個 dataHost 內可以定義多個 writeHost 和 readHost。但是,如果 writeHost 指定的后端數據庫宕機,那么這個 writeHost 綁定的所有 readHost 都將不可用。另一方面,由于這個 writeHost 宕機系統會自動的檢測到,并切換到備用的 writeHost 上去。
host 屬性
:用于標識不同實例,一般 writeHost 我們使用M1,readHost 我們用S1。
url 屬性
:后端實例連接地址,如果是使用 native 的 dbDriver,則一般為 address:port 這種形式。用 JDBC 或其他的
dbDriver,則需要特殊指定。當使用 JDBC 時則可以這么寫jdbc:mysql://localhost:3306/。
user 屬性
:后端存儲實例需要的用戶名字。
password 屬性
:后端存儲實例需要的密碼。
08啟動Mycat
使用命令
/usr/local/mycat/bin/mycat start
然后觀察wrapper.log文件看是否已經啟動成功.
出現這樣的界面說明已經啟動成功.可以通過Navicat客戶端連接Mycat,或者通過應用程序連接也是可以的.
如果需要修改默認端口或者默認密碼的話需要修改server.xml文件.在應用程序中連接的時候,和之前連接MySQL一樣的.只是URL地址不一樣而已,代碼還是一樣的.
09其他
目前我們連接Mycat之后,所有的讀操作都是走從節點的,如果有需求需要讀走主節點的話,可以使用Mycat中的注解,強制讓讀操作走主節點.
/*#mycat:db_type=master*/ 真實SQL