MyCAT 2实现mysql8主从同步读写分离
一、MyCAT2介绍
1.1 什么是MyCAT?
MyCAT是目前最流行的分布式数据库中间插件,是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器。前端用户可以把它看作一个数据库代理,用MySQL客户端工具和命令行访问,其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。
MyCAT发展到目前,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储。未来,它还会支持更多类型的存储。
不过,无论是哪种存储方式,在最终用户看,MyCAT里都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度。
1.2 为什么使用MyCAT?
随着互联网的发展,数据的量级也是呈指数的增长,从GB到TB到PB,操作数据也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求。
而NoSQL的出现暂时解决了这一危机。NoSQL通过降低数据的安全性,减少对事务的支持,减少对复杂查询的支持,来提升性能。 但是,NoSQL存在无法满足某些使用场景的情况,比如,有些使用场景绝对要有事务与安全指标。这时NoSQL肯定无法满足。所以,我们还是需要使用关系型数据库。
那么,如何使用关系型数据库解决海量存储的问题呢?此时就需要做数据库集群,为了提高查询性能将一个数据库的数据分散到不同的数据库中存储,为应对该问题,MyCAT 就出现了。
MyCAT的作用:
1)能满足数据库数据大量存储;
2)提高了查询性能;
3)实现读写分离,分库分表。
此外,MyCAT还可以解决如下问题:
1)解决表的容量问题:MySQL的表最大存储多少数据?500W条。
2)解决表查询的性能问题?我的表里面的数据非常多,导致我查询很慢?
3)解决表的DML的性能问题?
4)解决MySQL挂了的问题。
1.3 MyCAT解决问题的思路
(1)容量
(2)查询速度
最快也是Log(n),你加什么索引都不行。
(3)写入问题
1.4 数据库中间件对比
1.5 MyCAT和MySQL的区别
们可以把上层看作是对下层的抽象,例如操作系统是对各类计算机硬件的抽象。那么我们什么时候需要抽象?
假设一个项目只需要一个人完成时,我们不需要Leader,但是当需要几十人完成时,就应该有一个管理者,发挥沟通协调等作用,这个管理者对于他的上层来说就是对项目组的抽象。
同样的,当我们的应用只需要一台数据库服务器时,我们并不需要MyCAT,如果你需要分库甚至分表,这时候应用要面对很多个数据库时,这时,就需要对数据库层做一个抽象,来管理这些数据库,最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是MyCAT的核心作用。
所以你可以这样理解:数据库是对底层存储文件的抽象,而MyCAT是对数据库的抽象。
1.6 MyCAT1.x 和 MyCAT2 功能对比
功能 | 1.6 | 2 |
---|---|---|
多语句 | 不支持 | 支持 |
blob值 | 支持一部分 | 支持 |
全局二级索引 | 不支持 | 支持 |
任意跨库join(包含复杂查询) | catlet支持 | 支持 |
分片表与分片表JOIN查询 | ER表支持 | 支持 |
关联子查询 | 不支持 | 支持一部分 |
分库同时分表 | 不支持 | 支持 |
存储过程 | 支持固定形式的 | 支持更多 |
支持逻辑视图 | 不支持 | 支持 |
支持物理视图 | 支持 | 支持 |
批量插入 | 不支持 | 支持 |
执行计划管理 | 不支持 | 支持 |
路由注释 | 支持 | 支持 |
集群功能 | 支持 | 支持更多集群类型 |
自动hash分片算法 | 不支持 | 支持 |
支持第三方监控 | 支持mycat-web | 支持普罗米斯,kafka日志等监控 |
流式合拼结果集 | 支持 | 支持 |
范围查询 | 支持 | 支持 |
单表映射物理表 | 不支持 | 支持 |
XA事务 | 弱XA | 支持,事务自动恢复 |
支持MySQL8 | 需要更改mysql8的服务器配置支持 | 支持 |
虚拟表 | 不支持 | 支持 |
joinClustering | 不支持 | 支持 |
union all语法 | 不支持 | 支持 |
BKAJoin | 不支持 | 支持 |
优化器注释 | 不支持 | 支持 |
ER表 | 支持 | 支持 |
全局序列号 | 支持 | 支持 |
保存点 | 不支持 | 支持 |
离线迁移 | 支持 | 支持(实验) |
增量迁移 | CRC32算法支持 | BINLOG追平(实验) |
安全停机 | 不支持 | 支持(实验) |
HAProxy协议 | 不支持 | 支持 |
会话粘滞 | update后select会粘滞 | update后select会粘滞且支持设置时间 |
全局表插入支持全局序列号 | 不支持 | 支持 |
全局表插入支持主表插入自增结果作为序列号 | 不支持 | 支持 |
外部调用的分片算法 | 不支持但可定制 | 支持 |
1.7 架构
前端用户可以把MyCAT看作是一个数据库代理,用MySQL客户端工具(如Navicat)和命令访问,而后端支持MySQL、SQL Server、Oracle等主流数据库,用MySQL Native 协议和多个MySQL服务器通信,也可用JDBC协议与大多数主流数据库服务器通信,其核心功能就是分库分表,即将一个大表水平分割为N个小表,真正的存储在后端MySQL服务器中或其他数据库中。
1.8 MyCAT功能
(1)读写分离
(2)数据分片
垂直拆分(分库)、水平拆分(分表)、垂直+水平拆分(分库分表)
(3)多数据整合
MyCAT原理:可以用“拦截”一词形容,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析,如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当处理,最终返回给用户。
二、MyCAT2名词解释
(1)分库分表
按照一定规则把数据库中的表拆分为多个带有数据库实例、物理库、物理表访问路径的分表。
(2)逻辑库
数据库代理中的数据库,它可以包含多个逻辑表。
(3)逻辑表
数据库代理中的表,它可以映射代理连接的数据库中的表(物理表)。
(4)物理库
数据库代理连接的数据库中的库,比如MySQL上的information_schema。
(5)物理表
数据库代理连接的数据库中的表,比如MySQL上的information_schema.TABLES。
(6)拆分键
即分片键,描述拆分逻辑表的数据规则的字段。
(7)分区键
当使用等值查询的时候,能直接映射一个分区的拆分键。
(8)物理分表
指已经进行数据拆分的,在数据库上面的物理表,是分片表的一个分区。
(9)物理分库
一般指包含多个物理分表的库。
(10)分库
一般指通过多个数据库拆分分片表,每个数据库一个物理分表,物理分库名字相同。
(11)分片表、水平分片表
按照一定规则把数据拆分成多个分区的表,在分库分表语境下,它属于逻辑表的一种。
(12)全局表(广播表)
每个数据库实例都冗余全量数据的逻辑表。
它通过表数据冗余,使分片表的分区与该表的数据在同一个数据库实例里,达到JOIN运算能够直接在该数据库实例里执行。它的数据一致一般是通过数据库代理分发SQL实现,也有基于集群日志的实现。
(13)集群
多个数据节点组成的逻辑节点,在MyCAT2里,它是把对多个数据源地址视为一个数据源地址(名称),并提供自动故障恢复、转移、即实现高可用、负载均衡的组件。
(14)数据源
连接后端数据库的组件,它是数据库代理中连接后端数据库的客户端。
(15)schema(库)
在MyCAT2中配置表逻辑,视图等的配置。
三、安装MyCAT 2
前提:使用MyCAT 2要按照 jdk,MyCAT 2基于JDK 1.8开发
[root@localhost ~]# dnf install jdk-8u261-linux-x64.rpm
[root@localhost ~]# java -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)
(1)下载安装包
安装程序包: http://dl.mycat.org.cn/2.0/install-template/mycat2-install-template-1.21.zip
Jar包:http://dl.mycat.org.cn/2.0/1.21-release/mycat2-1.21-release-jar-with-dependencies.jar
# 解压安装包:
[root@localhost ~]# unzip mycat2-install-template-1.21.zip -d /usr/local
# 复制jar到mycat/lib目录:
[root@localhost ~]# cp mycat2-1.21-release-jar-with-dependencies.jar /usr/local/mycat/lib/
# 把bin目录的文件加执行权限:
[root@localhost ~]# chmod +x /usr/local/mycat/bin/*
(2)启动MySQL,添加mycat用户
因为mycat代理启动时需要一个默认的数据源,所以我们在启动时为其准备一个数据源。
# 安装mysql
[root@localhost ~]# yum install mysql-server -y
# 启动mysql
[root@localhost ~]# systemctl enable --now mysqld
# 修改root密码
[root@localhost ~]# mysqladmin -uroot password '123456'
# 在master上创建用户:
mysql> CREATE USER 'mycat'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
mysql> GRANT XA_RECOVER_ADMIN ON *.* TO 'mycat'@'%';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'mycat'@'%' ;
(3)配置物理库地址
启动之前配置物理库地址。这里使用默认值。
[root@localhost ~]# cat /usr/local/mycat/conf/datasources/prototypeDs.datasource.json
{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"prototypeDs",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"root",
"weight":0
}
(4)启动mycat
cd mycat/bin
./mycat start
./mycat status
./mycat start 启动
./mycat stop 停止
./mycat console 前台运行
./mycat install 添加到系统自动启动(暂未实现)
./mycat remove 取消随系统自动启动(暂未实现)
./mycat restart 重启服务
./mycat pause 暂停
./mycat status 查看启动状态…
[root@localhost ~]# cd /usr/local/mycat/bin
[root@localhost bin]# ./mycat start
Starting mycat2...
[root@localhost bin]# ./mycat status
mycat2 is running (5427).
(5)登录Mycat
管理端口9066;数据端口8066。
# 登录数据端口
[root@localhost bin]# mysql -uroot -p123456 -P8066 -h192.168.121.51
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 0
Server version: 5.7.33-mycat-2.0 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| `Database` |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.38 sec)
四、MyCAT2配置文件介绍
4.1 用户(user)
这个配置文件主要是用来配置MyCAT的登录用户的,也就是我们连接8066这个端口的用户信息。
配置文件位置:mycat/conf/user/{用户名}.user.json
{
"dialect":"mysql",
"ip":null,
"password":"123456",
"transactionType":"proxy",
"username":"root"
}
配置说明:
1)dialect:数据库(方言)类型
2)ip:配置白名单使用,一般写null 如果要限制这个用户
3)password:配置MyCAT用户的密码(明文)
4)isolation:设置初始化的事务隔离级别
READ_UNCOMMITTED:1
READ_COMMITTED:2
REPEATED_READ:3,默认
SERIALIZABLE:4
5)transactionType
默认值:proxy(本地事务,在涉及大于1个数据库的事务,commit阶段失败会导致不一致,但是兼容性最好)
可选值:xa(事务,需要确认存储节点集群类型是否支持XA)
4.2 数据源(datasource)
配置MyCAT连接后端的物理库的数据源。
配置文件位置:mycat/conf/datasources/{数据源名字}.datasource.json
{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"prototypeDs",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://localhost:3306?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8",
"user":"root",
"weight":0
}
配置说明:
1)dbType:数据源类型
2)name:数据源名字
3)password:后端MySQL的密码
4)url:后端MySQL的JDBC连接地址
5)user:后端MySQL的用户名
6)weight:配置数据源负载均衡的使用权重
4.3 逻辑库与逻辑表(logicaltable)
配置MyCAT里面和MySQL对应的逻辑表。
配置文件位置:mycat/conf/schemas/{库名}.schema.json
{
"customTables": {},
"globalTables": {},
"normalTables": {},
"schemaName": "test",
"shardingTables": {},
"targetName": "prototype"
}
配置说明:
1)customTables:自定义表
2)globalTables:全局表
3)normalTables:默认表
4)schemaName:库名
5)shardingTables:分片表
6)targetName:数据源名,也可以是集群名
4.4 序列号(sequence)
使用序列号的分片表,对应的自增主键要在建表SQL中体现。
配置文件位置: mycat/conf/sequences/{数据库名字}_{表名字}.sequence.json。
4.5 服务器(server)
这个是针对MyCAT的服务器的配置,一般情况下默认就行了,不用怎么配置。
五、MyCAT2注释配置
5.1 重置配置
/*+ mycat:resetConfig{} */
5.2 用户相关
(1)创建用户
/*+ mycat:createUser{
"username":"user",
"password":"",
"ip":"127.0.0.1",
"transactionType":"xa"}
*/
(2)删除用户
/*+ mycat:dropUser{ "username":"user"} */
(3)显示用户
/*+ mycat:showUsers */
5.3 数据源相关
(1)创建数据源
/*+ mycat:createDataSource{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"dc1",
"password":"123456",
"type":"JDBC",
"url":"jdbc:mysql://127.0.0.1:3306?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF-8",
"user":"root",
"weight":0}
*/;
(2)删除数据源
/*+ mycat:dropDataSource{
"dbType":"mysql",
"idleTimeout":60000,
"initSqls":[],
"initSqlsGetConnection":true,
"instanceType":"READ_WRITE",
"maxCon":1000,
"maxConnectTimeout":3000,
"maxRetryCount":5,
"minCon":1,
"name":"dc1",
"type":"JDBC",
"weight":0}
*/;
(3)显示数据源
/*+ mycat:showDataSources{} */
5.4 集群相关
(1)创建集群
先创建两个数据源dc1和dc2,然后创建集群,dc1是主节点
/*! mycat:createCluster{
"clusterType":"MASTER_SLAVE",
"heartbeat":{
"heartbeatTimeout":1000,
"maxRetry":3,
"minSwitchTimeInterval":300,
"slaveThreshold":0
},
"masters":[
"dc1" //主节点
],
"maxCon":200,
"name":"c0",
"readBalanceType":"BALANCE_ALL",
"replicas":[
"dc2" //从节点
],
"switchType":"SWITCH"
} */
(2)删除集群
/*! mycat:dropCluster{ "name":"c0"} */;
(3)显示集群
/*+ mycat:showClusters{} */
六、MyCAT2的主从配置
前提,先搭建好MySQL的主从配置,登录MyCAT 2在MyCAT2里面操作,也就是连接8066这个端口。
(1)创建逻辑库
[root@localhost ~]# mysql -uroot -p123456 -P8066 -h192.168.121.51
mysql> create database mydb1;
(2)使用注解方式添加数据源
#登录Mycat,注解方式添加数据源,指向从机
/*+ mycat:createDataSource{
"name":"rwSepw",
"url":"jdbc:mysql://192.168.121.11:3306/?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true",
"user":"mycat",
"password":"123456"
} */
/*+ mycat:createDataSource{
"name":"rwSepr1",
"url":"jdbc:mysql://192.168.121.12:3306/?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true",
"user":"mycat",
"password":"123456"
} */
/*+ mycat:createDataSource{
"name":"rwSepr2",
"url":"jdbc:mysql://192.168.121.13:3306/?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true",
"user":"mycat",
"password":"123456"
} */
#查询配置数据源结果
/*+ mycat:showDataSources{} */;
(3)更新集群信息
#更新集群信息,添加dr0从节点.
/*!mycat:createCluster{"name":"prototype","masters":["rwSepw"],"replicas":["rwSepr1","rwSepr2"]} */;
#查看配置集群信息
/*+ mycat:showClusters{} */;
#查看集群配置文件
[root@proxy ~]# cat /usr/local/mycat/conf/clusters/prototype.cluster.json
{
"clusterType":"MASTER_SLAVE",
"heartbeat":{
"heartbeatTimeout":1000,
"maxRetryCount":3,
"minSwitchTimeInterval":300,
"showLog":false,
"slaveThreshold":0.0
},
"masters":[
"rwSepw"
],
"maxCon":2000,
"name":"prototype",
"readBalanceType":"BALANCE_ALL",
"replicas":[
"rwSepr1",
"rwSepr2"
],
"switchType":"SWITCH"
}
readBalanceType——查询负载均衡策略
BALANCE_ALL(默认值):获取集群中所有数据源
BALANCE_ALL_READ:获取集群中允许读的数据源
BALANCE_READ_WRITE:获取集群中允许读写的数据源,但允许读的数据源优先
BALANCE_NONE:获取集群中允许写数据源,即主节点中选择
switchType
NOT_SWITCH:不进行主从切换
SWITCH:进行主从切换
七、验证读写分离
(1)重启MyCAT
[root@localhost ~]# cd /usr/local/mycat/bin/
[root@localhost bin]# ./mycat restart
Stopping mycat2...
Stopped mycat2.
Starting mycat2...
[root@localhost bin]# ./mycat status
mycat2 is running (5710).
(2)验证读写分离(不建议,会破坏主从同步)
# 在MyCAT创建db1库:
CREATE DATABASE db1 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_
# 在MyCAT创建表:
use db1
create table sys_user(
id bigint primary key,
username varchar(200) not null,
address varchar(500)
);
# 刷新逻辑表到物理库:
/*+ mycat:repairPhysicalTable{} */;
# 在MyCAT里面添加数据:
nsert INTO sys_user(id,username,address) values(1,"xiaofang","wuhan");
# 在MyCAT里查询测试:
# 修改上面3个MySQL数据库中db1库中sys_user表里面的数据,让它不一样,再在MyCAT里面执行查询
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| master |
+------------+
mysql> update db1.sys_user
-> set address="wuhan_master";
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| slave1 |
+------------+
mysql> update db1.sys_user
-> set address="wuhan_slave1";
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| slave2 |
+------------+
mysql> update db1.sys_user
-> set address="wuhan_slave2";
最后在在mycat中查询:
# mysql -uroot -p123456 -P8066 -h192.168.121.51 -e "select * from db1.sys_user"
+----+----------+--------------+
| id | username | address |
+----+----------+--------------+
| 1 | xiaofang | wuhan_slave1 |
+----+----------+--------------+
# mysql -uroot -p123456 -P8066 -h192.168.121.51 -e "select * from db1.sys_user"
+----+----------+--------------+
| id | username | address |
+----+----------+--------------+
| 1 | xiaofang | wuhan_slave2 |
+----+----------+--------------+
# mysql -uroot -p123456 -P8066 -h192.168.121.51 -e "select * from db1.sys_user"
+----+----------+--------------+
| id | username | address |
+----+----------+--------------+
| 1 | xiaofang | wuhan_master |
+----+----------+--------------+