实现单点Mycat读写分离

下载链接1:Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz

下载链接2:Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz

如有下载不了请及时在评论区留言

架构图

image-20250802140303841

主机名 ip 内存 硬盘
master 192.168.48.10 2G 100G
slave 192.168.48.11 2G 100G
mycat 192.168.48.128 >=2G 100G
client 192.168.48.101 2G 100G

部署主从复制

安装mysql

操作节点:[master,slave]

这是我的二进制mysql安装脚本,适用于大部分的linux通用安装,如果你有自己的安排可以直接略过这个,自己安装mysql

1
2
wget https://blog.qianyios.top/file/mysql_install.sh
bash mysql_install.sh

配置master

1.修改配置文件

1
2
3
4
5
vim /etc/my.cnf
##其他安装mysql的方法,你只需要确保有如下选项就行了
[mysqld]
server-id=10
log-bin=/data/logbin/qylog

sever-id :必须是整个集群里面唯一的,不能重复

log-bin:后续会在/data/logbin生成qylog.000001的二进制文件,你可以自定义路径和文件名不用加后缀

1
2
mkdir -p /data/logbin;chown -R mysql:mysql /data/logbin
systemctl restart mysqld

2.查看二进制文件的位置

1
2
3
4
5
6
7
8
9
10
11
mysql -uroot -p123456
show master logs;

(root@localhost) [(none)]> show master logs;
+--------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+--------------+-----------+-----------+
| qylog.000001 | 157 | No |
+--------------+-----------+-----------+
1 row in set (0.00 sec)
#记住这个qylog.000001和157,主从复制要用到

3.创建传输账号

1
2
create user repluser@'192.168.48.%' identified by '123456';
grant replication slave on *.* to repluser@'192.168.48.%';

配置从节点

1.修改配置文件

1
2
3
4
5
6
7
8
#其他安装mysql的方法,你只需要确保有如下选项就行了
[mysqld]
server-id=11
log-bin=/data/logbin/qylog
read_only=ON #设置数据库只读,针对supper user无效
#启动中继日志
relay_log=/data/relaylog/relay-log #relay log的文件路径,默认值hostname-relay-bin
relay_log_index=/data/relaylog/relay-log.index #默认值hostname-relay-bin.index

sever-id :必须是整个集群里面唯一的,不能重复

log-bin:后续会在/data/logbin生成qylog.000001的二进制文件,你可以自定义路径和文件名不用加后缀

1
2
3
mkdir -p /data/logbin /data/relaylog
chown -R mysql:mysql /data/logbin /data/relaylog
systemctl restart mysqld

启动复制线程

操作节点:[slave]

1
2
3
4
5
6
7
8
9
10
mysql -u root -p123456
CHANGE MASTER TO
MASTER_HOST='192.168.48.10',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='qylog.000001',
MASTER_LOG_POS=157,
get_master_public_key=1;
start slave;
show slave status\G;

确保有两个yes就行了

image-20250802111633490

如果你想重置线程可以用以下命令

1
2
stop slave;
reset slave;

有一个重要的点,因为二进制日志是记录你的操作的嘛,我们在开启二进制日志之后,不是在主节点创建了一个repluser用户吗,那这个操作肯定也被记录,然后这不是主从复制了吗,这里肯定,也会同步,也会运行,二进制日志本身就是一个sql文件,普通cat是看不了,你得用这个命令

1
[root@master ~]# mysqlbinlog -uroot -p123456 /data/logbin/qylog.000001 -v

image-20250802111808465

所有既然主从复制了,那在从节点,应该也运行了这个二进制文件,就说明从节点也有这个账号

1
select host,user from mysql.user;

image-20250802111832716

测试

接下来在主节点导入测试数据

全选复制粘贴退出mysql运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
cat > hellodb.sql <<"EOF"

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `hellodb` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `hellodb`;

DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
`ClassID` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`Class` varchar(100) DEFAULT NULL,
`NumOfStu` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ClassID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

LOCK TABLES `classes` WRITE;
INSERT INTO `classes` VALUES
(1,'Shaolin Pai',10),(2,'Emei Pai',7),
(3,'QingCheng Pai',11),(4,'Wudang Pai',12),(5,'Riyue Shenjiao',31),
(6,'Lianshan Pai',27),(7,'Ming Jiao',27),(8,'Xiaoyao Pai',15);
UNLOCK TABLES;

