一、应用背景
当项目存在大量高并发读写操作的时候,借助数据读写分离,即把对数据的读和写操作分布到不同的数据库服务器上,减少单个服务器的压力;同时可以备份数据,防止单点故障使数据丢失。
二、主从复制
在该模式下数据库分为主库master和从库slave(通常为一主多从),主库记录对数据库的操作到二进制日志中,从库复制并解析主库的日志文件到自己的中继日志中,然后执行中继日志中的操作同步数据。实现过程分为下列三个步骤:
- master记录对数据的操作到binary log
- slave将master的日志内容拷贝到自己的delay log
- slave解析重做delay log中的操作,同步数据
- 写操作针对master,读操作针对slave
三、环境准备
本次采用一主一从模式,创建两台虚拟机。
3.1 从库的创建
创建虚拟机,查看IP地址(192.168.70.139),若启动时ip地址未初始化,修改配置文件
etc/sysconfig/network-scripts/ifcfg-ens33中onboot=yes
安装mysql(这里采用rpm方式安装)
首先卸载冲突软件mariadb
上传mysql压缩包并进行解压到自定义目录usr/local/mysql,解压后按如下顺序一次安装6个文件,命令为rpm -ivh xxx
在安装上图中的6时出现如下依赖问题
需要先进行进行相应的依赖安装
安装完成之后启动mysql
3.2 从库的配置
修改配置文件/etc/my.cnf设置添加内容server-id=139,具体说明参照3.4。
查询日志文件/var/log/mysqld.log中mysql登录的默认密码后登录mysql,修改密码并授予权限给root用户
后执行如下语句,使从库可通过用户xx与主库通信
查看salve状态,可看到主库日志及其位置,从库日志及其位置信息
3.3 主库的创建
创建虚拟机,ip为192.168.70.138,按照3.1中的步骤方法在虚拟机中安装并启动mysql。
3.4 主库的配置
修改etc/my.cnf配置文件,在[mysql]字段下添加内容
log-bin=mysql-bin //启用二进制日志
server-id=138 //设置唯一标识id,这里选用ip地址低位138
重新启动mysql
登录mysql(可能需要先修改密码和对root用户进行授权),之后创建xx用户,并授予复制的权限,从库通过该用户与主库通信
查看主库状态,可看到二进制日志和位置信息
3.5 主从复制配置成功验证
分别连接master和slave,在主库中进行的操作同步更新到从库,说明配置成功。
四、读写分离在springboot项目中的使用
借助Sharding-JDBC框架,兼容各种JDBC和ORM框架,实现读写分离;
Sharding-JDBC的特点;
- 兼容基于JDBC的ORM框架,如:Mybatis,Spring JDBC Template等
- 兼容任何第三方的数据库连接池,如:DBCP,C3P0,Druid等
- 兼容任意实现JDBC规范的数据库,如:MySql,Oracle等
使用步骤:
引入坐标
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
配置读写分离原则并配置允许bean定义覆盖
spring:
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.70.138:3306/reggie?characterEncoding=utf-8
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.70.139:3306/reggie?characterEncoding=utf-8
username: root
password: root
masterslave:
# 读写分离配置 轮询策略
load-balance-algorithm-type: round_robin
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
main:
allow-bean-definition-overriding: true//允许bean定义覆盖