MyCat


一、Mycat

1、介绍

Mycat是开源的、活跃的、基于Java语言编写的MySQL数据库中间件。可以像使用mysql一样来使用mycat,对于开发人员来说根本感觉 不到mycat的存在。(伪装协议)

项目中,只需要将数据库连接换为mycat就可以了,其他都不需要动

官网:http://www.mycat.org.cn/

下载:http://dl.mycat.org.cn/

文档:https://www.yuque.com/books/share/6606b3b6-3365-4187-94c4-e51116894695/swswoy

2、安装

本文使用的版本是 1.6.7.4

需要安装 jdk ,并配置环境变量

下载后上传到服务器并解压

tar -vxzf Mycat-server-1.6.7.4-release-20210913163959-linux.tar.gz

解压后的文件结构

bin : 存放可执行文件,用于启动停止mycat
conf:存放mycat的配置文件
lib:存放mycat的项目依赖包(jar)
logs:存放mycat的日志文

如果使用的 mysql 版本较高,需要手动替换 lib 文件夹下的 mysql-conector-java 依赖,如果mysql不是使用8.0以上的,就不需要替换

然后需要对刚上传的jar进行授权

chmod 777 mysql-connector-java-8.0.17.jar

安装完成

3、核心概念

image-20220219232240319

4、基本使用-水平分表

案例:对 tb_order 这张表进行水平分库,一个库在阿里云服务器,一个在阿里云RDS数据库。

确保 MySQL 数据库配置文件中已配置 lower_case_table_names=1 ,不区分大小写。

(1)分片配置

修改 mycat 安装目录下的conf下的 schema.xml

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

    <!-- 逻辑库 -->
    <!-- name="库名" checkSQLschema="true" sqlMaxLimit="100" -->
    <!-- table name 属性使用逗号分割配置多个表,即多个表使用这个配置 -->
    <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
        <!-- 逻辑表 dataNode=分片列表 rule=分片规则 -->
        <table name="tb_order" dataNode="dn1,dn2" rule="auto-sharding-long" />
    </schema>

    <!-- 分片,dataHost=节点主机 -->
    <dataNode name="dn1" dataHost="aliyun" database="my_test2" />
    <dataNode name="dn2" dataHost="rds" database="my_test2" />

    <dataHost name="aliyun" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
        <!-- 心跳 -->
        <heartbeat>select user()</heartbeat>
        <!-- 数据库连接信息,注意此处url参数之间用&amp;取代& -->
        <writeHost host="hostS1" url="jdbc:mysql://120.79.69.164:3306/my_test2?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai" 
                    user="root" password="Root_211964" />

    </dataHost>

        <dataHost name="rds" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
        <!-- 心跳 -->
        <heartbeat>select user()</heartbeat>
        <!-- 数据库连接信息 -->
        <writeHost host="hostS1" url="jdbc:mysql://rm-wz96qu13c8715za9kfo.mysql.rds.aliyuncs.com:3306/my_test2?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai" 
                    user="root" password="Root_211964" />

    </dataHost>

</mycat:schema>

image-20220220165610659

(2)权限配置

修改 mycat 安装目录下的conf下的 server.xml

<!-- 确保这个id的生成策略为2 ,表示为根据时间戳 -->
<property name="sequnceHandlerType">2</property>
...
<!-- 配置用户权限 -->
<user name="root" defaultAccount="true">
    <property name="password">Root_211964</property>
    <!-- 用户可访问的逻辑库,多个库之间用逗号隔开 -->
    <property name="schemas">TESTDB</property>
</user>

<user name="user">
    <property name="password">Root_211964</property>
    <property name="schemas">TESTDB</property>
    <!-- 只读 -->
    <property name="readOnly">true</property>
</user>
...

(3)分片规则

逻辑表的分片规则:rule="auto-sharding-long",默认节点数为 3,当我们的节点数不等于3时,会报错