DROP TABLE IF EXISTS `coc`;
CREATE TABLE `coc` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ClassID` tinyint(3) unsigned NOT NULL,
`CourseID` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

LOCK TABLES `coc` WRITE;
INSERT INTO `coc` VALUES (1,1,2),(2,1,5),(3,2,2),(4,2,6),(5,3,1),(6,3,7),(7,4,5),(8,4,2),(9,5,1),(10,5,9),(11,6,3),(12,6,4),(13,7,4),(14,7,3);
UNLOCK TABLES;

DROP TABLE IF EXISTS `courses`;
CREATE TABLE `courses` (
`CourseID` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`Course` varchar(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

LOCK TABLES `courses` WRITE;
/*!40000 ALTER TABLE `courses` DISABLE KEYS */;
INSERT INTO `courses` VALUES (1,'Hamo Gong'),(2,'Kuihua Baodian'),(3,'Jinshe Jianfa'),(4,'Taiji Quan'),(5,'Daiyu Zanghua'),(6,'Weituo Zhang'),(7,'Dagou Bangfa');
/*!40000 ALTER TABLE `courses` ENABLE KEYS */;
UNLOCK TABLES;

DROP TABLE IF EXISTS `scores`;
CREATE TABLE `scores` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`StuID` int(10) unsigned NOT NULL,
`CourseID` smallint(5) unsigned NOT NULL,
`Score` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

LOCK TABLES `scores` WRITE;
INSERT INTO `scores` VALUES (1,1,2,77),(2,1,6,93),(3,2,2,47),(4,2,5,97),(5,3,2,88),(6,3,6,75),(7,4,5,71),(8,4,2,89),(9,5,1,39),(10,5,7,63),(11,6,1,96),(12,7,1,86),(13,7,7,83),(14,8,4,57),(15,8,3,93);
UNLOCK TABLES;

DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
`StuID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`Age` tinyint(3) unsigned NOT NULL,
`Gender` enum('F','M') NOT NULL,
`ClassID` tinyint(3) unsigned DEFAULT NULL,
`TeacherID` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`StuID`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

LOCK TABLES `students` WRITE;
INSERT INTO `students` VALUES (1,'Shi Zhongyu',22,'M',2,3),(2,'Shi Potian',22,'M',1,7),(3,'Xie Yanke',53,'M',2,16),(4,'Ding Dian',32,'M',4,4),(5,'Yu Yutong',26,'M',3,1),(6,'Shi Qing',46,'M',5,NULL),(7,'Xi Ren',19,'F',3,NULL),(8,'Lin Daiyu',17,'F',7,NULL),(9,'Ren Yingying',20,'F',6,NULL),(10,'Yue Lingshan',19,'F',3,NULL),(11,'Yuan Chengzhi',23,'M',6,NULL),(12,'Wen Qingqing',19,'F',1,NULL),(13,'Tian Boguang',33,'M',2,NULL),(14,'Lu Wushuang',17,'F',3,NULL),(15,'Duan Yu',19,'M',4,NULL),(16,'Xu Zhu',21,'M',1,NULL),(17,'Lin Chong',25,'M',4,NULL),(18,'Hua Rong',23,'M',7,NULL),(19,'Xue Baochai',18,'F',6,NULL),(20,'Diao Chan',19,'F',7,NULL),(21,'Huang Yueying',22,'F',6,NULL),(22,'Xiao Qiao',20,'F',1,NULL),(23,'Ma Chao',23,'M',4,NULL),(24,'Xu Xian',27,'M',NULL,NULL),(25,'Sun Dasheng',100,'M',NULL,NULL);
UNLOCK TABLES;

