转自:http://www.blogjava.net/amigoxie/archive/2014/12/26/421858.html
1、 高级功能
1.1 分片策略
MyCAT通过定义表的分片规则来实现分片,每个表格可以捆绑一个分片规则,每个分片规则指定一个分片字段并绑定一个函数,来实现动态分片算法。
1.1.1 分片规则
以常用的基于整数映射的分片函数org.MyCAT.route.function.PartitionByFileMap为例,此函数通过一个配置文件来确定映射关系,以下面的sharding-by-intfile这个分片规则为例:
<
tableRule
name
="sharding-by-intfile"
>
<
rule
>
<
columns
>
sharding_id
</
columns
>
<
algorithm
>
hash-int
</
algorithm
>
</
rule
>
</
tableRule
>

<
function
name
="hash-int"
class
="org.opencloudb.route.function.PartitionByFileMap"
>
<
property
name
="mapFile"
>
partition-hash-int.txt
</
property
>
</
function
>
conf目录下的partition-hash-int.txt文件的默认内容如下所示:
10000=0
10010=1
表明当字段user_id取值为10000的时候,返回分片节点ID为0,以此类推。
Schema.xml中定义customer表的分片规则为此规则:
<
table
name
="t_user"
dataNode
=" user0,user1,user2,user3"
rule
="sharding-by-intfile"
/>
于是t_user按照字段user_id进行水平分片,分片存储在四个数据节点user1、user2、user3和user4上。
使用MySQL客户端连接mycat的test_mycat数据库,分别运行如下插入语句:
INSERT
INTO
t_user (
user_id
, receive_address, create_time, province_code)
VALUES
(
'
10000
'
,
'
广州市越秀区广州大道中599号
'
,
'
2014-12-25 16:00:00
'
,
'
GD
'
);
INSERT
INTO
t_user (
user_id
, receive_address, create_time, province_code)
VALUES
(
'
10010
'
,
'
广州市越秀区广州大道中599号
'
,
'
2014-12-25 16:00:00
'
,
'
GD
'
);
INSERT
INTO
t_user (
user_id
, receive_address, create_time, province_code)
VALUES
(
'
10011
'
,
'
广州市越秀区广州大道中599号
'
,
'
2014-12-25 16:00:00
'
,
'
GD
'
);
连接localhost的user0 ~user3四个数据库,查看t_user表的数据后可得知user_id为10000和10010的记录分别进入user0和user1数据库,最后一条运行记录因为根据partition-hash-int.txt的配置无法确定写入那个数据库节点,因为报错:
[
Err
]
1003
-
can
'
t find datanode for sharding column:USER_ID val:10011
如何知道某个SQL在哪个分片上执行? 用explain sql语句:
explain
select
*
from
t_user
where
user_id
=
10000
or
user_id
=
10010
;
在MySQL客户端运行,结果如下图所示:
运行如下explain sql语句:
explain
select
*
from
t_user;
在MySQL客户端运行,结果如下图所示:
根据业务场景和数据特点,可以选用以下的分片规则:
l auto-sharding-long 主键自动增长的数字,按照范围进行自动分片,比如0-200万的数据在分片节点0,200-400万的数据在分片节点2,依次类推,根据数据库服务器的性能,可以每个分片存储100-500条记录之间,此种方式,每个分片表一个独立的自增长ID机制,确保记录的连续性。conf/ autopartition-long.txt中定义了分段范围与分片ID的关系。
rule.xml的参考配置为:
<
tableRule
name
="auto-sharding-long"
>
<
rule
>
<
columns
>
user_id
</
columns
>
<
algorithm
>
rang-long
</
algorithm
>
</
rule
>
</
tableRule
>

