一、简介

读写分离

读写分离基于主从复制实现

主服务器实现写

从服务器实现读

提升数据库的并发负载能力

什么是读写分离?

读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。
数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

为什么要读写分离呢?

因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。
但是数据库的“读”(读10000条数据可能只要5秒钟)。
所以读写分离,解决的是,数据库的写入,影响了查询的效率。

什么时候要读写分离?
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。

利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。

MySQL 读写分离原理

读写分离就是只在主服务器上写,只在从服务器上读。

主数据库(Master)负责处理所有的写操作,它维护着完整的数据集。
而从数据库(Slave)通过复制主数据库的数据,提供只读的服务。

基本的原理是让主数据库处理事务性操作,而从数据库处理 select 查询。

常见的实现方式

基于程序代码内部实现
在代码中根据 select、insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。

优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;

缺点是需要开发人员来实现,运维人员无从下手。

但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。

基于中间代理层实现
代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有以下代表性程序。

1)MySQL-Proxy

MySQL-Proxy 为 MySQL 开源项目,通过其自带的 lua 脚本进行SQL 判断。

2)Atlas

是由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。

它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。

360内部使用Atlas运行的mysql业务,每天承载的读写请求数达几十亿条。

支持事物以及存储过程。

3)Amoeba

由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。

4)Mycat

是一款流行的基于Java语言编写的数据库中间件,是一个实现了MySql协议的服务器,其核心功能是分库分表。配合数据库的主从模式还可以实现读写分离。

由于使用MySQL Proxy 需要写大量的Lua脚本,这些Lua并不是现成的,而是需要自己去写。这对于并不熟悉MySQL Proxy 内置变量和MySQL Protocol 的人来说是非常困难的。
Amoeba是一个非常容易使用、可移植性非常强的软件。因此它在生产环境中被广泛应用于数据库的代理层。

二、实验

环境:

三台rockyLinux 9虚拟机,基本配置已完成,mysql端与client端已做好数据库主从,使用Xshell进行连接。
mysql - 192.168.100.111
client - 192.168.100.112
mycat - 192.168.100.113

1、安装mysql

mysql安装,前文mysql基础中有,这里就不详细写了
详情见:http://t.csdnimg.cn/cm4t6

2、/etc/hosts添加文件内容

1
2
3
4
5
6
7
8
9
10
11
[root@mysql ~]# vim /etc/hosts      //在文件最后根据自己的机组信息写入
192.168.100.111 mysql.example.com mysql
192.168.100.112 client.example.com client
192.168.100.113 mycat.example.com mycat

//我这里直接scp传输过去
[root@mysql ~]# scp /etc/hosts root@192.168.100.112:/etc/hosts
root@192.168.100.112's password:
hosts 100% 288 437.7KB/s 00:00
[root@mysql ~]# scp /etc/hosts root@192.168.100.113:/etc/hosts

3、配置安装mycat

安装mycat环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//前面安装mysql时
[root@mycat software]# rz -E
rz waiting to receive.
[root@mycat software]# ls
Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz mysql-5.7.37-linux-glibc2.12-x86_64.tar.gz

//安装mycat环境
[root@mycat software]# yum -y install java java-devel

//查看Java版本
[root@mycat ~]# java -version
openjdk version "11.0.24" 2024-07-16 LTS
OpenJDK Runtime Environment (Red_Hat-11.0.24.0.8-2) (build 11.0.24+8-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-11.0.24.0.8-2) (build 11.0.24+8-LTS, mixed mode, sharing)

解压配置mycat

1
2
3
4
5
6
7
8
9
10
11
//将Mycat包解压到/opt/local/目录下
[root@mycat ~]# tar -zxvf /opt/software/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /usr/local/

//配置环境变量
[root@mycat ~]# vim /etc/profile //在文件最后写入
export MYCAT_HOME=/usr/local/mycat/

[root@mycat ~]# source /etc/profile //使环境变量生效
[root@mycat ~]# echo $MYCAT_HOME //检查变量是否生效
/usr/local/mycat/

4、配置MYCAT服务