Caused by: 
io.mycat.config.util.ConfigException: 
Illegal table conf : 
table [ TB_ORDER ] rule function [ rang-long ] partition size : 3 > table datanode size : 2, please make sure table datanode size = function partition size

修改 rule.xml

<!-- 添加defaultNode ,设定默认节点为0 ,不设定就会报错 -->
<function name="rang-long"
         class="io.mycat.route.function.AutoPartitionByLong">
         <property name="mapFile">autopartition-long.txt</property>
         <property name="defaultNode">0</property>
 </function>

修改 autopartition-long.txt,设定分片大小和规则

vim ./conf/autopartition-long.txt

#默认是三个,我们需要删除最后一个,不然就会报错,说节点少了
#K=1000条记录,M=10000条记录,那么下面三个配置就是0~500万的记录会存在数据库节点1的表中,500万~1000万会存在节点2的表中
0-500M=0
500M-1000M=1

该分片规则是用 id 字段判断,存储的数据 id 小于等于 500万存到第一个节点,大于500万小于等于1000万存到第二个节点,如果只有2节点,存储的id大于1000万时,报错。

(4)测试

在两台服务器创建对应的数据库,无需创建表

切换到Mycat的安装目录,执行如下指令,启动Mycat:

# 启动命令
bin/mycat start
# 停止命令
bin/mycat stop

Mycat启动之后,占用端口号 8066。

启动完毕之后,可以查看logs目录下的启动日志,查看Mycat是否启动完成。

tail -f logs/wrapper.log

连接 mycat ,和连接mysql一样(也可以使用navicat)

mysql -h 主机IP -P 8066 -uroot -p密码

在 Mycat 创建表