DROP TABLE IF EXISTS `teachers`;
CREATE TABLE `teachers` (
`TID` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(100) NOT NULL,
`Age` tinyint(3) unsigned NOT NULL,
`Gender` enum('F','M') DEFAULT NULL,
PRIMARY KEY (`TID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

LOCK TABLES `teachers` WRITE;
INSERT INTO `teachers` VALUES (1,'Song Jiang',45,'M'),(2,'Zhang Sanfeng',94,'M'),(3,'Miejue Shitai',77,'F'),(4,'Lin Chaoying',93,'F');
UNLOCK TABLES;


DROP TABLE IF EXISTS `toc`;
CREATE TABLE `toc` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CourseID` smallint(5) unsigned DEFAULT NULL,
`TID` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `toc` WRITE;
UNLOCK TABLES;

EOF

在主节点导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
mysql -uroot -p123456 < hellodb.sql
mysql -uroot -p123456 hellodb -e "show tables;"

mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| toc |
+-------------------+

mysql -uroot -p123456
use hellodb;
insert into teachers (name,age,gender)values("XIAOHU",18,'M');
select * from teachers;

(root@localhost) [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 5 | XIAOHU | 18 | M |#这就是新加的数据
+-----+---------------+-----+--------+

在从节点查看是否同步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql -uroot -p123456 hellodb -e "use hellodb;select * from teachers;"

[root@slave ~]# mysql -uroot -p123456 hellodb -e "use hellodb;select * from teachers;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 5 | XIAOHU | 18 | M |
+-----+---------------+-----+--------+

至此主从复制成功同步

部署mycat

注意:这台机上不能用mysql等其他数据库

操作节点:[mycat]

安装jdk

1
2
3
wget https://alist.qianyios.top/d/%E6%B8%B8%E5%AE%A2/%E8%B1%86%E5%8C%85haha/%E8%BF%90%E7%BB%B4/mysql/%E5%AE%89%E8%A3%85%E5%8C%85/jdk-8u202-linux-x64.rpm?sign=1F6ZiF7m6XPKTiV2PiNEH2xIInIVrb2uHIm3TvyFXG0=:0
mv 'jdk-8u202-linux-x64.rpm?sign=1F6ZiF7m6XPKTiV2PiNEH2xIInIVrb2uHIm3TvyFXG0=:0' jdk-8u202-linux-x64.rpm
rpm -ivh jdk-8u202-linux-x64.rpm
1
2
3
4
[root@mycat ~]# java -version
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

下载安装mycat

1
2
3
4
wget https://alist.qianyios.top/d/%E6%B8%B8%E5%AE%A2/%E8%B1%86%E5%8C%85haha/%E8%BF%90%E7%BB%B4/mysql/%E5%AE%89%E8%A3%85%E5%8C%85/Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz?sign=T83V18vz0xSMy6INAGV9eAzETOL7c0gxQuZA5YYWlhw=:0
mv 'Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz?sign=T83V18vz0xSMy6INAGV9eAzETOL7c0gxQuZA5YYWlhw=:0' Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz
mkdir -p /apps
tar xf Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz -C /apps

mycat安装目录结构:

  • bin mycat命令,启动、重启、停止等
  • catlet catlet为Mycat的一个扩展功能
  • conf Mycat 配置信息,重点关注
  • lib Mycat引用的jar包,Mycat是java开发的
  • logs 日志文件,包括Mycat启动的日志和运行的日志
  • version.txt mycat版本说明

logs目录:

  • wrapper.log mycat启动日志
  • mycat.log mycat详细工作日志

Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:

  • server.xml Mycat软件本身相关的配置文件,设置账号、参数等
  • schema.xml Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、节点控制
  • rule.xml Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等

启动和连接

1
2
3
4
5
6
echo 'PATH=/apps/mycat/bin:$PATH' > /etc/profile.d/mycat.sh
source /etc/profile.d/mycat.sh
mycat start
#连接mycat:
mysql -uroot -p123456 -h 127.0.0.1 -P8066
exit

Mycat 主要配置文件说明

server.xml

存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等

server.xml文件中配置的参数解释说明:

参数 说明
user 用户配置节点
name 客户端登录 MyCAT 的用户名,也就是客户端用来连接 Mycat 的用户名。
password 客户端登录 MyCAT 的密码
schemas 数据库名,这里会和 schema.xml 中的配置关联,多个用逗号分开,例如:db1,db2
privileges 配置用户针对表的增删改查的权限
readOnly mycat 逻辑库所具有的权限。true 为只读,false 为读写都有,默认为 false

注意:

  • server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录mycat时使用的账号信息
  • 逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
  • 这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用户名和密码,那么就需要在schema.xml文件中定义多个对应的库!

schema.xml

是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理服务器,此文件就是用来连接MySQL服务器的

schema.xml文件中配置的参数解释说明:

参数 说明
schema 数据库设置,此数据库为逻辑数据库,nameserver.xml 中的 schema 对应
dataNode 分片信息,也就是分库相关配置
dataHost 物理数据库,真正存储数据的数据库

配置说明

name属性唯一标识dataHost标签,供上层的标签使用。

maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数

minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小

每个节点的属性逐一说明

schema:

属性 说明
name 逻辑数据库名,与 server.xml 中的 schema 对应
checkSQLschema 数据库前缀相关设置,这里为 false
sqlMaxLimit SELECT 时默认的 LIMIT,避免查询全表

table

属性 说明
name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文 dataNode 设置的 name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名,具体规则下文 rule 详细介绍

dataNode

属性 说明
name 节点名,与 table 中的 dataNode 对应
datahost 物理数据库名,与 datahost 中的 name 对应
database 物理数据库中数据库名

dataHost

属性 说明
name 物理数据库名,与 dataNode 中的 dataHost 对应
balance 均衡负载的方式
writeType 写入方式
dbType 数据库类型
heartbeat 心跳检测语句,注意语句结尾的分号要加

schema.xml文件中有三点需要注意:balance=“1”,writeType=“0” ,switchType=“1”

schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类型,目前的取值有 4 种:

balance="0":不开启读写分离机制,所有读操作都发送到当前可用的writeHost上,即读请求仅发送到writeHost上

balance="1":一般用此模式,读请求随机分发到当前writeHost对应的readHost和standby的writeHost上。即全部的readHost与stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1, S2 都参与 select 语句的负载均衡

balance="2":读请求随机分发到当前dataHost内所有的writeHost和readHost上。即所有读操作都随机的在writeHost、 readhost 上分发

balance="3":读请求随机分发到当前writeHost对应的readHost上。即所有读请求随机的分发到wiriterHost 对应的 readhost 执行, writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有,1.3 没有

writeHost和readHost 标签

这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。

唯一不同的是:writeHost指定写实例、readHost指定读实例,组合这些读写实例来满足系统的要求。

在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去

注意:Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的主从复制将数据复制到readhost

修改server.xml文件配置Mycat的连接信息

1
vim /apps/mycat/conf/server.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        <property name="processorBufferPoolType">0</property>
#在上行下面添加下面的信息,端口3306
<property name="serverPort">3306</property>
<property name="managerPort">9066</property>
<property name="idleTimeout">300000</property>
<property name="authTimeout">15000</property>
<property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property>
<property name="frontWriteQueueSize">4096</property>
<property name="processors">32</property>

#再往下面翻翻,找到下面这行,用户名root,密码123456
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB</property>
#schemas对应的TESTDB 数据库要和后面要改的schema.xml相对应

这里填的是用户去连接的mysql,也就是说用户用mysql -uroot -p123465连的是mycat1的这个虚拟的TESTDB数据库,但是他映射的是后端的数据库,这个在下一步会讲到

修改schema.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#直接复制我的文件就行了,全选一键复制,看一下有什么信息要修改,修改后就可以复制了
cat > /apps/mycat/conf/schema.xml <<"EOF"
<?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"> </schema>
<dataNode name="dn1" dataHost="localhost1" database="hellodb" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- 写的节点-->
<writeHost host="host1" url="192.168.48.10:3306" user="qianyios" password="123456">
<!-- 读的节点-->
<readHost host="host2" url="192.168.48.11:3306" user="qianyios" password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
EOF

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema>这一行的dn1对应下面的这一行
<dataNode name="dn1" dataHost="localhost1" database="hellodb" />

TESTDB是前面上一步修改server.xml提到的要和前面一一对应的虚拟数据库
hellodb是后端对应的数据库名,就是说,我后端有哪个数据库是想映射到mycat的,就写,我总不能说所有数据库都写都映射

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">

其中balance="1"设置为1表示读写分离

<writeHost host="host1" url="192.168.48.10:3306" user="qianyios" password="123456">

<readHost host="host2" url="192.168.48.11:3306" user="qianyios" password="123456" />

这个qianyios用户等等后面会创建

image-20250802140642277

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#重启mycat
mycat stop
mycat start
#查看端口状态
[root@mycat ~]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:* users:(("java",pid=60546,fd=4))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=991,fd=7))
LISTEN 0 2048 *:9066#这个 *:* users:(("java",pid=60546,fd=179))
LISTEN 0 50 *:35183 *:* users:(("java",pid=60546,fd=70))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=991,fd=8))
LISTEN 0 50 *:36743 *:* users:(("java",pid=60546,fd=68))
LISTEN 0 50 *:1984 *:* users:(("java",pid=60546,fd=69))
LISTEN 0 2048 *:3306#这个 *:* users:(("java",pid=60546,fd=183))
[root@mycat ~]#