<
function
name
="rang-long"
class
="org.opencloudb.route.function.AutoPartitionByLong"
>
<
property
name
="mapFile"
>
autopartition-long.txt
</
property
>
</
function
>
对应的范围设置在conf/autopartition-long.txt文件,参考内容如下:
# range start-end ,data node index
# K=1000,M=10000.
0-10000=0
10001-20000=1
20001-30000=2
30000-40000=3
在schema.xml更改t_user表的rule到auto-sharding-long,重启MyCAT后,使用MySQL连接后运行如下SQL语句:
INSERT INTO t_user(user_id, receive_address, create_time, province_code) VALUES ('9999', '广州市越秀区广州大道中599号', '2014-12-25 17:00:00', 'GD');
INSERT INTO t_user(user_id, receive_address, create_time, province_code) VALUES ('10001', '广州市越秀区广州大道中599号', '2014-12-25 17:00:00', 'GD');
INSERT INTO t_user(user_id, receive_address, create_time, province_code) VALUES ('20001', '广州市越秀区广州大道中599号', '2014-12-25 17:00:00', 'GD');
INSERT INTO t_user(user_id, receive_address, create_time, province_code) VALUES ('30001', '广州市越秀区广州大道中599号', '2014-12-25 17:00:00', 'GD');
分别查询user0~user3数据库,可看到user_id分别为9999、10001、20001和30001的记录分别被插入到user0、user1、user2和user3数据库。
l mod-long,对某些表,我们基本上很少会涉及到范围查询的,只根据某个字段(最常见是主键)进行查找定位,则可以用求余的方式,随机分配到其中一个节点上。
rule.xml的参考配置为:
<
tableRule
name
="mod-long"
>
<
rule
>
<
columns
>
user_id
</
columns
>
<
algorithm
>
mod-long
</
algorithm
>
</
rule
>
</
tableRule
>

