官网 http://www.mycat.io/
Mycat 概要介绍 https://github.com/MyCATApache/Mycat-Server
入门指南 https://github.com/MyCATApache/Mycat-doc/tree/master/%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97
1 Mycat 介绍与核心概念
1.1 基本介绍
历史:从阿里 cobar 升级而来,由开源组织维护,2.0 正在开发中。
定位:运行在应用和数据库之间,可以当做一个 MySQL 服务器使用,实现对 MySQL 数据库的分库分表,也可以通过 JDBC 支持其他的数据库
Mycat 的关键特性(官网首页)
1、可以当做一个 MySQL 数据库来使用
2、支持 MySQL 之外的数据库,通过 JDBC 实现
3、解决了我们提到的所有问题,多表 join、分布式事务、全局序列号、翻页排 序
4、支持 ZK 配置,带监控 mycat-web 5、2.0 正在开发中
主机 物理主机,一台服务器,一个数据库服务,一个 3306 端口
物理数据库 真实的数据库,例如 146、150、151 的 gpcat 数据库
物理表 真实的表,例如 146、150、151 的 gpcat 数据库的 order_info 表
分片 将原来单个数据库的数据切分后分散存储在不同的数据库节点
分片节点 分片以后数据存储的节点
分片键 分片依据的字段,例如 order_info 表以 id 为依据分片,id 就是分片键,通常是主键
分片算法 分片的规则,例如随机、取模、范围、哈希、枚举以及各种组合算法
逻辑表 相对于物理表,是分片表聚合后的结果,对于客户端来说跟真实的表没有区别
逻辑数据库 相对于物理数据库,是数据节点聚合后的结果,例如 catmall
下载、解压 Mycat(有 Windows 版本,可以在本地数据库测试)
http://dl.mycat.io/
wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
tar -xzvf Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
Mycat 解压以后有 5 个目录:
bin 启动目录
catlet 空目录
conf 配置目录
lib jar 包依赖
logs 日志目录
主要的配置文件 server.xml、schema.xml、rule.xml 和具体的分片配置文件。
坑非常多,配置错误会导致无法启动,这个时候要看日志!
注意备份,不知道什么时候就跑不起来了
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">catmall</property>
</user>
java -cp Mycat-server-1.6.7.3-release.jar io.mycat.util.DecryptUtil 0:root:123456
<schema name="catmall" checkSQLschema="false" sqlMaxLimit="100">
<!-- 范围分片 -->
<table name="customer" primaryKey="id" dataNode="dn1,dn2,dn3" rule="rang-long-cust" />
<!-- 取模分片 -->
<table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order" >
<!-- ER 表 -->
<childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id"/>
</table>
<!-- 全局表 -->
<table name="student" primaryKey="sid" type="global" dataNode="dn1,dn2,dn3" />
</schema>
<dataNode name="dn1" dataHost="host1" database="gpcat" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root" password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.8.146:3306" user="root" password="xxx"/>
</writeHost>
<writeHost host="hostS1" url="localhost:3316" user="root" password="123456"/>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
switchType:主从切换配置
-1 表示不自动切换
<tableRule name="rang-long-cust">
<rule>
<columns>id</columns>
<algorithm>func-rang-long-cust</algorithm>
</rule>
</tableRule>
<function name="func-rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">rang-long-cust.txt</property>
</function>
分片配置:rang-long-cust.txt
10001-20000=1
0-10000=0
20001-100000=2
cd /usr/local/soft/mycat/conf
cp *.txt *.xml *.properties zkconf/
cd /usr/local/soft/mycat/bin
./init_zk_data.sh
loadZk=true
zkURL=127.0.0.1:2181
clusterId=010 myid=01001
clusterSize=1
clusterNodes=mycat_gp_01
#server booster ; booster install on db same server,will reset all minCon to 2
type=server
boosterDataHosts=dataHost1
3.2.5 启动停止
CREATE TABLE `customer` ( `id` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `order_info` ( `order_id` int(11) NOT NULL COMMENT '订单 ID', `uid` int(11) DEFAULT NULL COMMENT '用户 ID', `nums` int(11) DEFAULT NULL COMMENT '商品数量', `state` int(2) DEFAULT NULL COMMENT '订单状态', `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `order_detail` ( `order_id` int(11) NOT NULL COMMENT '订单号', `id` int(11) NOT NULL COMMENT '订单详情', `goods_id` int(11) DEFAULT NULL COMMENT '货品 ID', `price` decimal(10,2) DEFAULT NULL COMMENT '价格', `is_pay` int(2) DEFAULT NULL COMMENT '支付状态', `is_ship` int(2) DEFAULT NULL COMMENT '是否发货', `status` int(2) DEFAULT NULL COMMENT '订单详情状态', PRIMARY KEY (`order_id`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `student` ( `sid` int(8) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `qq` varchar(255) DEFAULT NULL, PRIMARY KEY (`sid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<table name="customer" dataNode="dn1,dn2,dn3" rule="rang-long-cust" primaryKey="id"/>
<table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order">
<childTable name="order_detail" joinKey="order_id" parentKey="order_id" primaryKey="id"/>
</table>
<table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global"/>
<dataNode name="dn1" dataHost="host1" database="gpcat"/> <dataNode name="dn2" dataHost="host2" database="gpcat"/>
<dataNode name="dn3" dataHost="host3" database="gpcat"/>
<dataHost balance="0" maxCon="1000" minCon="10" name="host1" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.8.146:3306" password="123456" user="root"/>
</dataHost>
<dataHost balance="0" maxCon="1000" minCon="10" name="host2" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.8.150:3306" password="123456" user="root"/>
</dataHost>
<dataHost balance="0" maxCon="1000" minCon="10" name="host3" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.8.151:3306"
password="123456" user="root"/>
</dataHost>
schema——rule.xml——分片配置
<tableRule name="rang-long-cust"> <rule>
<columns>id</columns>
<algorithm>rang-long-cust</algorithm> </rule>
</tableRule>
<function name="rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">rang-long-cust.txt</property> </function>
INSERT INTO `customer` (`id`, `name`) VALUES (6666, '赵先生'); INSERT INTO `customer` (`id`, `name`) VALUES (7777, '钱先生'); INSERT INTO `customer` (`id`, `name`) VALUES (16666, '孙先生'); INSERT INTO `customer` (`id`, `name`) VALUES (17777, '李先生'); INSERT INTO `customer` (`id`, `name`) VALUES (26666, '周先生'); INSERT INTO `customer` (`id`, `name`) VALUES (27777, '吴先生');
<tableRule name="mod-long-order">
<rule>
<columns>order_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<property name="count">3</property>
</function>
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (1, 1000001, 1, 2, '2019-9-23 14:35:37', '2019-9-23 14:35:37');
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (2, 1000002, 1, 2, '2019-9-24 14:35:37', '2019-9-24 14:35:37');
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (3, 1000003, 3, 1, '2019-9-25 11:35:49', '2019-9-25 11:35:49');
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (3, 20180001, 85114752, 19.99, 1, 1, 1);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180002, 25411251, 1280.00, 1, 1, 0);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180003, 62145412, 288.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180004, 21456985, 399.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180005, 21457452, 1680.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180006, 65214789, 9999.00, 1, 1, 3);
<table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global"/>
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (1, '黑白', '166669999'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (2, 'AV 哥', '466669999');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (3, '最强菜鸟', '368828888');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (4, '加载中', '655556666');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (5, '猫老公', '265286999');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (6, '一个人的精彩', '516895555');
<property name="sequnceHandlerType">0</property>
CUSTOMER.HISIDS=
CUSTOMER.MINID=10000001
CUSTOMER.MAXID=20000000
CUSTOMER.CURID=10000001
INSERT INTO `customer` (`id`, `name`) VALUES (next value for MYCATSEQ_CUSTOMER, 'qingshan');
<property name="sequnceHandlerType">1</property>
#sequence stored in datanode
GLOBAL=dn1
CUSTOMER=dn1
DROP TABLE IF EXISTS MYCAT_SEQUENCE; CREATE TABLE MYCAT_SEQUENCE (
name VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 1,
remark varchar(100),
PRIMARY KEY(name))
ENGINE=InnoDB;
<table name="mycat_sequence"
dataNode="dn1"
autoIncrement="true"
primaryKey="id">
</table>
DROP FUNCTION IF EXISTS `mycat_seq_currval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%`
FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50))
RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval ;
END ;;
DELIMITER ;
DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%`
FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50))
RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END ;;
DELIMITER ;
DROP FUNCTION IF EXISTS `mycat_seq_setval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%`
FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50), value INTEGER) RETURNS varchar(64) CHARSET latin1 DETERMINISTIC BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END ;;
DELIMITER ;
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('GLOBAL', 1, 100,'');
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('ORDERS', 1, 100,'订单表使 用');
select next value for MYCATSEQ_ORDERS
<property name="sequnceHandlerType">2</property>
#sequence depend on TIME
WORKID=01
DATAACENTERID=01
<property name="sequnceHandlerType">3</property>
# 代表使用 zk
INSTANCEID=ZK
# 与 myid.properties 中的 CLUSTERID 设置的值相同
CLUSTERID=010
cd /usr/local/soft/mycat/conf
cp *.txt *.xml *.properties zkconf/
chown -R zkconf/
cd /usr/local/soft/mycat/bin
./init_zk_data.sh
3.4.5 使用
在 schema.xml 的 table 标签上配置 autoIncrement="true",不需要获取和指定 序列的情况下,就可以使用全局 ID 了。
mysql -uroot -h127.0.0.1 -p123456 -P9066
mysql>show @@help;
4.1.2 命令行监控 mycatweb 监控
cd /usr/local/soft
wget http://dl.mycat.io/mycat-web-1.0/Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz
tar -xzvf Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz
cd mycat-web
nohup ./start.sh &
<!-- 1 为开启实时统计、0 为关闭 -->
<property name="useSqlStat">1</property>