在master主节点导入测试的数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#全新复制运行即可,要退出mysql,在shell终端运行
cat > hellodb.sql <<"EOF"

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `hellodb` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `hellodb`;

DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
`ClassID` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`Class` varchar(100) DEFAULT NULL,
`NumOfStu` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ClassID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

LOCK TABLES `classes` WRITE;
INSERT INTO `classes` VALUES
(1,'Shaolin Pai',10),(2,'Emei Pai',7),
(3,'QingCheng Pai',11),(4,'Wudang Pai',12),(5,'Riyue Shenjiao',31),
(6,'Lianshan Pai',27),(7,'Ming Jiao',27),(8,'Xiaoyao Pai',15);
UNLOCK TABLES;

DROP TABLE IF EXISTS `coc`;
CREATE TABLE `coc` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ClassID` tinyint(3) unsigned NOT NULL,
`CourseID` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

LOCK TABLES `coc` WRITE;
INSERT INTO `coc` VALUES (1,1,2),(2,1,5),(3,2,2),(4,2,6),(5,3,1),(6,3,7),(7,4,5),(8,4,2),(9,5,1),(10,5,9),(11,6,3),(12,6,4),(13,7,4),(14,7,3);
UNLOCK TABLES;

DROP TABLE IF EXISTS `courses`;
CREATE TABLE `courses` (
`CourseID` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`Course` varchar(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

LOCK TABLES `courses` WRITE;
/*!40000 ALTER TABLE `courses` DISABLE KEYS */;
INSERT INTO `courses` VALUES (1,'Hamo Gong'),(2,'Kuihua Baodian'),(3,'Jinshe Jianfa'),(4,'Taiji Quan'),(5,'Daiyu Zanghua'),(6,'Weituo Zhang'),(7,'Dagou Bangfa');
/*!40000 ALTER TABLE `courses` ENABLE KEYS */;
UNLOCK TABLES;

DROP TABLE IF EXISTS `scores`;
CREATE TABLE `scores` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`StuID` int(10) unsigned NOT NULL,
`CourseID` smallint(5) unsigned NOT NULL,
`Score` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

LOCK TABLES `scores` WRITE;
INSERT INTO `scores` VALUES (1,1,2,77),(2,1,6,93),(3,2,2,47),(4,2,5,97),(5,3,2,88),(6,3,6,75),(7,4,5,71),(8,4,2,89),(9,5,1,39),(10,5,7,63),(11,6,1,96),(12,7,1,86),(13,7,7,83),(14,8,4,57),(15,8,3,93);
UNLOCK TABLES;

DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
`StuID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`Age` tinyint(3) unsigned NOT NULL,
`Gender` enum('F','M') NOT NULL,
`ClassID` tinyint(3) unsigned DEFAULT NULL,
`TeacherID` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`StuID`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

