MyCat 分库分表及高可用集群

一、Mycat概述

1、什么是MyCat?

  • MyCat是一款数据库中间件、用于链接Java应用程序和数据库、例Tomcat web中间件。

2、为什么用Mycat?

  • Java与数据库紧密耦合。
  • 高访问量高并发对于数据库的压力。
  • 读写请求不一致。

3、MyCat可以做什么

  • 读写分离
    在这里插入图片描述

  • 数据分片

    • 垂直拆分(分库)、水平拆分(分表)、垂直+水平拆分(分库分表)
      在这里插入图片描述

4、MyCat原理

  • MyCat的原理中最重要的一个动词是“拦截”、它拦截用户发过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将SQL发往真实的后端数据库,并将返回的结果做适当的处理,最终返回给用户。
    在这里插入图片描述

二、MyCat环境搭建

  • 上传资源并解压
#解压资源
tar -zxvf Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz -C /opt/module/
#切换目录
cd /opt/module/mycat/ && ll

在这里插入图片描述

  • 配置环境变量
#编辑系统配置
vim /etc/profile

#MYCAT_HOME
export MYCAT_HOME=/opt/module/mycat
export PATH=$PATH:$MYCAT_HOME/bin

#使配置生效
source /etc/profile

#相关启动命令
mycat console | start | stop | restart | status | dump

在这里插入图片描述

  • Mycat主要配置文件解释
    • schema.xml 定义逻辑库、表、分片节点等内容
    • rule.xml 定义分片规则
    • server.xml 定义系统相关变量、如端口等。

三、MyCat读写分离配置

#切换目录
cd /opt/module/mycat/conf
#编辑 约100行
vim server.xml

在这里插入图片描述

  • 配置MYSQL Schema信息

    • 编辑schema.xml配置
    <mycat:schema xmlns:mycat="http://io.mycat/">
    
            <!--模板配置 -->
            <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
    
        </schema>
    
            <!--数据节点 -->
        <dataNode name="dn1" dataHost="host_1" database="task_db" />
    
        <!--
            数据主机配置 -->
            <dataHost name="host_1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    
                    <!--心跳检测 -->
                    <heartbeat>select user()</heartbeat>
    
                <!-- 写主机配置 -->
                    <writeHost host="hostM1" url="192.168.44.191:3306" user="root" password="SYS_666_admin">
    
                        <!-- can have multi read hosts -->
                            <readHost host="hostS1" url="192.168.44.193:3306" user="root" password="SYS_666_admin" />
    
                </writeHost>
    
                 <!-- 写主机配置 -->
                <writeHost host="hostM2" url="192.168.44.191:3306" user="root" password="SYS_666_admin">
    
                        <!-- can have multi read hosts -->
                          <readHost host="hostS2" url="192.168.44.193:3306" user="root" password="SYS_666_admin" />
      
                </writeHost>
            </dataHost>
    </mycat:schema>
    

    在这里插入图片描述

    • balance 属性解释:

      • balance=“0”:不开启读写分离机制、所有读请求都发送到可用的writeHost上。
        • balance=“1”:全部的readHost与 stand by writeHost参与Select的负载均衡,简单来说,当双主双从模式(m1->s1,m2->s2,并且m1和m2互为主备),则m2、s1、s2都将参与select语句的负载均衡。
        • balance=“2”:都有的读操作都随机在writeHost、readHost上分发。
        • balance=“3”:所有的读请求随机分发到readHost执行,writeHost不负担压力。
    • writeType 属性解释:

      • writeType=“0”:所有的写操作发送到配置的第一个writeHost,第一个挂了切换到第二个。切换记录在文件dnindex.properties
      • writeType=“0”:所有的写操作都随机的发送到配置的writeHost,1.5以后版本废弃不推荐。
    • switchType 属性解释:

      • switchType=“1”:自动切换。
      • switchType=“1”:-1手动切换。
      • switchType=“2”:基于MYSQL 主从状态决定。
  • 启动MyCat

#链接 服务端 8066端口
mysql -h 192.168.44.191 -P 8066 -u mycat_m -p123456;

#链接 服务端 9066
mysql -h 192.168.44.191 -P 9066 -u mycat_m -p123456;
#查看所有Mycat服务命令
show @@help;

在这里插入图片描述

  • 测试
    在这里插入图片描述