<
function
name
="rang-long"
class
="org.opencloudb.route.function.AutoPartitionByLong"
>
<
property
name
="mapFile"
>
autopartition-long.txt
</
property
>
</
function
>
在schema.xml更改t_user表的rule到mod-long,重启MyCAT后,使用MySQL连接后运行如下SQL语句:
INSERT INTO t_user (user_id, receive_address, create_time, province_code) VALUES (10004, '广州市越秀区广州大道中599号', '2014-12-25 17:30:00', 'GD');
INSERT INTO t_user (user_id, receive_address, create_time, province_code) VALUES (10005, '广州市越秀区广州大道中599号', '2014-12-25 17:30:00', 'GD');
INSERT INTO t_user (user_id, receive_address, create_time, province_code) VALUES (10006, '广州市越秀区广州大道中599号', '2014-12-25 17:30:00', 'GD');
INSERT INTO t_user (user_id, receive_address, create_time, province_code) VALUES (10007, '广州市越秀区广州大道中599号', '2014-12-25 17:30:00', 'GD');
分别查询user0~user3数据库,可看到user_id分别为10004~10007的记录分别被插入到user0、user1、user2和user3数据库。
所有的分片规则都在rule.xml中定义,不同的表根据需求,定义不同的分片规则。
对于某些不分片的表格,或者分片规则一样的表格,table的定义可以用简化的方式来写,如:<table name="t_user,t_user_class_rel" rule="auto-sharding-long" /> 。对于此种方式,name中定义的这些表格具有相同的属性,并且都不能有childTable 元素。
1.1.2 基于E-R关系分片策略
传统的数据库分片方式都是基于单个表格,对于表关联这种操作,则很难处理。为了能够执行t_user与t_user_class_rel的联合查询, MyCAT借鉴了NewSQL领域的新秀Foundation DB的设计思路,Foundation DB创新性的提出了Table Group的概念,其将子表的存储位置依赖于主表,并且物理上紧邻存放,因此彻底解决了JOIN的效率和性能问题,根据这一思路,提出了基于E-R关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上。
以t_user与t_user_class_rel例子为例,schema.xml中定义如下的分片配置:
<
table
name
="t_user"
dataNode
="user0,user1,user2,user3"
rule
="mod-long"
>
<
childTable
name
="t_user_class_rel"
primaryKey
="id"
joinKey
="user_id"
parentKey
="user_id"
/>
</
table
>
t_user采用mod-long这个分片策略,分片在user0~user3上,t_user_class_rel依赖父表进行分片,两个表的关联关系为t_user_class_rel.user_id=t_user.id。于是数据分片和存储的示意图如下:
这样一来,分片user0上的t_user与user0上的t_user_class_rel就可以进行局部的JOIN联合,user1~user3上也如此,再合并两个节点的数据即可完成整体的JOIN,试想一下,每个分片上t_user_class_rel表有1000万条,则10个分片就有1个亿,基于E-R映射的数据分片模式,基本上解决了80%以上的企业应用所面临的问题。
多对多的表格如何处理?多对多的表格通常情况下,有以下几种:
l 主表+关系表+字典表
l 主表A+关系表+主表B
对于第一种,字典表可以被定义为“全局表”,字典表的记录规模可以在几千到几十万之间,基本是变动比较少的表,由MyCAT自动实时同步到所有分片,这样就可以三个表都做JOIN操作了。
对于第二种,需要从业务角度来看,关系表更偏向哪个表,即“A的关系”还是“B的关系”,来决定关系表跟从那个方向存储。目前还暂时无法很好支持这种模式下的3个表之间的关联。未来版本中将考虑将中间表进行双向复制,以实现从A-关系表 以及B-关系表的双向关联查询。
关于全局表的实现方式,全局表在数据插入或更新的时候,会自动在全局表定义的所有数据节点上执行相同的操作,以保证所有数据节点都一致,由于这个特性,全局表可以跟任何分片或不分片的表格进行JOIN操作。对数据更新不频繁的,规模不是很大的(100万之内)的表都可以定义为MyCAT的全局表,以实现用存储换性能的目标。
1.1.3 主键分片 VS非主键分片
主键分片还是非主键分片,这个问题并不是很难,当你没人任何字段可以作为分片字段的时候,主键分片就是唯一选择,其优点是按照主键的查询最快,当采用自动增长的序列号作为主键时,还能比较均匀的将数据分片在不同的节点上。
若有某个合适的业务字段比较合适作为分片字段,则建议采用此业务字段分片,选择分片字段的条件如下:
- 尽可能的比较均匀分布数据到各个节点上;
- 该业务字段是最频繁的或者最重要的查询条件。
常见的除了主键之外的其他可能分片字段有“订单创建时间”、“店铺类别”或“所在省”等。当你找到某个合适的业务字段作为分片字段以后,不必纠结于“牺牲了按主键查询记录的性能”,因为在这种情况下,MyCAT提供了“主键到分片”的内存缓存机制,热点数据按照主键查询,丝毫不损失性能。做法如下:
<
table
name
="t_user"
primaryKey
="user_id"
dataNode
="user0,user1,user2,user3"
rule
="mod-long"
>
<
childTable
name
="t_user_class_rel"
primaryKey
="id"
joinKey
="user_id"
parentKey
="user_id"
/>
</
table
>
对于非主键分片的table,填写属性primaryKey,此时MyCAT会将你根据主键查询的SQL语句的第一次执行结果进行分析,确定该Table 的某个主键在什么分片上,并进行主键到分片ID的缓存,以下面SQL为例,由于id 不是orders的分片字段,因此这个SQL第一次会发送给所有分片去执行:
select
*
from
orders
where
id
=
1
;
对于多个主键的查询,一样可以自动优化,如:
select
*
from
orders
where
id
in
(
1
,
2
,
3
)
则会分别存储1、2、3这三个主键到分片的缓存关系。
设想下,每个表有5000万数据,10%的热点数据经常按照主键查询,5000万*10%=500万,缓存上述信息大概需要1.5G内存,通过分析缓存使用信息,就可以最精确的调优这笔缓存的内存。通过连接MyCAT的9066管理端口,执行show @@cache,可以显示当前缓存的使用情况。
1.2 高可用性配置
MyCAT支持高可用性的企业级特性,根据应用特性,可以配置如下几种策略:
l 后端数据库配置为一主多从,并开启读写分离机制。
l 后端数据库配置为双主双从(多从),并开启读写分离机制。
l 后端数据库配置为多主多从,并开启读写分离机制
后面两种配置,具有更高的系统可用性,当其中一个写节点(主节点)失败后,Mycat会侦测出来(心跳机制)并自动切换到下一个写节点,MyCAT在任何时候,只会往一个写节点写数据。
下面是典型的双主双从的MySQL集群配置:
MyCAT的schema.xml配置文件中的双主双从参考配置:
<
dataHost
name
="testhost"
maxCon
="1000"
minCon
="10"
balance
="1"
writeType
="0"
dbType
="mysql"
dbDriver
="native"
>
<
heartbeat
>
select user()
</
heartbeat
>
<!--
can have multi write hosts
-->
<
writeHost
host
="hostM1"
url
="localhost:3306"
user
="root"
password
=""
>
<
readHost
host
="hostM2"
url
="10.18.96.144:3306"
user
="axx"
password
="axx"
/>
</
writeHost
>
<
writeHost
host
="hostM3"
url
="……:3306"
user
="root"
password
=""
>
<
readHost
host
="hostM4"
url
="……:3306"
user
="axx"
password
="axx"
/>
</
writeHost
>
</
dataHost
>