LOCK TABLES `students` WRITE;
INSERT INTO `students` VALUES (1,'Shi Zhongyu',22,'M',2,3),(2,'Shi Potian',22,'M',1,7),(3,'Xie Yanke',53,'M',2,16),(4,'Ding Dian',32,'M',4,4),(5,'Yu Yutong',26,'M',3,1),(6,'Shi Qing',46,'M',5,NULL),(7,'Xi Ren',19,'F',3,NULL),(8,'Lin Daiyu',17,'F',7,NULL),(9,'Ren Yingying',20,'F',6,NULL),(10,'Yue Lingshan',19,'F',3,NULL),(11,'Yuan Chengzhi',23,'M',6,NULL),(12,'Wen Qingqing',19,'F',1,NULL),(13,'Tian Boguang',33,'M',2,NULL),(14,'Lu Wushuang',17,'F',3,NULL),(15,'Duan Yu',19,'M',4,NULL),(16,'Xu Zhu',21,'M',1,NULL),(17,'Lin Chong',25,'M',4,NULL),(18,'Hua Rong',23,'M',7,NULL),(19,'Xue Baochai',18,'F',6,NULL),(20,'Diao Chan',19,'F',7,NULL),(21,'Huang Yueying',22,'F',6,NULL),(22,'Xiao Qiao',20,'F',1,NULL),(23,'Ma Chao',23,'M',4,NULL),(24,'Xu Xian',27,'M',NULL,NULL),(25,'Sun Dasheng',100,'M',NULL,NULL);
UNLOCK TABLES;

