mycat1.6.7.3安装及使用
前提:配置了mysql主从复制
最小化安装centos7
关闭防火墙 firewalld和sellinux
安装jdk11
安装mysql8.0.23客户端
安装mycat1.6.7.3
介绍
是什么?
数据库中间件,前身是阿里的cobar
干什么?
(1)读写分离
(2)数据分片
1)垂直拆分
2)水平拆分
3)垂直+水平拆分
(3)多数据源整合
原理
“拦截”。
Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了
一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,
并将返回的结果做适当的处理,最终再返回给用户
这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用mycat还是mysql。
安装启动
解压到指定目录
tar -xvf Mycat-server-1.6.7.3-release-20190828135747-linux.tar.gz -C /usr/local/
替换mysql-connector
删除mycat/lib 文件夹下mysql-connector-java/5.1.35 将mysql-connector-java-8.0.22.jar到mycat/lib 目录下,由于我的电脑上有这个版本的jar就没有下8.0.23的jar 权限全开 chmod 777 mysql-connector-java-8.0.22.jar
修改server.xml
root改为mycat <user name="mycat" defaultAccount="true"> <property name="password">mycatP@ssw0rd</property> <property name="schemas">TESTDB</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>
修改schema.xml
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> </schema> <dataNode name="dn1" dataHost="host1" database="masterdb" /> <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="jdbc:mysql://192.168.0.111:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd"> <!-- can have multi read hosts --> <readHost host="hostS1" url="jdbc:mysql://192.168.0.221:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd" /> </writeHost> </dataHost> </mycat:schema>
验证数据库访问情况
mysql -uroot -prootP@ssw0rd -h 192.168.0.111 -P 3306 mysql -uroot -prootP@ssw0rd -h 192.168.0.221 -P 3306 如本机远程访问报错,请建对应用户 grant all privileges on *.* to root@'缺少的host' identified by 'rootP@ssw0rd';
启动程序
控制台启动 :去mycat/bin 目录下 ./mycat console #以这种方式启动,可以查看信息,方便调试
后台启动 :去mycat/bin 目录下 ./mycat start
错误Host ‘192.168.1.XXX’ is blocked because of many connection errors及解决方法
登陆
后台管理窗口 mysql -umycat -pmycatP@ssw0rd -P9066 -h192.168.0.211 --default-auth=mysql_native_password
命令 show @@help;
数据窗口
mysql -umycat -pmycatP@ssw0rd -h 192.168.0.211 -P 8066 --default-auth=mysql_native_password
读写分离
修改schema.xml中balance的值
负载均衡类型,目前的取值有4 种: 1. balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。 2. balance="1",全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载均衡。 3. balance="2",所有读操作都随机的在 writeHost、readhost 上分发。 4. balance="3",所有读请求随机的分发到 readhost 执行,writerHost 不负担读压力
学习时为了查看效果设置为2,由于只配置了一主一从,所以我设置为3
分库
将orderdb设置为不要主从复制
修改schema.xml
以下配置将orderdb中customer表配置在dn2中,其它表在dn1中
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> <table name="customer" dataNode="dn2" ></table> </schema> <dataNode name="dn1" dataHost="host1" database="orderdb" /> <dataNode name="dn2" dataHost="host2" database="orderdb" /> <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="jdbc:mysql://192.168.0.111:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM2" url="jdbc:mysql://192.168.0.221:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> </mycat:schema>
分别在dn1和dn2上执行创建orderdb
create database orderdb;
重启mycat,连接上mycat,使用mycat创建表
#客户表 rows:20万 CREATE TABLE customer( id INT AUTO_INCREMENT, NAME VARCHAR(200), PRIMARY KEY(id) ); #订单表 rows:600万 CREATE TABLE orders( id INT AUTO_INCREMENT, order_type INT, customer_id INT, amount DECIMAL(10,2), PRIMARY KEY(id) ); #订单详细表 rows:600万 CREATE TABLE orders_detail( id INT AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) ); #订单状态字典表 rows:20 CREATE TABLE dict_order_type( id INT AUTO_INCREMENT, order_type VARCHAR(200), PRIMARY KEY(id) );
查看可知,customer在dn2上,其它表在dn1上。(关于分库如何决定哪些表在哪些库中的原则:需要join查询的表不要分开)
水平分表
将orders水平拆分,跨库join,orders_detail表,全局字典表dict_order_type的配置
修改schema.xml
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> <table name="customer" dataNode="dn2" ></table>
<!-- 水平分片的表 --> <table name="orders" dataNode="dn1,dn2" rule="mod_rule" >
<!-- 跨库join,ER表 joinKey的值为父表水平分片的字段,否则当子表插入数据时会出错 --> <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" /> </table>
<!-- 全局表,每个库中都有,一般数据量不大,允许适当的冗余,不会影响数据库性能 --> <table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table> </schema> <dataNode name="dn1" dataHost="host1" database="orderdb" /> <dataNode name="dn2" dataHost="host2" database="orderdb" /> <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="jdbc:mysql://192.168.0.111:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM2" url="jdbc:mysql://192.168.0.221:3306?useSSL=false&serverTimezone=UTC" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> </mycat:schema>
修改rule.xml水平分片的规则
<!-- 添加分片规则 -->
<tableRule name="mod_rule"> <rule> <columns>id</columns> <algorithm>mod-long</algorithm> </rule> </tableRule>
<!-- 算法 --> <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <!-- how many data nodes --> <property name="count">2</property> </function>
重启mycat,在dn1和dn2上分别建立orders、orders_detail、dict_order_type表
使用mycat插入数据
# 向orders表中插入数据 insert into orders(id,order_type,customer_id,amount) values(1,101,100,100100); insert into orders(id,order_type,customer_id,amount) values(2,101,100,100300); insert into orders(id,order_type,customer_id,amount) values(3,101,101,120100); insert into orders(id,order_type,customer_id,amount) values(4,101,101,103100); insert into orders(id,order_type,customer_id,amount) values(5,102,101,100400); insert into orders(id,order_type,customer_id,amount) values(6,102,100,100020); # 向orders_detail中插入数据 insert into orders_detail (id,detail,order_id) values(1,'detail',1); insert into orders_detail (id,detail,order_id) values(2,'detail',2); insert into orders_detail (id,detail,order_id) values(3,'detail',3); insert into orders_detail (id,detail,order_id) values(4,'detail',4); insert into orders_detail (id,detail,order_id) values(5,'detail',5); insert into orders_detail (id,detail,order_id) values(6,'detail',6); # 向dict_order_type表中插入数据 insert into dict_order_type (id,order_type) values(101,'order_type1'); insert into dict_order_type (id,order_type) values(102,'order_type2'); # join查询 select o.*,od.detail,d.order_type from orders o inner join orders_detail od on o.id =od.order_id inner join dict_order_type d on o.order_type=d.id where o.customer_id=xxx;
注意:Mycat1.6事务内insert ER子表 joinKey指定父表字段为非分片字段时抛can't find (root) parent sharding node for sql
全局序列
1、本地文件(不推荐)
2、数据库方式
数据库序列原理:
利用数据库一个表 来进行计数累加。
但是并不成序列都读写数据库,是每次生这样效率太低
mycat会预加载一部分号段到mycat的内存中,这样大部分读写序列都是在内存中完成的。
如果内存中的号段用完了 mycat会再向数据库要一次。
问:那如果mycat崩溃了 ,那内存中的序列岂不是都没了?
是的。如果是这样,那么mycat启动后会向数据库申请新的号段,原有号段会弃用。
也就是说如果mycat重启,那么损失是当前的号段没用完的号码,但是不会因此出现主键重复。
建库序列脚本
win10 CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(NAME)) ENGINE=INNODB; DELIMITER $$ CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) 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; DELIMITER $$ CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name; RETURN mycat_seq_currval(seq_name); END $$ DELIMITER ; DELIMITER $$ CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name; RETURN mycat_seq_currval(seq_name); END $$ DELIMITER; SELECT * FROM MYCAT_SEQUENCE TRUNCATE TABLE MYCAT_SEQUENCE ##增加要用的序列 INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000, 100);
修改mycat配置
sequence_db_conf.properties
意思是 ORDERS这个序列在dn1这个节点上,具体dn1节点是哪台机子,请参考schema.xml
server.xml
重启mycat
插入语句
insert into `orders`(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);
设置自增方式
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"> <table name="customer" dataNode="dn2" ></table>
<!-- 设置使用自增方式 --> <table name="orders" dataNode="dn1,dn2" rule="mod_rule" primaryKey="id" autoIncrement="true" > <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" /> </table> <table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table> <!-- 全局序列表 --> <!-- <table name="mycat_sequence" dataNode="dn1" ></table> --> </schema> <dataNode name="dn1" dataHost="host1" database="orderdb" /> <dataNode name="dn2" dataHost="host2" database="orderdb" />
<!-- 此版本的全局序列不支持jdbc连接,所以用native ,要将dn1和dn2的密码加密方式修改为mysql_native_password --> <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="192.168.0.111:3306" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> <dataHost name="host2" 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="hostM2" url="192.168.0.221:3306" user="root" password="rootP@ssw0rd"> </writeHost> </dataHost> </mycat:schema>
自增方式插入语句
insert into `orders`(amount,customer_id,order_type) values(1000,101,102);
3、时间 戳方式(18位,比较长)
4、自主生成。
根据业务逻辑组合
可以利用redis的单线程原子性incr来生成序列
至此,使用mycat搭建读写分离分库分表的分布式数据库完毕。