一、MyCAT 简介和原理
MYCAT基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得MYCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,我们能看到更远。业界优秀的开源项目和创新思路被广泛融入到MYCAT的基因中,使得MYCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。MyCAT作为通用代理设计的,后端是以 Mysql协议 和 JDBC 的方式连接数据库,可以支持 Oracle、DB2、SQL Server 、 mongodb、mysql
数据库中间件
Mycat 其实只是一个数据中间件,或数据库代理
Tip: 所有难搞定的事情都可以通过中间件有效处理,中间件能有效解耦并专注于特定领域问题, LVM、LVS、MQ 都是这个思路(房屋中介,银行也都是这个思路)
所以Mycat没有存储引擎,本身并不存储数据,只是起到了请求分析,拆解,路由与结果聚合的作用,为前端应用提供统一接口,Mycat 与后端的数据库集群有机组合才一起构成一个分布式数据库系统
逻辑库(schema)
类似于LVM中VG的概念(VG由一个或多个PV构成),逻辑库是由一个或多个后端数据库构成的,展示给应用的是一个单一视图,是分布式数据库在逻辑上的一个抽象
逻辑表(table)
- 逻辑表
与数据库中表相对应的,分布式数据表在逻辑上的一个抽象
- 分片表
数据表切分后的一个部分(原表的一个真子集)
- 非分片表
没有分片的表,就是非分片表
- ER表
保留了实体关系特性的表,就是ER表
关系型数据库是基于实体关系模型的相关理论来构建的数据库,表与表间有依赖关系,通过表分组(Table Group) 让有依赖的表在同一实例库中从而避免了数据Join不会跨库操作
- 全局表
全局表是所有分片上都有一份完整拷贝的表
字典表或符合字典特性的表可以被设置为全局表
有以下特点的表,被称作字典表:
- 变动不频繁
- 数据量总体变化不大
- 数据规模不大(很少超过十万条记录)
- 会与其它表发生关联
这类表可以通过冗余来解决join问题,也就是所有的分片都放上一份数据的拷贝来避免跨分片联查
Tip: 数据冗余和表分组是解决跨分片数据join的好思路,也是数据切分规划的重要规则
二、MyCAT使用测试
1、背景:schem.xml文件父表和子表,以及使用枚举分片规则
#vim ./schema.xml
<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>
#vim ./rule.xml
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
#vim partition-hash-int.txt
1=0
2=1
10000=0
10010=1
2、登陆mycat后分别建立对应的表以及插入数据
mycat@TESTDB 08:08:56>show create table
customer
;
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| customer | CREATE TABLE `customer` (
`SHARDING_ID` int(11) DEFAULT NULL,
`id` int(11) NOT NULL,
`customer_id` int(11) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mycat@TESTDB 07:19:09>insert into
customer
(SHARDING_ID,
id
,customer_id,order_id) values (1,1,1,1);
Query OK, 1 rows affected (0.05 sec)
mycat@TESTDB 07:19:09>insert into
customer
(SHARDING_ID,
id
,customer_id,order_id) values
(2,2,2,2);
Query OK, 1 rows affected (0.05 sec)
mycat@TESTDB 07:54:27>select * from
customer
;
+-------------+----+-------------+----------+
| SHARDING_ID | id | customer_id | order_id |
+-------------+----+-------------+----------+
| 2 | 2 | 2 | 2 |
| 1 | 1 | 1 | 1 |
+-------------+----+-------------+----------+
2 rows in set (0.02 sec)
mycat@TESTDB 07:43:10>show create table
orders
;
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| orders | CREATE TABLE `orders` (
`SHARDING_ID` int(11) DEFAULT NULL,
`id` int(11) NOT NULL,
`customer_id` int(11) DEFAULT NULL,
`customer_name` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mycat@TESTDB 07:43:57>insert into
orders
(SHARDING_ID,
id
,
customer_id
,customer_name) values (1,1,1,'qw');
Query OK, 1 row affected (0.24 sec)
mycat@TESTDB 07:44:39>insert into
orders
(SHARDING_ID,
id
,
customer_id
,customer_name) values (1,2,1,'qw');
Query OK, 1 row affected (0.25 sec)
mycat@TESTDB 07:44:45>insert into
orders
(SHARDING_ID,
id
,
customer_id
,customer_name) values (1,3,1,'qw');
Query OK, 1 row affected (0.24 sec)
mycat@TESTDB 07:44:45>insert into
orders
(SHARDING_ID,
id
,
customer_id
,customer_name) values (1,3,3,'qw');
ERROR 1064 (HY000): can't find (root) parent sharding node for sql:insert into orders(SHARDING_ID,id,customer_id,customer_name) values (1,3,3,'qw')
mycat@TESTDB 07:45:50>select * from
orders
;
+-------------+----+-------------+---------------+
| SHARDING_ID | id | customer_id | customer_name |
+-------------+----+-------------+---------------+
| 2 | 1 | 1 | qw |
| 2 | 2 | 2 | qw |
| 1 | 3 | 2 | qw |
+-------------+----+-------------+---------------+
3 rows in set (0.01 sec)
mycat@TESTDB 07:53:01>show create table order_items;
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| order_items | CREATE TABLE `order_items` (
`SHARDING_ID` int(11) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`order_name` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mycat@TESTDB 07:53:59>insert into
order_items
(SHARDING_ID,
order_id
,order_name) values (1,1,'qw');
Query OK, 1 row affected (0.05 sec)
mycat@TESTDB 07:55:17>insert into
order_items
(SHARDING_ID,
order_id
,order_name) values (1,2,'qw');
Query OK, 1 row affected (0.07 sec)
mycat@TESTDB 07:55:30>
insert into
order_items
(SHARDING_ID,
order_id
,order_name) values (1,3,'qw');
Query OK, 1 row affected (0.07 sec)
mycat@TESTDB 07:55:52>insert into
order_items
(SHARDING_ID,
order_id
,order_name) values (1,4,'qw');
ERROR 1064 (HY000): can't find (root) parent sharding node for sql:insert into order_items(SHARDING_ID,order_id,order_name) values (1,4,'qw')
mycat@TESTDB 07:56:21>select * from
order_items
;
+-------------+----------+------------+
| SHARDING_ID | order_id | order_name |
+-------------+----------+------------+
| 1 | 2 | qw |
| 1 | 3 | qw |
| 1 | 1 | qw |
+-------------+----------+------------+
3 rows in set (0.02 sec)
mycat@TESTDB 08:09:45>
show create table
customer_addr
;
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| customer_addr | CREATE TABLE `customer_addr` (
`SHARDING_ID` int(11) DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`customer_name` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mycat@TESTDB 07:57:59>insert into
customer_addr
(SHARDING_ID,
customer_id
,customer_name) values (1,1,'qw');
Query OK, 1 row affected (0.26 sec)
mycat@TESTDB 07:58:28>insert into
customer_addr
(SHARDING_ID,
customer_id
,customer_name) values (1,2,'qw');
Query OK, 1 row affected (0.05 sec)
mycat@TESTDB 07:58:32>insert into
customer_addr
(SHARDING_ID,
customer_id
,customer_name) values (1,3,'qw');
ERROR 1064 (HY000): can't find (root) parent sharding node for sql:insert into customer_addr(SHARDING_ID,customer_id,customer_name) values (1,3,'yue')
mycat@TESTDB 08:04:42>select * from customer_addr;
+-------------+----+-------------+---------------+
| SHARDING_ID | id | customer_id | customer_name |
+-------------+----+-------------+---------------+
| 1 | 1 | 1 | qw |
| 1 | 2 | 2 | qw |
| 1 | 3 | 2 | qw |
+-------------+----+-------------+---------------+
3 rows in set (0.01 sec)
3、分片表子表配置 childTable标签:
- name属性
- joinKey属性:插入子表的时候会使用这个列的值查找父表存储的数据节点。
- parentKey属性:属性指定的值一般为与父表建立关联关系的列名。程序首先获取joinkey的值,再通过parentKey属性指定的列名产生查询语句,通过执行该语句得到父表存储在哪个分片上。从而确定子表存储的位置。
- primaryKey属性:同table标签所描述的。
- needAddLimit属性:同table标签所描述的。
总结:子表中的
joinKey="***_id"
字段取值取决于父表
primaryKey="ID"中的值,不然会报错(简单说
joinKey是
primaryKey的外键
)