本文原创作品,良心制作,干货为主,简洁清晰,一看就会
前言
学习读写分离,可拆分数据库读写压力,主库专注写操作,从库分担读请求,提升系统吞吐量;还能避免读操作阻塞写操作,优化响应速度,是高并发场景下保障数据库性能的关键方案
一、什么是读写分离
读写分离核心是拆分数据库读写操作:主库专注处理写入(增删改),并通过主从同步将数据变更实时同步到从库;从库仅承担查询(select)请求
通过中间件(如MyCat、Sharding-JDBC)或应用层路由,将写操作定向到主库,读操作分发到从库,实现压力分流,提升整体性能。
二、Mycat中间件及其作用
Mycat 是数据库中间件,就是介于数据库与应用之间,进行数据处理与交互的中间服 务是实现对主从数据库的读写分离、读的负载均衡
Java程序层:
java1、java2、java3… 是业务应用,负责发起数据库操作请求
中间件层(MyCat):
接收Java程序的请求后,根据操作类型(读/写)分发到不同数据库,同时对外提供逻辑库、逻辑用户、逻辑密码,让Java程序无需感知后端真实数据库的差异,像连接单库一样操作
数据库层:
所有写操作(增删改)路由到 mysql-master(主库);
所有读操作(查询)分发到 mysql-slave1(从库) (或 mysql-slave2可选),实现读压力分摊
整体架构通过“主库写+从库读”的分工,结合MyCat的路由能力,实现了数据库读写压力的分离,从而提升系统性能和可用性
三、读写分离实战
3.1 环境介绍
环境介绍:做实验前需同步时间,最好每台机器都ntpdate ntp.aliyun.***一下,防火墙需要关闭或者开启3306和8066端口
| 主机名 | ip地址 | 服务 | 系统 |
|---|---|---|---|
| mycat | 192.168.136.20 | mycat | CentOs |
| mysql-master | 192.168.136.10 | mysql5.7.27 | CentOs |
| mysql-slave1 | 192.168.136.134 | mysql5.7.24 | Ubuntu |
| mysql-slave2(可选) | 192.168.136.135 | mysql5.7.24 | Ubuntu |
说明:教程中我用了CentOS和Ubuntu只是因为我刚好只有这四台测试机,其实不用纠结系统选型,只要保证MySQL版本一致,其余操作完全相同,不管你用什么系统,这个教程都适用
3.2 安装mycat
mycat 是使用 JAVA语言进行编写开发,使用前需要先安装 JAVA 运行环境(JRE),由于 MyCAT 中使用了 JDK7 中的一些特性,所以要求必须在 JDK7 以上的版本上运行
3.2.1 安装jdk环境
官网下载地址:https://www.oracle.***/java/technologies/downloads/#java8
[root@mycat ~]# tar xf jdk-8u211-linux-x64.tar.gz -C /usr/local
[root@mycat ~]# cd /usr/local
[root@mycat local]# ls
bin etc games include jdk1.8.0_211 lib lib64 libexec sbin share src
[root@mycat local]# mv jdk1.8.0_211/ java
[root@mycat local]# vim /etc/profile #配置环境变量
JAVA_HOME=/usr/local/java
PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
[root@mycat local]# source /etc/profile
[root@mycat ~]# java -version #验证
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
3.2.2 安装mycat
MyCat官网:http://www.mycat.org.***/
[root@mycat ~]# tar xf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz -C /usr/local/
#待会我们要改的就是schema.xml和server.xml这两个文件
[root@mycat ~]# ls /usr/local/mycat/conf/
autopartition-long.txt dnindex.properties partition-hash-int.txt sequence_distributed_conf.properties zkconf
auto-sharding-long.txt ehcache.xml partition-range-mod.txt sequence_http_conf.properties zkdownload
auto-sharding-rang-mod.txt index_to_charset.properties rule.xml sequence_time_conf.properties
cacheservice.properties log4j2.xml schema.xml server.xml
dbseq.sql migrateTables.properties sequence_conf.properties sharding-by-enum.txt
dbseq - utf8mb4.sql myid.properties sequence_db_conf.properties wrapper.conf
[root@mycat ~]#
3.3 主数据库创建写用户
主库创建写用户,用于配置到mycat的schema.xml中,供mycat接收到Java程序请求的写操作时会登录此用户的数据库进行写操作
[root@mysql-master ~]# mysql -p'Qing@123'
mysql> create database tmpdb;
mysql> grant all on tmpdb.* to writeuser@'%' identified by 'Writeuser@123';
mysql> flush privileges;
3.4 从数据库创建读用户
从库创建读用户,用于配置到mycat的schema.xml中,供mycat接收到Java程序请求的读操作时会登录此用户的数据库进行读操作
#slave1创建读用户
root@mysql-slave1:~# mysql -p'Qing@123'
mysql> create database tmpdb;
mysql> grant all on tmpdb.* to readuser@'%' identified by 'Readuser@123';
mysql> flush privileges;
#slave2创建读用户(可选)
root@mysql-slave2:~# mysql -p'Qing@123'
mysql> create database tmpdb;
mysql> grant all on tmpdb.* to readuser@'%' identified by 'Readuser@123';
mysql> flush privileges;
3.5 修改server.xml文件
#修改前强烈建议先备份一份,待会改错了还有拯救的余地
[root@mycat mycat]# cp /usr/local/mycat/conf/server.xml /tmp/server.xml
[root@mycat mycat]# vim /usr/local/mycat/conf/server.xml #直接看文件最后进行修改
3.6 修改schema.xml文件
[root@mycat mycat]# cp /usr/local/mycat/conf/schema.xml /tmp/schema.xml
#schema.xml中有很多需要删掉或者修改的地方,大家如果嫌麻烦可以直接复制下面代码,然后改一些关键的东西即可
[root@mycat mycat]# vim /usr/local/mycat/conf/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" >
</schema>
<dataNode name="dn1" dataHost="localhost1" database="tmpdb" />
<dataHost name="localhost1" 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.136.10:3306" user="writeuser"
password="Writeuser@123">
<readHost host="hostS2" url="192.168.136.134:3306" user="readuser" password="Readuser@123" />
<readHost host="hostS3" url="192.168.136.135:3306" user="readuser" password="Readuser@123" />
</writeHost>
</dataHost>
</mycat:schema>
[root@mycat mycat]#
3.7 启动mycat
3.7.1 调整JVM
[root@mycat ~]# vim /usr/local/mycat/conf/wrapper.conf #添加一行
wrapper.startup.timeout=300 #超时时间300秒
3.7.2 启动mycat
[root@mycat ~]# /usr/local/mycat/bin/mycat start #启动mycat,需要稍微等一会
Starting Mycat-server...
[root@mycat ~]# jps #查看mycat是否启动,如果出现WrapperSimpleApp表示成功,这里mycat没有启动成功
6118 Jps
[root@mycat ~]# tail -f /usr/local/mycat/wrapper.log #查看错误日志,显示没有logs目录
FATAL | wrapper | 2025/11/08 13:49:01 | ERROR: Could not write pid file /usr/local/mycat/logs/mycat.pid: No such file or directory
FATAL | wrapper | 2025/11/08 13:50:13 | ERROR: Could not write pid file /usr/local/mycat/logs/mycat.pid: No such file or directory
^C
[root@mycat ~]# mkdir -p /usr/local/mycat/logs #创建目录
[root@mycat ~]# chown mysql.mysql /usr/local/mycat/logs
[root@mycat ~]# /usr/local/mycat/bin/mycat start
Starting Mycat-server...
[root@mycat ~]# jps #启动成功
6229 Jps
6203 WrapperSimpleApp
3.8 测试读写分离
测试读写是否分离,连接mycat,然后创建数据看看能不能查到
正常情况时mycat接受写请求时会分发给master数据库,读请求会分发给slave数据库,所以在没做主从同步的情况下,插入数据之后master数据库中有数据,而slave上没数据,证明读写分离成功
#用我们在server.xml中配置的逻辑用户和密码登录
# -h mycat的ip地址 -P mycat端口
[root@mycat ~]# mysql -uroot -p'123456' -h 192.168.136.20 -P 8066
mysql> show databases; #这里显示的是逻辑库,对应实际上的tmpdb库
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
mysql> use TESTDB;
mysql> create table student(id int);
mysql> insert into student values(1);
mysql> select * from student; #查询不到数据
ERROR 1146 (HY000): Table 'tmpdb.student' doesn't exist
#master数据库
[root@mysql-master ~]# mysql -p'Qing@123'
mysql> use tmpdb;
mysql> select * from student; #由于写操作是分配到了master数控,所以master数据库上肯定有数据
+------+
| id |
+------+
| 1 |
+------+
#slave1数据库
root@mysql-slave1:~# mysql -p'Qing@123'
mysql> use tmpdb;
mysql> select * from student; #slave1数据库只接受读操作,所以查不到数据,证明读写分离成功
ERROR 1146 (42S02): Table 'tmpdb.student' doesn't exist
#slave2数据库一样查不到数据
root@mysql-slave2:~# mysql -p'Qing@123'
mysql> use tmpdb;
mysql> select * from student;
ERROR 1146 (42S02): Table 'tmpdb.student' doesn't exist
3.9 配置主从同步
我们已成功实现读写分离,但生产环境中还需搭配主从同步。这样一来,写入主库的数据会自动同步到从库,从库始终有最新数据可供查询,真正实现后端数据库的读写压力分担,发挥读写分离的核心价值
我这就不详细将怎么做主从同步了,我之前发过一篇文章,里面详细记录主从同步的两种方法,不会的小伙伴可以参考这篇https://blog.csdn.***/m0_63756214/article/details/154487592?spm=1001.2014.3001.5501
3.10 测试主从同步
主从同步已经做好了,现在来测试
[root@mycat ~]# mysql -uroot -p'123456' -h 192.168.136.20 -P 8066 #连接mycat
mysql> use TESTDB;
mysql> show tables;
+-----------------+
| Tables_in_tmpdb |
+-----------------+
| class |
| student |
+-----------------+
mysql> create table employees(id int,name varchar(20));
mysql> insert into employees values(1,'lisa'),(2,'tom'); #插入数据
mysql> select * from employees; #查看数据,实现了主从同步和读写分离,实验完成
+------+------+
| id | name |
+------+------+
| 1 | lisa |
| 2 | tom |
+------+------+
注:
文中若有疏漏,欢迎大家指正赐教。
本文为100%原创,转载请务必标注原创作者,尊重劳动成果。
求赞、求关注、求评论!你的支持是我更新的最大动力,评论区等你~
后续会持续分享MySQL相关知识。