CREATE TABLE `tb_order` (
  `id` bigint(1) NOT NULL,
  `user_name` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

5、schema.xml 配置

(1)schema标签

<!-- 逻辑库 -->
<!-- table name 属性使用逗号分割配置多个表,即多个表使用这个配置 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
    <!-- 逻辑表 dataNode=分片列表 rule=分片规则 -->
    <table name="tb_order" dataNode="dn1,dn2" rule="auto-sharding-long" />
</schema>

schema 标签用于定义MyCat实例中的逻辑库, 一个MyCat实例中, 可以有多个逻辑库, 可以通过 schema 标签来划分不同的逻辑库。

MyCat中的逻辑库的概念, 等同于MySQL中的database概念, 需要操作某个逻辑库下的表时, 也需要切换逻辑库(use xxx)。

核心属性:

  • name:指定自定义的逻辑库库名
  • checkSQLschema:在SQL语句操作时指定了数据库名称,执行时是否自动去除;true:自动去除,false:不自动去除
  • sqlMaxLimit:如果未指定limit进行查询,列表查询模式查询多少条记录

(2)table标签

table 标签定义了MyCat中逻辑库schema下的逻辑表, 所有需要拆分的表都需要在table标签中定义。

table 标签核心属性:

  • name:定义逻辑表表名,在该逻辑库下唯一
  • dataNode:定义逻辑表所属的dataNode,该属性需要与dataNode标签中name对应;多个dataNode逗号分隔
  • rule:分片规则的名字,分片规则名字是在rule.xml中定义的
  • primaryKey:逻辑表对应真实表的主键
  • type:逻辑表的类型,目前逻辑表只有全局表和普通表,如果未配置,就是普通表;全局表,配置为global

(3)dataNode标签

<!-- 分片,dataHost=节点主机 -->
<dataNode name="dn1" dataHost="aliyun" database="my_test2" />

dataNode标签中定义了MyCat中的数据节点, 也就是我们通常说的数据分片。一个dataNode标签就是一个独立的数据分片。

核心属性:

  • name:定义数据节点名称
  • dataHost:数据库实例主机名称,引用自dataHost 标签中name属性
  • database:定义分片所属数据库

(4)dataHost标签

<dataHost name="aliyun" maxCon="1000" minCon="10" balance="0"
          writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
    <!-- 心跳 -->
    <heartbeat>select user()</heartbeat>
    <!-- 数据库连接信息,注意此处url参数之间用&amp;取代& -->
    <writeHost host="hostS1" url="jdbc:mysql://120.79.69.164:3306/my_test2?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai" 
               user="root" password="Root_211964" />

</dataHost>

该标签在MyCat逻辑库中作为底层标签存在, 直接定义了具体的数据库实例、读写分离、心跳语句。

核心属性:

  • name:唯一标识,供上层标签使用(dataNode标签)

  • maxCon/minCon:最大连接数/最小连接数

  • balance:负载均衡策略,取值 0,1,2,3 (读写分离处使用)

  • writeType:写操作分发方式

    • 0:写操作转发到第一个writeHost,第一个挂了,切换到第二个;
    • 1:写操作随机分发到配置的writeHost
  • dbDriver:数据库驱动,支持native、jdbc

6、rule.xml 配置

rule.xml中定义所有拆分表的规则, 在使用过程中可以灵活的使用分片算法, 或者对同一个分片算法使用不同的参数, 它让分片过程可配 置化。主要包含两类标签:tableRule、Function。

image-20220220211730027

(1)tableRule 标签

<tableRule name="auto-sharding-long">
    <rule>
        <!-- 根据id字段进行分片 -->
        <columns>id</columns>
        <!-- 分片算法,引用Function标签 -->
        <algorithm>rang-long</algorithm>
    </rule>
</tableRule>

(2)function标签

<function name="rang-long"
          class="io.mycat.route.function.AutoPartitionByLong">
    <!-- 关联的可配置参数的外部文件 -->
    <property name="mapFile">autopartition-long.txt</property>
    <property name="defaultNode">0</property>
</function>

7、server.xml 配置

server.xml配置文件包含了MyCat的系统配置信息,主要有两个重要的标签:system、user。

(1)system 标签

对应的系统配置项及其含义,参考资料。

<system>
    <property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
    <property name="ignoreUnknownCommand">0</property><!-- 0遇上没有实现的报文(Unknown command:),就会报错、1为忽略该报文,返回ok报文。
    在某些mysql客户端存在客户端已经登录的时候还会继续发送登录报文,mycat会报错,该设置可以绕过这个错误-->
    <property name="useHandshakeV10">1</property>
    <property name="removeGraveAccent">1</property>
    <property name="useSqlStat">0</property>  <!-- 1为开启实时统计、0为关闭 -->
    <property name="useGlobleTableCheck">0</property>  <!-- 1为开启全加班一致性检测、0为关闭 -->
    <property name="sqlExecuteTimeout">300</property>  <!-- SQL 执行超时 单位:秒-->
    ...
</system>

(2)user 标签

配置用户及其权限

image-20220220212547910

8、垂直分库

(1)基本配置

image-20220221203627377

<!-- =================垂直分库======================================== -->
<schema name="my_test3" checkSQLschema="true" sqlMaxLimit="100">
    <!-- 逻辑表 dataNode=分片列表 rule=分片规则 -->
    <table name="tb_shopping" dataNode="aliyun" primaryKey="id" />
    <table name="tb_address" dataNode="rds" primaryKey="id" />
</schema>

<!-- 分片,dataHost=节点主机 -->
<dataNode name="aliyun" dataHost="aliyun" database="my_test2" />
<dataNode name="rds" dataHost="rds" database="my_test2" />

primaryKey:表的主键,这里不需要 rule 属性,rule 属性时用来定义分片规则的,这里一张表只存在一个数据库,不需要分片

dataHost 标签同上,这里就不写了。

(2)创建表

  • 只需在 Mycat 创建表,Mycat 即会将表创建到指定的数据库。

  • 创建没有配置的表会报错。

  • 表在命令行可以显示全部配置的表,但用 navicat 等工具每次只能展示其中一个mysql数据库中的表,包括mysql节点中未配置的表,navicat刷新一下,有展示的是另一个mysql节点的全部表。好奇怪啊!!!

(3)多表联查

在 Mcat 中使用多表联查时:

  • 多张表在同一个分片中,可以执行
  • 多张表在不同分片中,不能执行,报错

此时应该将一些多个业务中都会用到的表,如字典表,设置为全局表

(4)配置全局表

<schema name="my_test3" checkSQLschema="true" sqlMaxLimit="100">
    <table name="tb_dict" dataNode="aliyun,rds" primaryKey="id" type="global" />
</schema>

当执行创建表的语句时,会在全局表所配置的所有分片中创建表

对全局表进行插入数据时,也会对所有分片进行插入

9、水平分表

在业务系统中, 有一张表(日志表), 业务系统每天都会产生大量的日志数据, 单台服务器的数据存储及处理能力是有限的, 可以对数据库表 进行拆分。

定义一个逻辑表,拥有多个节点

水平分表核心是分片规则

image-20220302192601735

配置完启动mycat,需要优先创建数据库

10、分片规则

(1)范围分片

根据指定的字段及其配置的范围与数据节点的对应情况, 来决定该数据属于哪一个分片。

注意:只能指定数字类型的字段

如:id 为0到500万存放到第一个节点

500万到1000万存放到第二个节点

1000万到1500万存放到第三个节点

schema.xml 中配置逻辑表

<table name="tb_order" dataNode="aliyun,rds" rule="auto-sharding-long" />

rule.xml 中配置相关分片字段

<tableRule name="auto-sharding-long">
    <rule>
        <columns>id</columns>
        <algorithm>rang-long</algorithm>
    </rule>
</tableRule>

image-20220302193704606

(2)取模

根据指定的字段值与节点数量进行求模运算(分散存储),根据运算结果, 来决定该数据属于哪一个分片。

注意:只能指定数字类型的字段

如:id 为 9,模于 节点数 3,得到结果 0,落在第一个节点

id 为 10,模于 节点数 3,得到结果 1,落在第二个节点

id 为 11,模于 节点数 3,得到结果 2,落在第三个节点

image-20220302193751961

(3)一致性 hash

所谓一致性哈希,相同的哈希因子计算值总是被划分到相同的分区表中,不会因为分区节点的增加而改变原来数据的分区位置。

注意:指定字段不一定要是数字

image-20220302194343712

(4)枚举

通过在配置文件中配置可能的枚举值, 指定数据分布到不同数据节点上, 本规则适用于按照省份、性别、状态拆分数据等业务 。

image-20220302195012099

(5)应用指定

运行阶段由应用自主决定路由到那个分片, 直接根据字符子串(必须是数字)计算分片号。

image-20220302203642848

(6)固定分片hash算法

该算法类似于十进制的求模运算,但是为二进制的操作,例如,取id 的二进制低10 位 与 1111111111 进行位& 运算。

0 或 1 和 1 进行 & 运算之后,值为它本身。

特点:

➢ 如果是求模,连续的值,分别分配到各个不同的分片;但是此算法会将连续的值可能分配到相同的分片,降低事务处理的难度。

➢ 可以均匀分配,也可以非均匀分配。

➢ 分片字段必须为数字类型。

image-20220302203836178

(7)字符串hash解析

截取字符串中的指定位置的子字符串, 进行hash算法,算出分片。

image-20220302204321589

(8)按(天)日期分片

image-20220302204358277

(9)自然月

使用场景为按照月份来分片, 每个自然月为一个分片。

image-20220302204437653

二、MyCat读写分离

读写分离,简单地说是把对数据库的读和写操作分开,以对应不同的数据库服务器。主数据库提供写操作,从数据库提供读操作,这样能有效 地减轻单台数据库的压力。

通过MyCat即可轻易实现上述功能,不仅可以支持MySQL,也可以支持Oracle和SQL Server。

image-20220309210918613

1、一主一从

搭建方式见主从复制

原理:MySQL的主从复制,是基于二进制日志(binlog)实现的。

配置:MyCat控制后台数据库的读写分离和负载均衡由schema.xml文件datahost标签的balance属性控制。

image-20220309211056127

需要注意的是 datahost 标签的属性 balance 是用于配置负载均衡策略,目前有如下4种取值

参数值 含义
0 不开启读写分离机制 所有读操作都发送到当前可用的writeHost
1 全部的 readHost与备用的writeHost 都参与 select语句的负载均衡(主要针对于双主双从模式)
2 所有的读写操作都随机在writeHostreadHost上分发
3 所有的读请求随机分发到writeHost对应的 readHost上执行,writeHost 不负担读压力

1 和 3 为读写分离

配置好以上配置后,即可实现读写分离

问题:主节点Master宕机之后,业务系统就只能够读,而不能写入数据了。

2、双主双从搭建

一个主机Master1 用于处理所有写请求,它的从机 Slave1 和另一台主机Master2 还有它的从机Slave2 负责所有读请求。当 Master1 主机宕机后,Master2 主机负责写请求,Master1 、Master2 互为备机。架构图如下:

image-20220309212343696

其实双主双从根本上是 3 组主从复制:

  • 主库1、从库1 — 单向主从
  • 主库2、从库2 — 单向主从
  • 主库1、主库2 — 双向主从

(1)主库配置

修改配置文件/etc/my.cnf

2 台主库配置有且只有 server-id ,不同

# mysql 服务id,保证整个集群环境中唯一,取值范围:1 到 2的31次方减1,默认为1
server-id=1
# 指定要同步的数据库
binlog-db=db01
#在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates

重启数据库

systemctl restart mysqld

两台主库创建账户并授权

# 创建 rewind 用户,并设置密码,%表示该用户可在任意主机连接mysql服务
create user 'rewind'@'%' identified with mysql_native_password by '123456';
# 为 rewind 用户分匹配主从复制权限
grant replication slave on *.* to 'rewind'@'%';

通过指令,查看两台主库的二进制日志坐标

show master status;

字段含义说明:

  • file : 从哪个日志文件开始推送日志文件
  • position : 从哪个位置开始推送日志
  • binlog_ignore_db : 指定不需要同步的数据库

(2)从库配置

修改配置文件/etc/my.cnf

# mysql 服务id,保证整个集群环境中唯一,取值范围:1 到 2的31次方减1,默认为1
server-id=3

重启后,两台从库配置关联的主库

CHANGE MASTER TO MASTER_HOST='XXX.XXX',MASTER_USER='XXX',MASTER_PASSWORD='XXX',MASTER_LOG_FILE='mysql-bin.000988',MASTER_LOG_POS=386021;

需要注意slave1对应的是master1,slave2对应的是master2。

启动两台从库主从复制,查看从库状态

# 启动 ,8.0.22 之前
start slave;
# 查看状态,8.0.22 之前
show slave status\G

查看系统返回信息中 Slave_IO_Running 和 Slave_SQL_Running 的状态是否为 Yes。

(3)双主同步配置

Master2 复制 Master1,Master1 复制 Master2。

CHANGE MASTER TO MASTER_HOST='XXX.XXX',MASTER_USER='XXX',MASTER_PASSWORD='XXX',MASTER_LOG_FILE='mysql-bin.000988',MASTER_LOG_POS=386021;

启动两台主库库主从复制,查看状态

# 启动 ,8.0.22 之前
start slave;
# 查看状态,8.0.22 之前
show slave status\G

3、双主双从读写分离

MyCat控制后台数据库的读写分离和负载均衡由schema.xml文件datahost标签的balance属性控制,通过writeType及switchType来完成失 败自动切换的。

image-20220309214351712

image-20220309214404662

登录MyCat,测试查询及更新操作,判定是否能够进行读写分离,以及读写分离的策略是否正确。

当主库挂掉一个之后,是否能够自动切换。


  目录