一直對Mysql分庫分表有點興趣,但是也一直停留在有興趣的階段,沒有遇到能應用的場景。人生苦短,與其等一個機會,不如自己創造吧。稍微調研了下,選擇使用 Mycat 這樣一款開源產品。沒有什麼特別的理由,也不去討論挖掘機哪家強,只是為了學習。
本機環境
電腦環境:Ubuntu 16.04
JDK:1.8
Docker version 1.11.2
Mysql 5.7.13
Mycat 1.5-RELEASE
Navicat for Mysql
安裝Mysql
為了測試方便,Mysql都跑在Docker上,關於Docker環境的安裝這裡就不說了,參照 Daocloud 。Docker成功安裝之後,去DaoCloud鏡像下載Mysql鏡像 docker pull daocloud.io/library/mysql:5.7.13 ,下載完畢之後命令行執行 sudo docker images 確認下,輸出如下:
上圖的兩個鏡像分別是Mysql和Daocloud工具包,暫時用不到其他鏡像,這樣就可以了。
因為肯定要用到多個mysql,所以下面先啟動兩個mysql服務,測試下環境:
sudo docker run --name mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=bboyjing -d daocloud.io/library/mysql:5.7.13
sudo docker run --name mysql2 -p 3316:3306 -e MYSQL_ROOT_PASSWORD=bboyjing -d daocloud.io/library/mysql:5.7.13
命令行輸入 sudo docker ps -a ,輸出如下,啟動正常
本機安裝Mysql客戶端
本機只需要連接到服務端Mysql,所以只安裝個客戶端就可以了,命令行執行 sudo apt-get install mysql-client ,安裝完畢之後測試下,命令行執行 mysql -h127.0.0.1 -P3306 -uroot -pbboyjing 、 mysql -h127.0.0.1 -P3316 -uroot -pbboyjing ,兩個都能連接上表示環境正常。
安裝Navicat
圖形界面的展示可能方便點,所以裝個Navicat備用,直接 官網 下載就可以了,至於破解什麼的,自己看著辦。安裝成功之後分別連上localhost的3306、3316端口測試下。
安裝Mycat
Github 下載對應系統版本,解壓即可,目錄結構如下:
bin目錄:存放執行腳本的命令
catlet目錄:自定義分片規則存放路徑
conf目錄:存放各種配置文件
lib目錄:存放Mycat依賴的一些jar包
logs目錄:日志目錄
下面到Mycat根目錄下執行下bin目錄的啟動腳本試試看,要先安裝jdk,這個就不說了。控制台執行 sudo ./bin/mycat console ,輸出如下,表示正常啟動
若已經安裝過jdk的情況下,出現Unable to start JVM: No such file or directory,可能是JAVA環境變量不在root用戶下導致的,嘗試下如下方法,若還是不成功,應該不會的。
cd /opt
sudo chmod -R 777 mycat
./bin/mycat console
至此,簡單的可運行的Mycat環境搭建完畢,稍微了解下Mycat,簡單的來說它就是一個攔截在數據庫前面的代理,數據庫訪問請求先經過Mycat,然後根據分片規則分發到具體的主機來實現分庫分表等功能
先看一下Mycat裡幾個重要的概念
用戶
邏輯庫(schema)
邏輯表(table)
分片節點(dataNode)
分片規則(rule)
全局序列號(sequence)
下面就逐個來講講,想一個場景,然後把配置都配好,最終要完整的運行起來。
用戶
用戶相關配置位於conf/server.xml中,server.xml包含了整個Mycat Server的配置情況,這裡只截取針對性的內容來看下
<username="root">
<propertyname="password">bboyjing</property>
<propertyname="schemas">OrderDB</property>
<!-- <property name="readOnly">true</property> -->
</user>
上述配置定義了連接Mycat Server的用戶名和密碼,以及能夠訪問的schema(schema下面再講解),如果是只讀用戶可以加上readOnly屬性為true。下面就把原有的user標簽修改為上述內容。
邏輯庫(schema)
schema的概念和Mysql中的DataBase概念是一樣的,這樣就容易理解了。其相關配置位於conf/schema.xml中,user標簽中的schemas屬性指向的就是schema標簽的name屬性。下面看下schema標簽的內容:
<schemaname="OrderDB"checkSQLschema="false"sqlMaxLimit="100">
</schema>
schema標簽有四個屬性
name:schema的名稱相當於數據庫的名稱
dataNode:schema所在的分片(dataNode下面講解),其實就是物理數據庫。不過直接在schema上定義dataNode會略顯粗糙,可能更多的還是由各個表自己定義分片規則來路由到相應的dataNode。
checkSQLschema:當設置為true時,如果執行 select * from OrderDB.order ,Mycat會把語句修改為 select * from order ,即把表示schema的字符刪掉,比較好的做法是關掉這個驗證,發送SQL時不要帶schema。
sqlMaxLimit:當設置為某個數值時,即使執行SQL沒有加上limit,Mycat也會自動加上對應的值。當SQL語句中指定了limit時,不受該值約束。官方文檔上還說如果運行的schema為非拆分庫的話,該屬性不會生效,所以寫SQL時還是嚴謹點好,該查多少條自己控制。
邏輯表(table)
table就是對應Mysql中的表,table標簽是schema的子標簽,所以依然是修改conf/schema.xml。
<schemaname="OrderDB"checkSQLschema="false"sqlMaxLimit="100">
<tablename="order"dataNode="dn1,dn2"rule="mod-long"/>
</schema>
table標簽有九個屬性
name:對應Mysql中的表名
dataNode:邏輯表所在的分片,該屬性值需要和dataNode標簽的name屬性對應,dateNode標簽下面會講解
rule:邏輯表使用的分片規則名稱,規則在conf/rule.xml中配置,該屬性值必須與tableRule標簽中的name屬性對應
ruleRequired:是否綁定分片規則,如果為true的話,就一定要配置rule
primaryKey:邏輯表對應真實表的主鍵
type:邏輯表類型,分為全局表和普通表,後面寫例子時再詳細說明該屬性
autoIncrement:是否啟用自增主鍵,對應Mysql自增主鍵,默認時禁用的
subTable:分表,1.6以後開始支持
needAddLimit:是否允許自動添加schema標簽中設置的limit,默認為true
table標簽下還有個childTable子標簽,用於定義E-R分片的字表,所謂E-R分片就是把兩個有關系的路由到同一個分片,方便join操作,具體配置後面寫示例時再看。
分片節點(dataNode)
dataNode定義了Mycat中的數據節點,也就是通常說的數據分片,其實就是指向了具體的數據庫地址和名稱。
dataNode標簽和schema同級,依然修改conf/schema.xml
<dataNodename="dn1"dataHost="dockerhost1"database="order_db"/>
<dataNodename="dn2"dataHost="dockerhost2"database="order_db"/>
dataNode標簽有三個屬性
name:分片名稱,全局唯一
dataHost:數據庫實例地址,對應dataHost標簽的name屬性(下面講解)
dataBase:對應數據庫實例上的具體數據庫,要預先建好
節點主機(dataHost)
dataHost標簽定義了具體的數據庫實例、讀寫分離配置和心跳語句。
dataHost標簽和schema同級,依然修改conf/schema.xml。
<dataHostname="dockerhost1"maxCon="1000"minCon="10"balance="0"
writeType="0"dbType="mysql"dbDriver="native"switchType="1">
<heartbeat>select user()</heartbeat>
<writeHosthost="hostM1"url="localhost:3306"user="root"password="bboyjing">
</writeHost>
</dataHost>
<dataHostname="dockerhost2"maxCon="1000"minCon="10"balance="0"
writeType="0"dbType="mysql"dbDriver="native"switchType="1">
<heartbeat>select user()</heartbeat>
<writeHosthost="hostM1"url="localhost:3316"user="root"password="bboyjing">
</writeHost>
</dataHost>
dataHost標簽有9個屬性
name:節點主機名稱
maxCon:指定每個讀寫實例連接池的最大連接
minCon:指定每個讀寫實例連接池的最小連接,即初始化連接池的大小
balance:讀操作負載均衡類型,目前有三個可選值”0”、”1”、”2”、”3”。讀寫分離相關策略,後面再詳細講,例子中的”0”代表不開啟讀寫分離,讀操作都發到writeHost上
writeType:寫操作負載均衡類型,目前有三可選值”0”、”1”、”2”,具體後面再看,例子中的”0”表示所有寫操作發送到第一個writeHost,第一個掛了切換到還生存的第二個writeHost。
dbType:指定連接的數據庫類型,目前支持二進制的Mysql協議,還有其他的JDBC連接的數據庫。例如mongodb、oracle、spark等
dbDriver:指定連接數據庫的驅動,目前可選指為native和JDBC。native支持mysql和mariadb,其他數據庫需要用JDBC驅動
switchType:自動切換標識,”1”為默認值,表示不自動切換,其他可選指為”1”、”2”,暫不展開
tempReadHostAvailable:writeHost失聯後,其下面的readHost仍舊可用,默認0,可選值0、1
分片規則(rule)
分片規則位於conf/rule.xml中,其中定義了我們對表進行拆分所涉及到的規則定義,
<tableRulename="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<functionname="mod-long"class="org.opencloudb.route.function.PartitionByMod">
<!-- how many data nodes -->
<propertyname="count">2</property>
</function>
tableRule標簽
name屬性:指定rule全局唯一的名字
columns標簽:拆分的列的名字
algorithm標簽:指向function標簽的name屬性,表示具體的算法
function標簽
name屬性:指定算法名稱
class屬性:指定路由算法具體的類名
property標簽:定義了算法具體的規則,此算法的含義是根據id mod2將數據路由到兩個分片上。Mycat定義了一些算法規則,後面再講
啟動Docker中的兩台Mysql容器
#因為之前已經啟動過容器,如果沒有主動刪除過,先查看下其狀態
sudo docker ps -a
#若容器處於Exited狀態下,將其啟動即可(示例是本人自己的CONTAINER ID)
sudo docker start d1f418414648
sudo docker start 9d9674cc4fa7
連接兩台Mysql並分別新建數據庫order_db
mysql -h127.0.0.1 -P3306 -uroot -pbboyjing
create database order_db;
exit
mysql -h127.0.0.1 -P3316 -uroot -pbboyjing
create database order_db;
exit
啟動Mycat
#進入Mycat安裝目錄
cd /opt/mycat
#啟動Mycat
bin/mycat start
通過Mysql客戶端連接Mycat
#查看啟動日志(出現connected successfuly MySQLConnection表示啟動成功)
vim logs/mycat.log
#由日志可以看出Mycat端口為8066和9066,其中8066為數據端口、9066為管理端口
#下面我們通過server.xml中配置的用戶來連接Mycat,出現mysql交互界面表示連接成功
mysql -h127.0.0.1 -P8066 -uroot -pbboyjing
#查看databases
mysql> show databases;
+----------+
| DATABASE |
+----------+
| OrderDB |
+----------+
#出現的是server.xml中配置的邏輯庫(schema)
到此表示Mycat服務正常啟動,並且通過Mysql客戶端可以連通,上面最後一步show databases的結果如下圖所示:
設計Order表
簡單地設計一張order表,位於order_db庫中,表結構如下:
CREATETABLE`order`(
`id`int(11)NOTNULL,
`status`tinyint(4)NOTNULL,
`price`int(11)NOTNULL,
`create_time`bigint(20)NOTNULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8
基於上一步Mysql客戶端中操作
#切換至OrderDB庫
mysql> use OrderDB;
#執行簡表語句,成功後會在兩台Mysql中都新建相同的order表
mysql> CREATE TABLE `order` (
-> `id` int(11) NOT NULL,
-> `status` tinyint(4) NOT NULL,
-> `price` int(11) NOT NULL,
-> `create_time` bigint(20) NOT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
成功的輸出如下: