1、MyCat概念
1.1 總體架構(gòu)
MyCAT的
架構(gòu)如下圖所示:
MyCAT使用
MySQL的通訊協(xié)議模擬成一個(gè)
mysql服務(wù)器,并建立了完整的Schema(
數(shù)據(jù)庫(kù))、Table(數(shù)據(jù)表)、User(用戶)的邏輯模型,并將這套邏輯模型映射到后端的存儲(chǔ)節(jié)點(diǎn)DataNode(MySQL Instance)上的真實(shí)物理庫(kù)中,這樣一來(lái),所有能使用MySQL的客戶端以及編程語(yǔ)言都能將MyCAT當(dāng)成是MySQLServer來(lái)使用,不必開(kāi)發(fā)新的客戶端協(xié)議。
當(dāng)MyCAT收到一個(gè)客戶端發(fā)送的SQL請(qǐng)求時(shí),會(huì)先對(duì)SQL進(jìn)行語(yǔ)法分析和檢查,分析的結(jié)果用于SQL路由,SQL路由策略支持傳統(tǒng)的基于表格的分片字段方式進(jìn)行分片,也支持獨(dú)有的基于數(shù)據(jù)庫(kù)E-R關(guān)系的分片策略,對(duì)于路由到多個(gè)數(shù)據(jù)節(jié)點(diǎn)(DataNode)的SQL,則會(huì)對(duì)收到的數(shù)據(jù)集進(jìn)行“歸并”然后輸出到客戶端。
SQL執(zhí)行的過(guò)程,簡(jiǎn)單的說(shuō),就是把SQL通過(guò)網(wǎng)絡(luò)協(xié)議發(fā)送給后端的真正的數(shù)據(jù)庫(kù)上進(jìn)行執(zhí)行,對(duì)于MySQL Server來(lái)說(shuō),是通過(guò)MySQL網(wǎng)絡(luò)協(xié)議發(fā)送報(bào)文,并解析返回的結(jié)果,若SQL不涉及到多個(gè)分片節(jié)點(diǎn),則直接返回結(jié)果,寫(xiě)入客戶端的SOCKET流中,這個(gè)過(guò)程是非阻塞模式(NIO)。
DataNode是MyCAT的邏輯數(shù)據(jù)節(jié)點(diǎn),映射到后端的某一個(gè)物理數(shù)據(jù)庫(kù)的一個(gè)Database,為了做到系統(tǒng)高可用,每個(gè)DataNode可以配置多個(gè)引用地址(DataSource),當(dāng)主DataSource被檢測(cè)為不可用時(shí),系統(tǒng)會(huì)自動(dòng)切換到下一個(gè)可用的DataSource上,這里的DataSource即可認(rèn)為是Mysql的主從服務(wù)器的地址。
1.2 邏輯庫(kù)
與任何一個(gè)傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)一樣,MyCAT也提供了“數(shù)據(jù)庫(kù)”的定義,并有用戶授權(quán)的功能,下面是MyCAT邏輯庫(kù)相關(guān)的一些概念:
schema:邏輯庫(kù),與MySQL中的Database(數(shù)據(jù)庫(kù))對(duì)應(yīng),一個(gè)邏輯庫(kù)中定義了所包括的Table。
table:表,即物理數(shù)據(jù)庫(kù)中存儲(chǔ)的某一張表,與傳統(tǒng)數(shù)據(jù)庫(kù)不同,這里的表格需要聲明其所存儲(chǔ)的邏輯數(shù)據(jù)節(jié)點(diǎn)DataNode,這是通過(guò)表格的分片規(guī)則定義來(lái)實(shí)現(xiàn)的,table可以定義其所屬的“子表(childTable)”,子表的分片依賴于與“父表”的具體分片地址,簡(jiǎn)單的說(shuō),就是屬于父表里某一條記錄A的子表的所有記錄都與A存儲(chǔ)在同一個(gè)分片上。
分片規(guī)則:是一個(gè)字段與函數(shù)的捆綁定義,根據(jù)這個(gè)字段的取值來(lái)返回所在存儲(chǔ)的分片(DataNode)的序號(hào),每個(gè)表格可以定義一個(gè)分片規(guī)則,分片規(guī)則可以靈活擴(kuò)展,默認(rèn)提供了基于數(shù)字的分片規(guī)則,字符串的分片規(guī)則等。
dataNode: MyCAT的邏輯數(shù)據(jù)節(jié)點(diǎn),是存放table的具體物理節(jié)點(diǎn),也稱之為分片節(jié)點(diǎn),通過(guò)DataSource來(lái)關(guān)聯(lián)到后端某個(gè)具體數(shù)據(jù)庫(kù)上,一般來(lái)說(shuō),為了高可用性,每個(gè)DataNode都設(shè)置兩個(gè)DataSource,一主一從,當(dāng)主節(jié)點(diǎn)宕機(jī),系統(tǒng)自動(dòng)切換到從節(jié)點(diǎn)。
dataHost:定義某個(gè)物理庫(kù)的訪問(wèn)地址,用于捆綁到dataNode上。
MyCAT目前通過(guò)配置文件的方式來(lái)定義邏輯庫(kù)和相關(guān)配置:
· MYCAT_HOME/conf/schema.xml中定義邏輯庫(kù),表、分片節(jié)點(diǎn)等內(nèi)容;
· MYCAT_HOME/conf/rule.xml中定義分片規(guī)則;
· MYCAT_HOME/conf/server.xml中定義用戶以及系統(tǒng)相關(guān)變量,如端口等。
下圖給出了MyCAT一個(gè)可能的邏輯庫(kù)到物理庫(kù)(MySQL的完整映射關(guān)系),可以看出強(qiáng)大的分片能力以及靈活的Mysql集群整合能力。
2、 MyCat基本使用教程
2.1 下載和安裝
MyCAT使用
Java開(kāi)發(fā),因?yàn)橛玫搅薐DK 7的部分功能,所以在使用前請(qǐng)確保安裝了JDK 7.0,要求是JDK 7.0以上,并設(shè)置了正確的Java環(huán)境變量
目前下載的版本是免安裝,解壓在任意磁盤、根目錄下,避免路徑中出現(xiàn)中文。
目錄下的“
Mycat-server-1.2-GA-win.tar.gz”文件,解壓后的目錄結(jié)構(gòu)如下圖所示:
目錄說(shuō)明見(jiàn)下表所示:
目錄名稱
說(shuō)明
bin
存放window版本和
Linux版本,除了提供封裝成服務(wù)的版本之外,也提供nowrap的shell腳本命令,方便大家選擇和修改。
Windows 下 運(yùn)行:mycat.bat console在控制臺(tái)啟動(dòng)程序,也可以裝載成服務(wù),若此程序運(yùn)行有問(wèn)題,也可以運(yùn)行startup_nowrap.bat,確保java命令可以在命令執(zhí)行。
Warp方式的命令,可以安裝成服務(wù)并啟動(dòng)或停止。
l mycat install (可選)
l mycat start
注意,wrap方式的程序,其JVM配置參數(shù)在conf/wrap.conf中,可以修改為合適的參數(shù),參數(shù)調(diào)整參照
http://wrapper.tanukisoftware.com/doc/english/properties.html。
conf
存放配置文件:
l server.xml:是Mycat服務(wù)器參數(shù)調(diào)整和用戶授權(quán)的配置文件。
l schema.xml:是邏輯庫(kù)定義和表以及分片定義的配置文件。
l rule.xml:是分片規(guī)則的配置文件,分片規(guī)則的具體一些參數(shù)信息單獨(dú)存放為文件,也在這個(gè)目錄下,配置文件修改,需要重啟MyCAT或者通過(guò)9066端口reload。
l wrapper.conf:JVM配置參數(shù)等設(shè)置。
l log4j.xml:日志存放在logs/mycat.log中,每天一個(gè)文件,日志的配置是在conf/log4j.xml中,根據(jù)自己的需要,可以調(diào)整輸出級(jí)別為debug,debug級(jí)別下,會(huì)輸出更多的信息,方便排查問(wèn)題。
lib
MyCAT自身的jar包或依賴的jar包的存放目錄。
logs
MyCAT日志的存放目錄。日志存放在logs/mycat.log中,每天一個(gè)文件
2.2 啟動(dòng)和停止
安裝mycat服務(wù) :mycate install
啟動(dòng)mycat服務(wù) :mycate start
停止mycat服務(wù) :mycate stop
注意:當(dāng)修改配置文件后,需要重啟mycat服務(wù)
3、使用教程
3.1 硬件配置和安裝數(shù)據(jù)庫(kù)
本地 mycat 192.168.1.5
服務(wù)器A mysql 192.168.1.201
服務(wù)器A mysql 192.168.1.202
安裝MySQL服務(wù)器和MySQL客戶端,筆者使用的MySQL服務(wù)器是免安裝版本:mysql-noinstall-5.1.73-winx64,MySQL客戶端是:Navicat for MySQL,免安裝版本安裝方法請(qǐng)參考:
http://blog.csdn.net/q98842674/article/details/120947773.2 創(chuàng)建數(shù)據(jù)庫(kù)
分別在服務(wù)器A、服務(wù)器B創(chuàng)建所用的分片數(shù)據(jù)庫(kù);
CREATE database db1;
3.3 配置文件
schema.xml配置文件,因?yàn)榉謳?kù)在不同的服務(wù)器,因此配置兩個(gè)datahost;如果在一個(gè)datahost中配置多個(gè)writeHost,則為主從配置。type="global"時(shí),為全局表,
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<table name="travelrecord" dataNode="dn1,dn2" rule="auto-sharding-long" />
<!-- global table is auto cloned to all defined data nodes ,so can join
with any table whose sharding node is in the same data node -->
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<!-- random sharding using mod sharind rule -->
<table name="hotnews" primaryKey="ID" dataNode="dn1,dn2"
rule="mod-long" />
<!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
rule="mod-long" /> -->
<table name="employee" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile" />
<table name="customer" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile">
<childTable name="orders" primaryKey="ID" joinKey="customer_id"
parentKey="id">
<childTable name="order_items" joinKey="order_id"
parentKey="id" />
</childTable>
<childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
parentKey="id" />
</table>
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost2" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.201:3306" user="shopuser"
password="123456">
</writeHost>
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.202:3306" user="shopuser"
password="123456">
</writeHost>
</dataHost>
</mycat:schema>
server.xml配置文件,本實(shí)例很簡(jiǎn)單,就只定義user,
name:用戶名
password:密碼
schemas:實(shí)例名,和schema.xml定義的schema對(duì)應(yīng),這里的實(shí)例名是虛擬名,也就是對(duì)mycat服務(wù)的一種別名,是 應(yīng)用程序以及客戶端連接的入口。
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<property name="defaultSqlParser">druidparser</property>
<!-- <property name="useCompression">1</property>--> <!--1為開(kāi)啟mysql壓縮協(xié)議-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默認(rèn)是65535 64K 用于sql解析時(shí)最大文本長(zhǎng)度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequnceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<property name="mutiNodeLimitType">1</property> 0:開(kāi)啟小數(shù)量級(jí)(默認(rèn)) ;1:開(kāi)啟億級(jí)數(shù)據(jù)排序
<property name="mutiNodePatchSize">100</property> 億級(jí)數(shù)量排序批量
<property name="processors">32</property> <property name="processorExecutor">32</property>
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
</system>
<user name="test">
<property name="password">test</property>
<property name="schemas">TESTDB</property>
</user>
</mycat:server>
3.4 登錄mycat
在任意有mysql的客戶端的機(jī)器連接Mycat, 執(zhí)行以下命令
mysql -utest -ptest -h192.168.1.5 -P8066 -DTESTDB 注意:8066登錄mycat數(shù)據(jù)端口,9066登錄mycat管理端口(能看到mycat內(nèi)的配置、以及各個(gè)數(shù)據(jù)庫(kù)連接情況,很有用)
3.5 測(cè)試
全局表:company
mysql> create table company(id int not null primary key,name varchar(100),sharding_id int not null);
Query OK, 0 rows affected (0.30 sec)
mysql> explain create table company(id int not null primary key,name varchar(100),sharding_id int not null);
+-----------+------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+------------------------------------------------------------------------------------------------+
| dn1 | create table company(id int not null primary key,name varchar(100),sharding_id int not null) |
| dn2 | create table company(id int not null primary key,name varchar(100),sharding_id int not null) |
+-----------+------------------------------------------------------------------------------------------------+
2 rows in set (0.04 sec)
mysql> insert into company(id,name,sharding_id) values(1,'leader us',10000);
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 6
Current database: TESTDB
Query OK, 1 row affected (0.03 sec)
mysql> explain insert into company(id,name,sharding_id) values(1,'leader us',10000);
+-----------+-----------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+-----------------------------------------------------------------------+
| dn1 | insert into company(id,name,sharding_id) values(1,'leader us',10000) |
+-----------+-----------------------------------------------------------------------+
1 row in set (0.00 sec)
水平分表:travelrecord
mysql> explain create table travelrecord(id int not null primary key,name varchar(100));
+-----------+---------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------------+
| dn1 | create table travelrecord(id int not null primary key,name varchar(100)) |
| dn2 | create table travelrecord(id int not null primary key,name varchar(100)) |
| dn3 | create table travelrecord(id int not null primary key,name varchar(100)) |
+-----------+---------------------------------------------------------------------+
3 rows in set (0.01 sec)
(7) 三個(gè)分片上都插入了3條數(shù)據(jù)
mysql> explain insert into travelrecord(id,name) values(1,'hp');
+-----------+---------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------+
| dn1 | insert into travelrecord(id,name) values(1,'hp') |
| dn2 | insert into travelrecord(id,name) values(1,'hp') |
| dn3 | insert into travelrecord(id,name) values(1,'hp') |
+-----------+---------------------------------------------+
3 rows in set (0.00 sec)