Mycat官网:http://www.mycat.io
Mycat下载地址: http://dl.mycat.io
Mycat配置参考:https://github.com/MyCATApache/Mycat-Server
1、建议大家选择 1.6.5 版本,毕竟是比较稳定的版本,且 1.6.5 版本 才开始支持单库分表。
下载:
wget http://dl.mycat.io/1.6.5/Mycat-server-1.6.5-release-20180122220033-linux.tar.gz
解压:
tar -zxvf Mycat-server-1.6.5-release-20180122220033-linux.tar.gz
- bin MyCAT 启用停止目录
- catlet MyCAT 扩展功能目录
- conf MyCAT 配置文件目录
- lib MyCAT 引入的 jar 目录
- logs MyCAT 日志文件目录
version.txt MyCAT 版本信息文件
2、配置:
垂直切分实现
垂直切分定义
数据的垂直切分,也可以称为纵向切分。将数据库想象成由很多个一大块一大块的“数据块”(表)组成,垂直地将这些“数据块”切开,然后把它们分散到多台数据库主机上面。这样的切分方法就是垂直(纵向)的数据切分。
一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或多个表。而在架构设计中,各个功能模块相互之间的交互点越统一、越少,系统的耦合度就越低,系统各个模块的维护性及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易
1.1.2 优缺点
垂直切分优点:
(1)数据库的拆分简单明了,拆分规则明确;
(2)应用程序模块清晰明确,整合容易;
(3)数据维护方便易行,容易定位。
垂直切分缺点:
(1)部分表关联无法在数据库级别完成,要在程序中完成;
(2)对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定能满足要求;
(3)事务处理相对复杂;
(4)切分达到一定程度之后,扩展性会受到限制;
(5)过度切分可能会带来系统过于复杂而难以维护。
①cat schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="MYCATDB" checkSQLschema="false" sqlMaxLimit="10000">
<!-- auto sharding by id (long) -->
<table name="test1" dataNode="leodn1" />
<table name="test2" dataNode="leodn2" />
<table name="test3" dataNode="leodn2" />
<table name="test4" dataNode="leodn3" />
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="leodn1" dataHost="mysql_host1" database="leodb1" />
<dataNode name="leodn2" dataHost="tidb_host2" database="leodb2" />
<dataNode name="leodn3" dataHost="mysql_host2" database="leodb3" />
<dataHost name="mysql_host1" maxCon="10000" minCon="10" balance="0" writeType="1" dbType="mysql" dbDriver="native" switchType="-1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="mhostM1" url="192.168.180.47:3306" user="root" password="q1w2E#R$">
<readHost host="thostS2" url="192.168.180.3:4000" user="root" password="q1w2E#R$" />
<readHost host="mhostS3" url="192.168.180.4:3306" user="root" password="q1w2E#R$" />
</writeHost>
</dataHost>
<dataHost name="tidb_host2" maxCon="10000" minCon="10" balance="0" writeType="1" dbType="mysql" dbDriver="native" switchType="-1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="thostM1" url="192.168.180.3:4000" user="root" password="q1w2E#R$">
<readHost host="mhostS2" url="192.168.180.4:3306" user="root" password="q1w2E#R$" />
<readHost host="mhostS3" url="192.168.180.4:3306" user="root" password="q1w2E#R$" />
</writeHost>
</dataHost>
<dataHost name="mysql_host2" maxCon="10000" minCon="10" balance="0" writeType="1" dbType="mysql" dbDriver="native" switchType="-1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="thostM1" url="192.168.180.4:3306" user="root" password="q1w2E#R$">
<readHost host="mhostS2" url="192.168.180.4:3306" user="root" password="q1w2E#R$" />
<readHost host="thostS2" url="192.168.180.3:4000" user="root" password="q1w2E#R$" />
</writeHost>
</dataHost>
</mycat:schema>
②cat server.xml
<?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://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sequnceHandlerType">2</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<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="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> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭
-->
<property name="useOffHeapForMerge">1</property>
<!--
单位为m
-->
<property name="memoryPageSize">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<user name="mycat" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">MYCATDB</property>
<!-- 配置多个库名 -->
<!--<property name="schemas">MYCATDB,MYCATDB1,MYCATDB2,MYCATDB3</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">TESTDB</property>
<property name="readOnly">true</property>
</user> -->
</mycat:server>
3、启动mycat;
启动:
./mycat start
查看启动状态:
./mycat status
停止:
./mycat stop
重启(改变上面的 xml 配置不用重启,管理端可以重新载入):
./mycat restart
查看 logs/ 下的 wrapper.log 和 mycat.log 可以查看运行时问题和异常。
mycat 启动日志:
cat ./logs/wrapper.log
mycat 应用日志:
cat ./logs/mycat.log
4、连接
mysql -u mycat -p -P8066 -h 192.168.180.4
mycli -u mycat -P8066 -h 192.168.180.4
联合查询 前面需要加 /*!mycat:catlet=io.mycat.catlets.ShareJoin */
2.配置mycat conf/server.xml 中定义用户以及系统相关变量,如端口等.
conf/schema.xml 中定义逻辑库,表、分片节点等内容.
conf/rule.xml 中定义分片规则.
-----------------------------------------------------------------------------------------------------------------------------
readHost 标签:指定读实例
readHost 标签 -> host 属性:标识不同的实例
readHost 标签 -> url 属性:指定连接实例的 url 地址
readHost 标签 -> user 属性:指定连接实例的用户名
readHost 标签 -> password 属性:指定连接实例的密码
-----------------------------------------------------------------------------------------------------------------------------
writeHost 标签:指定写实例
writeHost 标签 -> host 属性:标识不同的实例
writeHost 标签 -> url 属性:指定连接实例的 url 地址
writeHost 标签 -> user 属性:指定连接实例的用户名
writeHost 标签 -> password 属性:指定连接实例的密码
-----------------------------------------------------------------------------------------------------------------------------
heartbeat 标签:心跳检查,select user() 通常用于 MySQL 数据库的心跳检查
-----------------------------------------------------------------------------------------------------------------------------
dataHost 标签:定义数据库的实例,配置读写分离等
dataHost 标签 -> name 属性:唯一标识,供上层调用
dataHost 标签 -> maxCon 属性:连接池最大连接数量
dataHost 标签 -> minCon 属性:初始化连接池连接数量
dataHost 标签 -> balance 属性:负载均衡,配置 1 指所有读操作会随机发送到 readHost 实例上
dataHost 标签 -> writeType 属性:负载均衡,配置 0 指所有写操作会发送到可用的 writeHost 实例上
dataHost 标签 -> dbType 属性:指定物理数据库类型
dataHost 标签 -> dbDriver 属性:指定物理数据库使用的 Driver
dataHost 标签 -> slaveThreshold 属性:延迟时间,确保读到的数据是相对较新
-----------------------------------------------------------------------------------------------------------------------------
dataNode 标签:数据节点,也是通常所说的数据分片
dataNode 标签 -> name 属性:数据节点名称,具有唯一性,供上层调用
dataNode 标签 -> dataHost 属性:指定该数据节点的数据库实例(dataHost 标签 -> name 属性)
dataNode 标签 -> database 属性:物理数据库名称
-----------------------------------------------------------------------------------------------------------------------------
schema 标签:配置逻辑数据库
schema 标签 -> name 属性:与上面配置的 server.xml 中配置的逻辑数据库名称一致
schema 标签 -> checkSQLschema 属性:是否去掉 SQL 中 db.table 的 db. 前缀,这里设置默认 false
schema 标签 -> sqlMaxLimit 属性:如果 select 没有 limit,会默认添加 limit 关键字,避免查询全表
schema 标签 -> dataNode 属性:指定该逻辑数据库的数据节点(dataNode 标签 -> name 属性)
-----------------------------------------------------------------------------------
验证:
下面来分析下垂直切分的优缺点:
优点:
• 拆分后业务清晰,拆分规则明确;
• 系统之间整合或扩展容易;
• 数据维护简单。
缺点:
• 部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度;
• 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高;
• 事务处理复杂
/*!mycat: sql=注解 Sql 语句*/真正执行 Sql
注解支持的'!'不被 mysql 单库兼容,
注解规范
1. 注解 SQL 使用 select 语句,不允许使用 delete/update/insert 等语句;虽然 delete/update/insert 等
语句也能用在注解中,但这些语句在 Sql 处理中有额外的逻辑判断,从性能考虑,请使用 select 语句
2.注解 SQL 禁用表关联语句;
3.注解 SQL 尽量用最简单的 SQL 语句,如 select id from tab_a where id=’10000’;
4.无论是原始 SQL 还是注解 SQL,禁止 DDL 语句;
5.能不用注解的尽量不用;
Mycat 支持的或者不支持的语句有哪些?
答:不支持的语法结构,如跨分片 insert into,复杂子查询,3 表及其以上跨库 join 等不支持。
=============================================
查:跨分片查询
/*!mycat:catlet=io.mycat.catlets.ShareJoin */ select * from test2,test1 where test2.name=test1.name;
+----+-----------+------+------+-----------+-----------+------+------+
| id | name | old | year | name | name | old | year |
+----+-----------+------+------+-----------+-----------+------+------+
| 3 | lihongbao | 60 | 2020 | lihongbao | lihongbao | 60 | 2020 |
+----+-----------+------+------+-----------+-----------+------+------+
1 row in set (0.01 sec)
==============================
mycat 跨分片 order by 按照from test2,test1 最后的那个表排序生效
mysql mycat@localhost:MYCATDB> /*!mycat:catlet=io.mycat.catlets.ShareJoin */ select * from test2,test1 where test1.old=test2.old order by test1.year desc;
+-------+------+-----+------+-----+-------+-----+------+
| id | name | old | year | old | name | old | year |
+-------+------+-----+------+-----+-------+-----+------+
| 30011 | yang | 28 | 14 | 28 | zhao | 28 | 4 |
| 30010 | han | 27 | 13 | 27 | li | 27 | 3 |
| 30009 | shen | 26 | 12 | 26 | wang | 26 | 2 |
| 30008 | feng | 25 | 11 | 25 | zhang | 25 | 1 |
+-------+------+-----+------+-----+-------+-----+------+
4 rows in set
Time: 0.034s
mysql mycat@localhost:MYCATDB> /*!mycat:catlet=io.mycat.catlets.ShareJoin */ select * from test2,test1 where test1.old=test2.old order by test2.year desc;
+-------+------+-----+------+-----+-------+-----+------+
| id | name | old | year | old | name | old | year |
+-------+------+-----+------+-----+-------+-----+------+
| 30008 | feng | 25 | 11 | 25 | zhang | 25 | 1 |
| 30009 | shen | 26 | 12 | 26 | wang | 26 | 2 |
| 30010 | han | 27 | 13 | 27 | li | 27 | 3 |
| 30011 | yang | 28 | 14 | 28 | zhao | 28 | 4 |
+-------+------+-----+------+-----+-------+-----+------+
mysql mycat@localhost:MYCATDB> /*!mycat:catlet=io.mycat.catlets.ShareJoin */ select * from test1,test2 where test1.old=test2.old order by test2.year desc;
+----+-------+-----+------+-----+------+-----+------+
| id | name | old | year | old | name | old | year |
+----+-------+-----+------+-----+------+-----+------+
| 18 | zhao | 28 | 4 | 28 | yang | 28 | 14 |
| 17 | li | 27 | 3 | 27 | han | 27 | 13 |
| 16 | wang | 26 | 2 | 26 | shen | 26 | 12 |
| 15 | zhang | 25 | 1 | 25 | feng | 25 | 11 |
+----+-------+-----+------+-----+------+-----+------+
----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------
insert into 同一个MySQL支持,不同的MySQL之间不支持(test1,test4在不同的服务器上)
insert into x select from y 的 SQL,若 x 与 y 不是相同的分片规则,则不被支持,此时会涉及到跨分片转移。
增:
insert into test4 VALUES(6,'lihongbao',6660,2020);
—— Query OK, 1 row affected (0.01 sec)
增:批量插入
目前 Mycat1.3.0.3 以后支持多 values 的批量插入,如 insert into(xxx) values(xxx),(xxx) 。
mysql> insert into test1 (name,old,year) values('ren',25,111),('si',26,222),('wu',27,333),('wei',28,444);
Query OK, 1 row affected (0.08 sec)
增:
不同库insert into select
mysql> /*!mycat: sql=select * from MYCATDB.test1 */ INSERT INTO test1(name,old,year) SELECT name, old , year FROM test4;
(1146, u"Table 'leodb1.test4' doesn't exist")
同库insert into select(加不加注解都可以,注解test2为insert into表)
/*!mycat: sql=select 1 from test2 */insert into test2(old,name,year) select old,name,year from test3;
Query OK, 2 rows affected
Time: 0.020s
批量插入与 ID 自增长结合的支持:
/*!mycat:catlet=demo.catlets.BatchInsertSequence */ insert into test4 VALUES('li',6660,2020);
注: 此方式不需要在 sql 语句中显示的设置主键字段,程序在后台根据 primaryKey 配置的主键列,自动生
成主键的 sequence 值并替换原 sql 中相关的列和值;
删:
delete from test4 where old=60;
You're about to run a destructive command.
Do you want to proceed? (y/n): y
Your call!
Query OK, 1 row affected
Time: 0.025s
改:
update test1 set name='hongbao' , old=30 where year=24;
Reconnecting...
Query OK, 2 rows affected
Time: 0.002s
----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------