2、 管理监控命令
MyCAT自身有类似其他数据库的管理监控方式,通过Mysql命令行,登录管理端口(9066)执行相应的SQL,进行管理
mysql
-
utest
-
ptest
-
P9066
show
@@help
;
此命令会显示所有的管理监控命令,另外请参照《Mycat命令行监控指南.docx》这个文档来深入了解。
2.1 监控命令汇总
“show @@help;”命令的运行结果如下所示:
mysql
>
show
@@help
;
+
--
------------------------------------+-----------------------------------+
|
STATEMENT
|
DESCRIPTION
|
+
--
------------------------------------+-----------------------------------+
|
clear
@@slow
where
datanode
=
?
|
Clear slow sql
by
datanode
|
|
clear
@@slow
where
schema
=
?
|
Clear slow sql
by
schema
|
|
kill
@@connection
id1,id2,
|
Kill
the specified connections
|
|
offline
|
Change MyCat status
to
OFF
|
|
online
|
Change MyCat status
to
ON
|
|
reload
@@config
|
Reload
all
config
from
file
|
|
reload
@@route
|
Reload route config
from
file
|
|
reload
@@user
|
Reload
user
config
from
file
|
|
rollback
@@config
|
Rollback
all
config
from
memory
|
|
rollback
@@route
|
Rollback
route config
from
memory
|
|
rollback
@@user
|
Rollback
user
config
from
memory
|
|
show
@@backend
|
Report backend connection status
|
|
show
@@command
|
Report commands status
|
|
show
@@connection
|
Report connection status
|
|
show
@@connection
.sql
|
Report connection sql
|
|
show
@@database
|
Report databases
|
|
show
@@datanode
|
Report dataNodes
|
|
show
@@datanode
where
schema
=
?
|
Report dataNodes
|
|
show
@@datasource
|
Report dataSources
|
|
show
@@datasource
where
dataNode
=
?
|
Report dataSources
|
|
show
@@heartbeat
|
Report heartbeat status
|
|
show
@@parser
|
Report parser status
|
|
show
@@processor
|
Report processor status
|
|
show
@@router
|
Report router status
|
|
show
@@server
|
Report server status
|
|
show
@@slow
where
datanode
=
?
|
Report datanode slow sql
|
|
show
@@slow
where
schema
=
?
|
Report
schema
slow sql
|
|
show
@@sql
where
id
=
?
|
Report specify SQL
|
|
show
@@sql
.detail
where
id
=
?
|
Report
execute
detail status
|
|
show
@@sql
.
execute
|
Report
execute
status
|
|
show
@@sql
.slow
|
Report slow SQL
|
|
show
@@threadpool
|
Report threadPool status
|
|
show
@@time
.
current
|
Report
current
timestamp
|
|
show
@@time
.startup
|
Report startup
timestamp
|
|
show
@@version
|
Report Mycat Server version
|
|
stop
@@heartbeat
name:time
|
Pause dataNode heartbeat
|
|
switch
@@datasource
name:
index
|
Switch dataSource
|
+
--
------------------------------------+-----------------------------------+
37
rows
in
set
(
0.02
secs)
2.2 常用监控命令
常用的监控命令如下所示:
2.2.1 reload @@config
在MyCAT的命令行监控窗口运行:
reload
@@config
;
该命令用于更新配置文件,例如更新schema.xml文件后在命令行窗口输入该命令,可不用重启即进行配置文件更新。运行结果参考如下:
mysql
>
reload
@@config
;
Query OK,
1
row affected (
0.29
sec)
Reload config success
2.2.2 show @@database
在MyCAT的命令行监控窗口运行:
show
@@database
;
该命令用于显示MyCAT的数据库的列表,对应schema.xml配置文件的schema子节点,参考运行结果如下:
mysql
>
show
@@database
;
+
--
----------+
|
DATABASE
|
+
--
----------+
|
photo
|
|
test_mycat
|
|
weixin
|
|
yixin
|
+
--
----------+
4
rows
in
set
(
0.00
sec)
2.2.3 show @@datanode
在MyCAT的命令行监控窗口运行:
show
@@datanode
;
该命令用于显示MyCAT的数据节点的列表,对应schema.xml配置文件的dataNode节点,参考运行结果如下:
mysql
>
show
@@datanode
;
+
--
------+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+--------------+
|
NAME
|
DATHOST
|
INDEX
|
TYPE
|
ACTIVE
|
IDLE
|
SIZE
|
EXECUTE
|
TOTAL_TIME
|
MAX_TIME
|
MAX_SQL
|
RECOVERY_TIME
|
+
--
------+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
|
photo
|
testhost
/
photo
|
0
|
mysql
|
0
|
7
|
1000
|
0
|
0
|
0
|
0
|-
1
|
|
user0
|
testhost
/
eip_user0
|
0
|
mysql
|
0
|
7
|
1000
|
5
|
0
|
0
|
0
|-
1
|
|
user1
|
testhost
/
eip_user1
|
0
|
mysql
|
0
|
7
|
1000
|
1
|
0
|
0
|
0
|-
1
|
|
user2
|
testhost
/
eip_user2
|
0
|
mysql
|
0
|
7
|
1000
|
1
|
0
|
0
|
0
|-
1
|
|
user3
|
testhost
/
eip_user3
|
0
|
mysql
|
0
|
7
|
1000
|
1
|
0
|
0
|
0
|-
1
|
|
weixin
|
testhost
/
weixin
|
0
|
mysql
|
0
|
7
|
1000
|
0
|
0
|
0
|
0
|-
1
|
|
yixin
|
testhost
/
yixin
|
0
|
mysql
|
0
|
7
|
1000
|
0
|
0
|
0
|
0
|-
1
|
+
--
------+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
7
rows
in
set
(
0.05
sec)
其中,“NAME”表示dataNode的名称;“dataHost”表示对应dataHost属性的值,即数据主机;“ACTIVE”表示活跃连接数;“IDLE”表示闲置连接数;“SIZE”对应总连接数量。
运行如下命令,可查找对应的schema下面的dataNode列表:
show
@@datanode
where
schema
=
?
该命令的执行结果参考如下:
mysql
>
show
@@datanode
where
schema
=
test_mycat;
+
--
-----+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
|
NAME
|
DATHOST
|
INDEX
|
TYPE
|
ACTIVE
|
IDLE
|
SIZE
|
EXECUTE
|
TOTAL_TIME
|
MAX_TIM
|
MAX_SQL
|
RECOVERY_TIME
|
+
--
-----+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
|
user0
|
testhost
/
eip_user0
|
0
|
mysql
|
0
|
6
|
1000
|
5
|
0
|
0
|
0
|-
1
|
|
user1
|
testhost
/
eip_user1
|
0
|
mysql
|
0
|
6
|
1000
|
1
|
0
|
0
|
0
|-
1
|
|
user2
|
testhost
/
eip_user2
|
0
|
mysql
|
0
|
6
|
1000
|
1
|
0
|
0
|
0
|-
1
|
|
user3
|
testhost
/
eip_user3
|
0
|
mysql
|
0
|
6
|
1000
|
1
|
0
|
0
|
0
|-
1
|
+
--
-----+--------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
4
rows
in
set
(
0.00
sec)
2.2.4 show @@heartbeat
该命令用于报告心跳状态,参考运行结果如下所示:
mysql
>
show
@@heartbeat
;
+
--
------+-------+--------------+------+---------+-------+--------+---------+----------------+---------------------+-------+
|
NAME
|
TYPE
|
HOST
|
PORT
|
RS_CODE
|
RETRY
|
STATUS
|
TIMEOUT
|
EXECUTE_TIME
|
LAST_ACTIVE_TIME
|
STOP
|
+
--
------+-------+--------------+------+---------+-------+--------+---------+----------------+---------------------+-------+
|
hostM1
|
mysql
|
localhost
|
3306
|
1
|
0
|
idle
|
30000
|
0
,
2001
,
1445
|
2014
-
12
-
26
12
:
11
:
05
|
false
|
|
hostM3
|
mysql
|
localhost
|
3306
|
1
|
0
|
idle
|
30000
|
5003
,
5168
,
4278
|
2014
-
12
-
26
12
:
11
:
05
|
false
|
|
hostM2
|
mysql
|
10.18
.
96.144
|
3306
|
1
|
0
|
idle
|
30000
|
5
,
3
,
2
|
2014
-
12
-
26
12
:
11
:
05
|
false
|
|
hostM4
|
mysql
|
10.18
.
96.144
|
3306
|
1
|
0
|
idle
|
30000
|
2
,
2
,
2
|
2014
-
12
-
26
12
:
11
:
05
|
false
|
+
--
------+-------+--------------+------+---------+-------+--------+---------+----------------+---------------------+-------+
4
rows
in
set
(
0.01
sec)
2.2.5 show @@version
该命令用于获取MyCAT的版本,参考运行结果如下所示:
mysql
>
show
@@version
;
+
--
----------------+
|
VERSION
|
+
--
----------------+
|
5.1
.
48
-
mycat
-
1.2
|
+
--
--------------+
1
row
in
set
(
0.00
sec)
2.2.6 show @@sql.slow
该命令用于查询运行缓慢的SQL语句,参考运行结果如下所示:
mysql
>
show
@@sql
.slow;
Empty
set
(
0.00
sec)
2.2.7 show @@connection
该命令用于获取连接状态,参考运行结果如下所示:
mysql
>
show
@@connection
;
+
--
----------+------+-----------+------+------------+------------+---------+----
--
--+---------+---------------+-------------+------------+
|
PROCESSOR
|
ID
|
HOST
|
PORT
|
LOCAL_PORT
|
SCHEMA
|
CHARSET
|
NET_IN
|
NET_OUT
|
ALIVE_TIME(S)
|
RECV_BUFFER
|
SEND_QUEUE
|
+
--
----------+------+-----------+------+------------+------------+---------+----
--
--+---------+---------------+-------------+------------+
|
Processor0
|
5
|
127.0
.
0.1
|
8066
|
54448
|
test_mycat
|
utf8
|
320
|
44674
|
225
|
4096
|
0
|
|
Processor3
|
6
|
127.0
.
0.1
|
9066
|
54432
|
NULL
|
utf8
|
162
|
741
|
459
|
4096
|
0
|
+
--
----------+------+-----------+------+------------+------------+---------+----
--
--+---------+---------------+-------------+------------+
2
rows
in
set
(
0.04
sec)
3、 参考文档
(1)《MyCAT inAction中文版》
(2)《Mycat命令行监控指南.docx》