DROP TABLE IF EXISTS `teachers`;
CREATE TABLE `teachers` (
`TID` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(100) NOT NULL,
`Age` tinyint(3) unsigned NOT NULL,
`Gender` enum('F','M') DEFAULT NULL,
PRIMARY KEY (`TID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

LOCK TABLES `teachers` WRITE;
INSERT INTO `teachers` VALUES (1,'Song Jiang',45,'M'),(2,'Zhang Sanfeng',94,'M'),(3,'Miejue Shitai',77,'F'),(4,'Lin Chaoying',93,'F');
UNLOCK TABLES;


DROP TABLE IF EXISTS `toc`;
CREATE TABLE `toc` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CourseID` smallint(5) unsigned DEFAULT NULL,
`TID` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `toc` WRITE;
UNLOCK TABLES;

EOF
1
2
3
#在主节点导入
mysql -uroot -p123456 < hellodb.sql
mysql -uroot -p123456 hellodb -e "show tables;"

image-20250802135101220

在master节点创建用户并对mycat授权

1
2
3
mysql -uroot -p123456 -e "create user 'qianyios'@'192.168.48.%' identified by '123456' ;"
mysql -uroot -p123456 -e "GRANT ALL PRIVILEGES ON *.* TO 'qianyios'@'192.168.48.%';"
mysql -uroot -p123456 -e"flush privileges;"

qianyios用来给mycat连接本数据库的的账号,映射到前端

在主节点创建好后,由于主从复制,在从节点是可以看得见的

1
select host,user from mysql.user

image-20250802135801899

测试读写分离

image-20250802140308663

客户端登入mycat

操作节点:[client]

1
mysql -u root -p123456 -h192.168.48.128

-h192.168.48.128要链接的是mycat的地址

登上了,但是看不了表

image-20250802142028803

一查看报错

1
[root@mycat ~]# tail -f /apps/mycat/logs/*

image-20250802142013990

1
can't connect to mysql server ,errmsg:Client does not support authentication protocol requested by server; consider upgrading MySQL client

这是由于 MySQL 8 默认使用了新的认证协议 caching_sha2_password,而 MyCat 客户端可能不支持这种新的认证协议。以下是解决方法:

1
2
3
#在master主节点运行
mysql -uroot -p123456 -e "ALTER USER 'qianyios'@'192.168.48.%' IDENTIFIED WITH mysql_native_password BY '123456';"
mysql -uroot -p123456 -e "FLUSH PRIVILEGES;"

再次重新登入就可以连接了并查看表里

操作节点:[client]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql -u root -p123456 -h192.168.48.128
use TESTDB;
show tables;

mysql> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| toc |
+-------------------+
7 rows in set (0.00 sec)

验证读写分离

为了确保数据可观,这里要重启一下mycat

操作节点:[mycat]

9066是mycat的管理端口

1
2
3
4
mycat stop;mycat start;
mysql -uroot -p123456 -P9066 -h127.0.0.1
#查看读写分离状态信息
show @@datasource;

image-20250802142919545

目的读和写的信息数是0

开始测试

操作节点:[client]

1
2
3
mysql -uroot -p123456 -h 192.168.48.128 -P 3306
#进行一次查询
use TESTDB;select * from teachers;

image-20250802143113971

回到mycat的状态栏

image-20250802143142635

是不是读的操作就出来了,就是他走的是从节点

接下来验证写操作

操作节点:[client]

1
2
mysql> insert into teachers(name,age,gender)values("xiaohu",25,'M');
Query OK, 1 row affected (0.05 sec)

回到mycat的状态栏

image-20250802143403801

是不是一目了然,主节点有了写入的数据,从节点没有

至此读写分离部署成功

模拟从节点宕机

1
[root@slave ~]# systemctl stop mysqld

然后里面去客户端进行一次查询

1
use TESTDB;select * from teachers;

image-20250802152050769

然后去mycat节点查看状态

image-20250802152133703

这时候从节点宕机之后,客户端会出现几秒钟的查询不到的状态,然后mycat会把请求转向主节点

面试题

mycat是如何检查主从节点存活的

看我的操作,答案在最后

在主从两个节点的my.cnt添加这个

1
2
3
4
5
[mysqld]
general_log

#重启
systemctl restart mysqld

general_log 是一个日志系统,用于记录所有由 MySQL 服务器接收到的连接和执行的 SQL 语句。这个日志对于监控数据库操作、分析性能问题、审计和故障排除非常有用。

1
[root@master ~]# tail -f /data/mysql/master.log

image-20250802151405779

1
[root@slave ~]# tail -f /data/mysql/slave.log

image-20250802151421746

解答:在mycat的/apps/mycat/conf/schema.xml的心跳机制里

image-20250802151809659

mycat就会每10s发送一次select user()去监测主从节点状态

特别声明
千屹博客旗下的所有文章,是通过本人课堂学习和课外自学所精心整理的知识巨著
难免会有出错的地方
如果细心的你发现了小失误,可以在下方评论区告诉我,或者私信我!
非常感谢大家的热烈支持!