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&amp;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&amp;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&amp;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&amp;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&amp;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&amp;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搭建读写分离分库分表的分布式数据库完毕。

posted on 2021-07-24 01:19  wtsgtc  阅读(504)  评论(0编辑  收藏  举报

导航