三、MyCat 垂直拆分(分库配置)

  • Mycat分库概述及规则

    • 概述:一个数据库由很多表构成,每个表对应着不同的业务,垂直拆分是指按照业务将表进行分类,分布到不同的数据库上面,以此分担压力,如下图:

    在这里插入图片描述

    • 分库规则:将有紧密关联关系的表应该在同一个库里,相互没有关联关系的表分到不同库里,且两台主机上两个数据库中的表【不可关联查询】。
  • 编辑schema.xml分库配置

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

        <!--模板配置 -->
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
                <!-- 数据库表配置 -->
                <table name="tb_customer" dataNode="dn2"></table>
        </schema>

        <!--数据节点 -->
        <dataNode name="dn1" dataHost="host_1" database="task_order_db" />
        <dataNode name="dn2" dataHost="host_2" database="task_order_db" />

        <!--数据节点(db1)主机配置 -->
        <dataHost name="host_1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">

                <!--心跳检测 -->
                <heartbeat>select user()</heartbeat>

                <!-- 读写主机配置 -->
                <writeHost host="hostM1" url="192.168.44.193:3306" user="root" password="SYS_666_admin">

                </writeHost>

        </dataHost>

        <!--数据节点(db12主机配置 -->
        <dataHost name="host_2" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">

                <!--心跳检测 -->
                <heartbeat>select user()</heartbeat>

                <!-- 读写主机配置 -->
                <writeHost host="hostM2" url="192.168.44.194:3306" user="root" password="SYS_666_admin">

                </writeHost>

        </dataHost>

</mycat:schema>
  • SQL脚本
#准备测试脚本
CREATE DATABASE `task_order_db`;

USE `task_order_db`;

#客户表 rows:50w
CREATE TABLE `tb_customer` (
`cust_id` int(11) NOT NULL AUTO_INCREMENT,
`cust_name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#订单状态字典表 rows:30w
CREATE TABLE `tb_dictionary_order_type` (
`order_type_id` int(11) NOT NULL AUTO_INCREMENT,
`order_type` varchar(200) DEFAULT NULL,
PRIMARY KEY (`order_type_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#订单明细表 rows:800w
CREATE TABLE `tb_order_detail` (
`order_detail_id` int(11) NOT NULL AUTO_INCREMENT,
`order_detail` varchar(2000) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
PRIMARY KEY (`order_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#订单表 rows:800w
CREATE TABLE `tb_orders` (
`order_id` int(11) NOT NULL AUTO_INCREMENT,
`order_type` int(11) DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`order_amount` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  • 链接MyCat并创建表信息并测试
    在这里插入图片描述
    在这里插入图片描述

四、MyCat水平拆分(分表配置)

1、MyCat取模分表

  • ① 编辑schema.xml 配置目标表
  <!-- 分库分表Schema配置-->
  <schema name="TASKORDERDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn2">
          <!-- 数据库表配置 -->
          <table name="tb_customer" dataNode="dn3"></table>

          <!--水平分表 -->
          <table name="tb_orders" dataNode="dn2,dn3" rule="is_rule" primaryKey="order_id">
          
          </table>
  </schema>

在这里插入图片描述

  • ② 编辑rule.xml配置分表规则
 <!--自定义分片规则 -->
  <tableRule name="is_rule">
            <rule>
                    <columns>customer_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>

在这里插入图片描述

  • ③ 测试分表
#插入语句
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(1,1,10008005,785.65);
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(2,1,10008020,1152.65);
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(3,1,35008153,6235.65);
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(4,1,10009539,8569.65);
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(5,1,16808876,1358.65);

在这里插入图片描述

2、Mycat 分表"Join"

  • ① ER表概述
    • Mycat借鉴了 NewSQL 领域的新秀Foundtion DB 的设计思路,Foundation DB 创新性提出了Table Group的概念,其将子表的存储位置 依赖于主表,并且物理上紧邻存放,因私彻底解决了Join 的效率和性能问题,根据这一思路,提出了技术E-R关系型的数据分片策略,子表的记录与所关联的浮标记录存放在同一个数据分片上。
  • ② 编辑schema.xml配置子表
  <!-- 分库分表Schema配置-->
 <schema name="TASKORDERDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn2">
         <!-- 数据库表配置 -->
         <table name="tb_customer" dataNode="dn3"></table>

         <!--水平分表 -->
         <table name="tb_orders" dataNode="dn2,dn3" rule="is_rule" primaryKey="order_id">
           <!-- 
            name: 表名
            primaryKey: 子表主键
            joinKey: 子表关联字段
            parentKey: 主表关联字段
            -->
            <childTable name="tb_order_detail" primaryKey="order_detail_id" joinKey="order_id" parentKey="order_id" />
         </table>
 </schema>

在这里插入图片描述

  • ③ 测试
#插入语句
INSERT INTO tb_order_detail(order_detail_id,order_detail,order_id) VALUES(1,'order_detail_1',1);
INSERT INTO tb_order_detail(order_detail_id,order_detail,order_id) VALUES(2,'order_detail_2',2);
INSERT INTO tb_order_detail(order_detail_id,order_detail,order_id) VALUES(3,'order_detail_3',3);
INSERT INTO tb_order_detail(order_detail_id,order_detail,order_id) VALUES(4,'order_detail_4',4);
INSERT INTO tb_order_detail(order_detail_id,order_detail,order_id) VALUES(5,'order_detail_5',5);

#链接查询
SELECT * FROM tb_orders tbo INNER JOIN tb_order_detail tbod ON tbo.order_id=tbod.order_id AND tbo.order_id=2;

在这里插入图片描述

3、MyCat 全局表Global

  • 全局表示Mycat定义的一种特殊的表,通常指定是数据量不大且变动不频繁的表,全局表具有如下特性

    • 全局表的插入,更新操作会实时在所有节点上执行,保持各个数据分片的一致性。
    • 全局表的查询操作只能从一个节点上获取。
    • 全局表可以和任何一个表JOIN。
  • ① 编辑schema.xml配置全局表

 <!--全局表配置 -->
 <table name="tb_dictionary_order_type" dataNode="dn2,dn3"  type="global"  primaryKey="order_type_id"></table>
  • ② 测试
INSERT INTO tb_dictionary_order_type(order_type_id,order_type) VALUES(1,'type_1');
INSERT INTO tb_dictionary_order_type(order_type_id,order_type) VALUES(2,'type_2');

在这里插入图片描述

4、Mycat 分片枚举

  • ① 编辑schema.xml 配置表
 <!-- 分片枚举配置 -->
<table name="tb_orders_ware_info" dataNode="dn2,dn3" rule="is_sharding_rule"  primaryKey="ware_info_id"></table>

在这里插入图片描述

  • ② 编辑rule.xml配置规则
<!-- 枚举分片 -->
<tableRule name="is_sharding_rule">
          <rule>
                  <columns>area_code</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>

        <!--
         0: 字段类型为int型
        非0: 字段类型为String型
         -->
        <property name="type">1</property>

        <!--
         默认节点配置:小于0不设置默认节点、大于等于0表示设置默认节点,若碰到不识别的枚举值则路由到该节点、不设置则报错。
         -->
        <property name="defaultNode">0</property>
</function>

在这里插入图片描述

  • ③ 编辑partition-hash-int.txt文件配置枚举规则
#编辑命令
vim partition-hash-int.txt

10000=0
10010=1
  • ④ 测试
#区域信息表-Mycat中创建
CREATE TABLE tb_orders_ware_info(
ware_info_id INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '区域主键',
order_id INT(11) COMMENT '订单号',
address VARCHAR(200) COMMENT '地址',
area_code VARCHAR(20) COMMENT '区域编号'
);

#插入数据
INSERT INTO tb_orders_ware_info(ware_info_id,order_id,address,area_code) VALUES(1,1,'南京',10000);
INSERT INTO tb_orders_ware_info(ware_info_id,order_id,address,area_code) VALUES(2,2,'上海',10010);

在这里插入图片描述

5、 MyCat范围分片

  • ① 编辑schema.xml配置表
 <!-- 范围分片 -->
<table name="tb_payment_info" dataNode="dn2,dn3" rule="is_auto_sharding_rule"  primaryKey="payment_info_id"></table>

在这里插入图片描述

  • ② 编辑rule.xml配置规则

<!-- 范围分片 -->
 <tableRule name="is_auto_sharding_rule">
           <rule>
                   <columns>order_id</columns>
                   <algorithm>rang-long</algorithm>
           </rule>
  </tableRule>

 <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
         <property name="mapFile">autopartition-long.txt</property>
 
         <!--
            默认节点配置:小于0不设置默认节点、大于等于0表示设置默认节点,若碰到不识别的枚举值则路由到该节点、不设置则报错。
          -->
         <property name="defaultNode">0</property>

 </function>

在这里插入图片描述

  • ③ 编辑autopartition-long.txt配置范围区间
#编辑命令
vim autopartition-long.txt

#order_id 在0·100之间分一片
0-100=0
101-200=1
  • ④ 测试
#支付信息表
CREATE TABLE tb_payment_info(
payment_info_id INT(11) PRIMARY KEY AUTO_INCREMENT,
order_id INT(11) COMMENT '订单ID',
payment_status INT COMMENT '支付状态'
);

INSERT INTO tb_payment_info(payment_info_id,order_id,payment_status) VALUES(1,78,0);
INSERT INTO tb_payment_info(payment_info_id,order_id,payment_status) VALUES(2,96,1);
INSERT INTO tb_payment_info(payment_info_id,order_id,payment_status) VALUES(3,132,0);
INSERT INTO tb_payment_info(payment_info_id,order_id,payment_status) VALUES(4,105,0);

在这里插入图片描述

6、MyCat 日期分片

  • ① 编辑schema.xml
 <!-- 日期分片 -->
<table name="tb_login_info" dataNode="dn2,dn3" rule="is_date_sharding_rule"  primaryKey="login_info_id"></table>

在这里插入图片描述

  • ② 编辑rule.xml配置规则
 <!--日期分片 -->
<tableRule name="is_date_sharding_rule">
           <rule>
                   <columns>login_date</columns>
                   <algorithm>shardingByDate</algorithm>
           </rule>
  </tableRule>


 <function name="shardingByDate" class="io.mycat.route.function.PartitionByDate">
         <!--日期格式 -->
         <property name="dateFormat">yyyy-MM-dd</property>

         <!--起始日期 -->
         <property name="sBeginDate">2020-01-01</property>

         <!-- 结束日期:到达这个日期则会循环插入 -->
         <property name="sEndDate">2020-01-04</property>

         <!-- 分区天数、即从开始日期算起、分割2天一个分区 -->
         <property name="sPartionDay">2</property>

 </function>

在这里插入图片描述

  • ③ 测试
#用户登录信息表
CREATE TABLE tb_login_info(
login_info_id INT(11) PRIMARY KEY AUTO_INCREMENT,
user_id INT(11) COMMENT '用户ID',
login_date DATETIME COMMENT '登录时间'
);

INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(1,101,'2020-01-29 18:35:42');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(2,102,'2020-01-29 18:54:30');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(3,103,'2020-01-30 09:35:42');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(4,104,'2020-01-30 12:35:01');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(5,105,'2020-02-01 01:35:00');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(6,106,'2020-02-01 01:21:12');
INSERT INTO tb_login_info(login_info_id,user_id,login_date) VALUES(7,107,'2020-02-02 02:35:42');

在这里插入图片描述

7、MyCat全局序列

  • 在实现分库分表的情况下,数据库的自增策略已经无法保证全局唯一ID,为此,Mycat提供了全局sequenue且提供了如下多种实现方式

    • 本地文件: 此方式Mycat将sequence配置到文件中,当使用到sequence中的配置后,Mycat会更新classpath中的sequence_conf.properties文件中的sequence当前的值。

      • 优点: 本地加载,读取速度快
      • 缺点: 抗风险能力差,Mycat所在主机宕机后,无法读取。
    • 数据库方式: 利用数据库的一个表来进行计数累加,但是不是每次生成的序列都读写数据库,这样效率过低。Mycat会预加载一部分号段到Mycat的内存中,这样大部分序列都是在内存中完成的。如果号段用完了Mycat会再向数据库获取一次。

    • 时间戳方式: 全局序列ID=64位二进制(42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))换算成十进制为18位数的long类型,每毫秒可以并发12位二进制的累加。
      -优点: 配置比较简单

      • 缺点: 18位ID过长
    • 自主生成全局序列: 利用Redis的单线程原子性incr来生成序列。

  • ① 在dn2创建全局序列

#创建数据库
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 100, PRIMARY KEY(name)) ENGINE=InnoDB;

#获取当前sequence值的函数
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER $
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64)     CHARSET utf8
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 ;

#设置sequence值的函数
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER $
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS     varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $
DELIMITER ;

#获取下一个sequence值的函数
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER $
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64)     CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $
DELIMITER ;


#初始化sequence初始值
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('MYCAT_SEQUENCE', 999, 100);

在这里插入图片描述

  • ② 编辑sequence_db_conf.properties文件修改序列
#编辑命令
vim sequence_db_conf.properties

MYCAT_SEQUENCE=dn2

在这里插入图片描述

  • ③ 编辑server.xml 开启数据库访问
#约18行  0-本地文件   1-数据库模式  2-时间戳方式
vim server.xml

<property name="sequnceHandlerType">1</property>
  • ④ 测试sequence
# MYCATSEQ_ 加上序列名称
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(NEXT VALUE FOR  MYCATSEQ_MYCAT_SEQUENCE,1,1535784,1358.65);
INSERT INTO tb_orders(order_id,order_type,customer_id,order_amount) VALUES(NEXT VALUE FOR  MYCATSEQ_MYCAT_SEQUENCE,1,3565784,1358.65);

在这里插入图片描述

五、Mycat 高可用集群搭建

  • 更新暂无…
发布了109 篇原创文章 · 获赞 151 · 访问量 7万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 护眼 设计师: 闪电赇

分享到微信朋友圈

×

扫一扫,手机浏览