编辑mycat服务读写分离的schema.xml,设置数据库写入节点为mysql,读取节点client,注意IP要修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//把下面文件里的内容全部清除,写入新的内容
[root@mycat ~]# vim /usr/local/mycat/conf/schema.xml
//清除后写入以下内容,第89行的ip记得改为自己的
//第六行的数据库内容需要修改,主库和从库都要有才行
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="USERDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"></schema>
<dataNode name="dn1" dataHost="localhost1" database="shiqian" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" dbType="mysql" dbDriver="native" writeType="0" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.100.111:3306" user="root" password="redhat">
<readHost host="hostS1" url="192.168.112.20:3306" user="root" password="redhat" />
</writeHost>
</dataHost>
</mycat:schema>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//在client节点查看主从是否启动
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.111
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 154
Relay_Log_File: mysql-relay-bin.000008
Relay_Log_Pos: 367
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
//当上面两个信息为yes时就是启动成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@mycat ~]# vim /usr/local/mycat/conf/server.xml
删除如下5行,在文件最末尾处
<user name="root"> //光标移到这一行按5dd这五行就全删了
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>

</user>

//修改文件内信息
<user name="root">
<property name="password">redhat</property>
<property name="schemas">USERDB</property>

5、启动mycat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@mycat ~]# cd /usr/local/mycat/bin/
[root@mycat bin]# ./mycat start
Starting Mycat-server...

//查看80669066端口是否开启
[root@mycat bin]# ss -anlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 50 *:1984 *:*
LISTEN 0 100 *:8066 *:*
LISTEN 0 50 *:36087 *:*
LISTEN 0 80 *:3306 *:*
LISTEN 0 100 *:9066 *:*
LISTEN 0 50 *:45783 *:*
LISTEN 0 128 [::]:22 [::]:*

6、root用户授权

在mysql和client节点分别给root数据库用户授权,因为默认情况下,数据库用户root不允许远程登录
在mysql节点与client节点分别都要进入mysql中执行以下命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select User,Host from user;
+---------------+-----------------+
| User | Host |
+---------------+-----------------+
| repl | 192.168.100.112 |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------------+
4 rows in set (0.01 sec)

mysql> grant all privileges on *.* to 'root'@'%' identified by 'redhat' with grant option;
Query OK, 0 rows affected, 1 warning (0.01 sec)

三、mycat验证

在mycat节点验证

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
[root@mycat ~]# mysql -uroot -predhat -P8066 -h172.0.0.1
mysql: [Warning] Using a password on the command line interface can be insecure.
^C
[root@mycat ~]# mysql -uroot -predhat -P8066 -h127.0.0.1
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 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)

Copyright (c) 2000, 2022, 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 |
+----------+
| USERDB |
+----------+
1 row in set (0.00 sec)

mysql> use USERDB;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------+
| Tables_in_shiqian |
+-------------------+
| sq |
+-------------------+
1 row in set (0.00 sec)

mysql> select * from sq;
+----+----------+------+
| id | name | age |
+----+----------+------+
| 1 | tom | 18 |
| 2 | marry | 19 |
| 3 | rose | 20 |
| 4 | mike | 19 |
| 5 | zhangsan | 18 |
| 6 | lisi | 20 |
| 7 | wangwu | 18 |
+----+----------+------+
7 rows in set (0.04 sec)

mysql> insert into sq values(8,'horzxy',21);
Query OK, 1 row affected (0.00 sec)

mysql> insert into sq values(9,'lliu',18);
Query OK, 1 row affected (0.00 sec)

mysql> select * from sq;
+----+----------+------+
| id | name | age |
+----+----------+------+
| 1 | tom | 18 |
| 2 | marry | 19 |
| 3 | rose | 20 |
| 4 | mike | 19 |
| 5 | zhangsan | 18 |
| 6 | lisi | 20 |
| 7 | wangwu | 18 |
| 8 | horzxy | 21 |
| 9 | lliu | 18 |
+----+----------+------+
9 rows in set (0.00 sec)

通过管理接口9066来查看读写分离的情况,看写入的次数和查看的次数,依次做测试

1
2
3
4
5
6
7
8
9
[root@mycat ~]# mysql -h127.0.0.1 -P9066 -uroot -predhat -e 'show @@datasource;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------+--------+-------+-----------------+------+------+--------+------+------+---------+-----------+------------+
| DATANODE | NAME | TYPE | HOST | PORT | W/R | ACTIVE | IDLE | SIZE | EXECUTE | READ_LOAD | WRITE_LOAD |
+----------+--------+-------+-----------------+------+------+--------+------+------+---------+-----------+------------+
| dn1 | hostM1 | mysql | 192.168.100.111 | 3306 | W | 0 | 6 | 1000 | 85 | 4 | 2 |
| dn1 | hostS1 | mysql | 192.168.112.20 | 3306 | R | 0 | 0 | 1000 | 0 | 0 | 0 |
+----------+--------+-------+-----------------+------+------+--------+------+------+---------+-----------+------------+