首页 > 数据库 > > 死磕数据库系列(九):MySQL 读写分离详解
上一期我们学习了:死磕数据库系列(八):MySQL 主从同步详解 ,当业务量到达一定程度时,数据库的负载压力就会随之越来越明显,这个时候我们就面临如何解决这个问题的困境。我们发现其实数据库大部分的负载压力源于读,而不是写,所以,读写分离技术就随之出现。
但是,有一些技术同学可能对于“读写分离”了解不多,认为数据库的负载问题都可以使用“读写分离”来解决。
这其实是一个非常大的误区,我们要用“读写分离”,首先应该明白“读写分离”是用来解决什么样的问题的,而不是仅仅会用这个技术。
基本的原理是让主数据库处理事务性增、删、改操作(INSERT、DELETE、UPDATE),而从数据库处理 SELECT 查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。
实现方式主要基于 mysql 的主从复制,通过路由的方式使应用对数据库的写请求只在master上进行,读请求在slave上进行。
在应用和数据库之间增加代理层,代理层接收应用对数据库的请求,根据不同请求类型转发到不同的实例,在实现读写分离的同时可以实现负载均衡。
实现原理
开源方案
MySQL的代理常见的是mysql-proxy、cobar、mycat、Atlas等。这种方式对于应用来说,MySQL Proxy是完全透明的,应用则只需要连接到MySQL Proxy的监听端口即可。当然,这样proxy机器可能成为单点失效,但完全可以使用多个proxy机器做为冗余,在应用服务器的连接池配置中配置到多 个proxy的连接参数即可。
基于应用内路由的方式即为在应用程序中实现,针对不同的请求类型去不同的实例执行sql。
基于spring的aop实现: 用aop来拦截spring项目的dao层方法,根据方法名称就可以判断要执行的sql类型(即是read还是write类型),进而动态切换主从数据源。类似项目有:
多数据源切换:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter
使用mysql驱动Connector/J的可以实现读写分离。即在jdbc的url中配置为如下的形示:
jdbc:mysql:replication://master,slave1,slave2,slave3/test
java程序通过在连接MySQL的jdbc中配置主库与从库等地址,jdbc会自动将读请求发送给从库,将写请求发送给主库,此外,mysql的jdbc驱动还能够实现多个从库的负载均衡。
sharding-sphere是强大的读写分离、分表分库中间件,sharding-jdbc是sharding-sphere的核心模块。
sharding-jdbc 可以与springboot集成。官方网址:https://shardingsphere.apache.org/
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
以上四种方案各有优缺点,基于MySQL proxy代理的方式对于应用来说相对简单,但是在项目稳定性、事务支持性等方面还存在问题;而基于应用内路由的方式固然灵活度比较高,但是也增加了应用逻辑的复杂度;基于mysql-connector-java的jdbc驱动和sharding-jdbc的方式在使用上相对简单,但限制了需要使用java开发。
amobea 服务器IP为192.168.169.202(在主从复制的基础上进行读写分离)
因为 Amoeba 基于是 jdk1.5 开发的,所以官方推荐使用 jdk1.5 或 1.6 版本,
高版本不建议使用。
将jdk-6u14-linux-x64.bin 和 amoeba-mysql-binary-2.2.0.tar.gz.0
上传到/opt目录下。
cd /opt/
cp jdk-6u14-linux-x64.bin /usr/local/
cd /usr/local/
chmod +x jdk-6u14-linux-x64.bin
./jdk-6u14-linux-x64.bin
按空格到后一行,按yes,按回车。
mv jdk1.6.0_14/ /usr/local/jdk1.6
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
#在末尾加入
source /etc/profile
java -version
##安装 Amoeba软件##
mkdir /usr/local/amoeba
tar zxvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
chmod -R 755 /usr/local/amoeba/
/usr/local/amoeba/bin/amoeba
//如显示amoeba start|stop 说明安装成功








在Master、Slave1、Slave2 的mysql上开放权限给 Amoeba 访问。
grant all on *.* to test@'192.168.169.%' identified by '123456';
cd /usr/local/amoeba/conf/
cp amoeba.xml amoeba.xml.bak
vim amoeba.xml
#修改amoeba配置文件
30修改
<property name="user">amoeba</property>
32修改
<property name="password">123456</property>
115修改
<property name="defaultPool">master</property>
117去掉注释–
<property name="writePool">master</property>
<property name="readPool">slaves</property>



cp dbServers.xml dbServers.xml.bak
vim dbServers.xml
#修改数据库配置文件
23注释掉
作用:默认进入test库 以防mysql中没有test库时,会报错
<!-- mysql schema
<property name="schema">test</property>
-->
26修改
<!-- mysql user -->
<property name="user">test</property>
28-30去掉注释
<property name="password">123456</property>
45修改,设置主服务器的名Master
<dbServer name="master" parent="abstractServer">
48修改,设置主服务器的地址
<property name="ipAddress">192.168.223.10</property>
52修改,设置从服务器的名slave1
<dbServer name="slave1" parent="abstractServer">
55修改,设置从服务器1的地址
<property name="ipAddress">192.168.223.9</property>
58复制上面6行粘贴,设置从服务器2的名slave2和地址
<dbServer name="slave2" parent="abstractServer">
<property name="ipAddress">192.168.223.11</property>
65修改
<dbServer name="slaves" virtual="true">
71修改
<property name="poolNames">slave1,slave2</property>
/usr/local/amoeba/bin/amoeba start&
#启动Amoeba软件,按ctrl+c 返回
netstat -anpt | grep java
#查看8066端口是否开启,默认端口为TCP 8066



在客户端(192.168.169.200)服务器上进行测试:
使用yum快速安装MySQL虚拟客户端
yum install -y mariadb mariadb-server mysql -u amoeba -p123456 -h 192.168.169.201 -P8066
通过amoeba服务器代理访问mysql ,在通过客户端连接mysql后写入的数据只有主服务会记录,然后同步给从服务器
create database zzz; use zzz;create table ceshi (id int(10),name varchar(10),address varchar(10));
stop slave; #关闭同步 use zzz;
use zzz;
select * from test;
客户端会分别向slave1和slave2读取数据,显示的只有在
两个从服务器上添加的数据,没有在主服务器上添加的数据
insert into test values('4','zb','four');
只有主服务器上有此数据


之后在两个从服务器上执行 start slave; 即可实现同步在主服务器和客户机上添加的数据
start slave;
更多关于MySQL读写分离实践的操作与配置,请参考以下往期推送的文章:
参考链接如下: https://blog.csdn.net/weixin_44842613/ article/details/116604132 https://blog.csdn.net/FateZRK/article/ details/125526077
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3163397/ ,如需转载,请注明出处,否则将追究法律责任。