1. mycat簡介
mycat是一個開源數據庫中間件;它可以管理你的所有數據庫,並對他們進行讀寫分離,分庫分表等。
使用起來的話Mycat就是一個近似於MySQL的數據庫服務器,你可以用連接MySQL的方式去連接Mycat(除了端口不同,默認的Mycat端口是8066而非MySQL的3306),大多數情況下,可以用你熟悉的對象映射框架比如MyBatis操作Mycat。
它最主要的兩個功能就是:
- 數據庫的讀寫分離
- 分庫分表
2. 下載mycat
mycat的官網:https://github.com/MyCATApache/Mycat-Server
可以從這裏去下載,我下載的是1.6版本的
下載後,直接解壓
tar –zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
然後進入bin目錄,執行以下命令就可以啓動了
./mycat start
MyCat關閉命令:
./mycat stop
登錄mycat:用類似mysql的登錄方式就可以登錄了,初始賬號下面會有說明
mysql -uroot -p -P8066 -h127.0.0.1
mycat默認數據訪問端口是8066
3. 配置文件
其實進行讀寫分離 我們只需要配置2個文件就可以使用了,進入conf文件夾:
- server.xml:系統配置,比如用戶,白名單等
- schema.xml: 配置關聯的數據庫,在這裏面做讀寫分離,分庫分表等操作
3.1 server.xml講解
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="useSqlStat">0</property> <!-- 1爲開啓實時統計、0爲關閉 -->
<property name="useGlobleTableCheck">0</property> <!-- 1爲開啓全加班一致性檢測、0爲關閉 -->
<!-- 指定使用Mycat全局序列的類型:即數據庫主鍵的生成方式
0爲本地文件方式,1爲數據庫方式,2爲時間戳序列方式。
對於讀寫分離而言,是不需要考慮主鍵生成方式的,也就是不需要配置全局序列號的。 -->
<property name="sequnceHandlerType">2</property>
<property name="processorBufferPoolType">0</property>
<property name="handleDistributedTransactions">0</property>
<property name="useOffHeapForMerge">1</property>
<property name="memoryPageSize">1m</property>
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<property name="systemReserveMemorySize">384m</property>
<property name="useZKSwitch">true</property>
</system>
<!-- 全局SQL防火牆設置 -->
<!--
<firewall>
<whitehost>
<host host="127.0.0.1" user="mycat"/>
<host host="127.0.0.2" user="mycat"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<!-- 設置連接mycat時的用戶名和密碼, 邏輯庫
邏輯庫是指一個虛擬的數據庫,通過這個虛擬的數據庫去管理多個真實的數據庫
我這裏創建了一個用戶名爲mycat,密碼爲123456的賬號,該用戶可以連接到mycatdb這個邏輯數據庫
-->
<user name="mycat">
<property name="password">123456</property>
<property name="schemas">mycatdb</property>
</user>
<!-- root和user賬號都是默認生成的,所以一開始什麼都不設置的情況下,可以通過這兩個賬號登錄mycat
注意修改一下屬性爲schemas的值,默認是TESTDB,但是我們沒有在schema.xml文件中配置這個邏輯數據庫,所以啓動時就會報錯,
所以我們這裏將這兩個默認賬號的schemas都設置爲mycatdb
-->
<user name="root">
<property name="password">123456</property>
<property name="schemas">mycatdb</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>
<user name="user">
<property name="password">user</property>
<property name="schemas">mycatdb</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
其實在這個文件中,我們只是新增了一個mycat賬號,並且把所有用戶的邏輯數據庫全部改爲了mycatdb,接下來我們就要去創建邏輯數據庫mycatdb了。
3.2 schema.xml解讀
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 這裏設置邏輯數據庫
name:指定邏輯數據庫的名字
dataNode: 指向下面dataNode的name屬性,進行關聯-->
<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<!--只做讀寫分離,不做分庫分表,Mycat只是幫我們轉發一下請求,讀轉發到從庫,寫轉發到主庫,則schema標籤裏面不用配置table-->
</schema>
<!-- dataNode表示數據分片,可以理解成一個真實數據庫在多個msql中的集合
database:表示真實數據庫,設置爲你想進行讀寫分離的那個數據庫,這裏我是要對tfp這個數據庫進行讀寫分離
dataHost: 指向下面dataHost的name屬性值 -->
<dataNode name="dn1" dataHost="localhost1" database="tfp" />
<!-- 可以添加多個dataNode標籤,來對不同數據庫進行讀寫分離 -->
<!-- dataHost表示真實的mysql實例,需要配置真實的mysql實例列表
balance:負載均衡類型,目前的取值有4種:
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設置爲1
switchType:用於指定主服務器發生故障後的切換類型。
-1 表示不自動切換
1 默認值,自動切換(推薦)
2 基於MySQL主從同步的狀態決定是否切換
3 基於MySQL galary cluster的切換機制(適合集羣)(1.4.1)
通常情況下,我們MySQL採用雙主雙從的模式下,switchType爲1即可。因爲雙主從模式下,主從同步關係很複雜,不能根據MySQL的狀態來切換。只需要在一個主出問題後,切換到另外的主。
-->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!-- heartbeat:用於和後端數據庫進行心跳檢查的語句,檢測MySQL數據庫是否正常運行。
當switchType爲1時,mysql心跳檢查語句是select user()。
當switchType爲2時,mysql心跳檢查語句是show slave status。
當switchType爲3時,mysql心跳檢查語句是show status like 'wsrep%'。 -->
<heartbeat>select user()</heartbeat>
<!--writeHost: 指定寫實例(主)
host屬性可以隨便寫
user和password表示真實數據庫的用戶名密碼-->
<writeHost host="hostM3339" url="127.0.0.1:3339" user="root"
password="123456">
<!-- 指定讀實例(從) -->
<readHost host="hostS3340" url="127.0.0.1:3340" user="root" password="123456" />
<readHost host="hostS3341" url="127.0.0.1:3341" user="root" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
我的數據庫格式如下:
dataNode標籤中的database屬性指的就是真實tfp數據庫。
然後在dataHost中配置,tfp數據庫所在的所有真實mysql數據庫實例列表,即一主兩從的3個數據庫實例
4. 啓動測試
啓動mycat,然後進入客戶端進行操作增刪改查
mysql -umycat -p -P8066 -h127.0.0.1
show databases;
use mycatdb;
show tables;
當執行show databases;命令時可以看出來,它裏面存放的其實就是mycatdb這個邏輯數據庫。
這裏還有一個問題:
如果進行正常的操作增刪改查,其實看不出來到底是不是讀寫分離了,因爲3個數據庫的數據始終是一樣的。
做法:可以對兩個slaver從數據庫中的user表中的數據進行略微的修改(不要進行增刪操作,否則可能會出問題),比如修改一條記錄的值。最後進行查找操作,查看數據是從哪個數據庫中查出來的。
使用navicat連接bug:
使用navicat 12連接mycat時提示表不存在,
解決方案:使用低版本的navicat
5. java代碼實現讀寫分離
使用springboot +mybatis的方式連接mycat進行讀寫分離
源碼地址:https://gitee.com/tfp-study/mycat-read-write-split
其實和普通的項目沒有什麼區別,該怎麼做還是怎麼做,只是修改一下數據庫連接時的url,username,password
遇到一個bug,啓動報錯:
java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
解決辦法:
將數據庫連接版本降低成5.1.37
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
<scope>runtime</scope>
</dependency>
驅動使用:spring.datasource.driver-class-name=com.mysql.jdbc.Driver即可