查看原文
其他

【Spring Boot 实战】如何实现读写分离?

小东啊 Java后端 2020-08-21

作 者:小东啊

来 源:李浩东的博客

免费送书活动进行中

一. 前言

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时间有大量并发读操作和较少写操作类型的应用系统来说,将单一的数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。 

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

虽然读写分离可以提升系统的吞吐量和可用性,但同时也带来了数据不一致的问题,这包括多个主库之间的数据一致性,以及主库与从库之间的数据一致性的问题。

并且,读写分离也带来了与数据分片同样的问题,它同样会使得应用开发和运维人员对数据库的操作和运维变得更加复杂。透明化读写分离所带来的影响,让使用方尽量像使用一个数据库一样使用主从数据库,是读写分离中间件的主要功能。

在上一篇文章介绍到Mysql数据库的分库分表,本文将介绍读写分离

二. 本文计划

  1. 安装Mysql

  2. 配置主从复制

  3. 测试主从复制

  4. 读写分离

  5. 测试读写分离

三. 项目实战

环境介绍

  1. CentOS 7 192.168.0.3 从数据库

  2. CentOS 7 192.168.0.4 主数据库

3.1 安装Mysql数据库

这里不做过多介绍了 我这里安装的Mysql 8.0

3.2 配置主从复制

MySQL 主从复制的方式有多种,本文主要演示基于基于日志(binlog)的主从复制方式。

MySQL 主从复制(也称 A/B 复制) 的原理
  • Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件, 这些记录叫做二进制日志事件(binary log events);

  • Slave 通过 I/O 线程读取 Master 中的 binary log events 并写入到它的中继日志(relay log);

  • Slave 重做中继日志中的事件, 把中继日志中的事件信息一条一条的在本地执行一次,完 成数据在本地的存储, 从而实现将改变反映到它自己的数据(数据重放)。

主从配置需要注意的点

  1. 主从服务器操作系统版本和位数一致;

  2. Master 和 Slave 数据库的版本要一致;

  3. Master 和 Slave 数据库中的数据要一致;

  4. Master 开启二进制日志, Master 和 Slave 的 server_id 在局域网内必须唯一;

主从配置的简要步骤

Master 上的配置

  1. 1.安装数据库;

  2. 2.修改数据库配置文件, 指明 server_id, 3.开启二进制日志(log-bin);

  3. 3.启动数据库, 查看当前是哪个日志, position 号是多少;

  4. 4.登录数据库, 授权数据复制用户(IP 地址为从机 IP 地址, 如果是双向主从, 6.这里的还需要授权本机的 IP 地址, 此时自己的 IP 地址就是从 IP 地址);

  5. 5.备份数据库(记得加锁和解锁);

  6. 6.传送备份数据到 Slave 上;

  7. 7.启动数据库;

以下步骤, 为单向主从搭建成功, 想搭建双向主从需要的步骤:

  1. 登录数据库, 指定 Master 的地址、 用户、 密码等信息(此步仅双向主从时需要)

  2. 开启同步

  3. 查看状态

1. 主从服务器分别作以下操作:

  1. 1.1、版本一致

  2. 1.2、初始化表,并在后台启动mysql

  3. 1.3、修改root的密码

2. 修改主服务器master:

  1. #vim /etc/my.cnf

  2. [mysqld]

  3. log-bin=mysql-bin //[必须]启用二进制日志

  4. server-id=222 //[必须]服务器唯一ID,默认是1,一般取IP最后一段/自定义都可以的

3. 连接数据库 检验是否配置成功

  1. mysql> mysql -u root -p

  2. mysql> show master status;


可以看到这些信息,说明前面我们配置成功

4. 修改从服务器slave:

  1. #vi /etc/my.cnf

  2. [mysqld]

  3. log-bin=mysql-bin //[不是必须]启用二进制日志

  4. server-id=226 //[必须]服务器唯一ID,默认是1,一般取IP最后一段/自定义都可以的

5. 重复上面动作

  1. mysql> mysql -u root -p

  2. mysql> show master status;

可以看到这些信息,说明前面我们配置成功

6. 重启两台服务器的mysql

  1. systemctl restart mysqld.service

7. 在主服务器上建立帐户并授权slave: 在从节点上设置主节点参数

  1. change master to master_host='192.168.0.4',master_user='test',master_password='12root',master_log_file='mysql-bin.000001',master_log_pos=155;

一般不用root帐号,"%" 表示所有客户端都可能连,只要帐号,密码正确,此处可用具体客户端IP代替,如192.168.0.4(主服务器的IP),加强安全 8.开启主从同步

  1. mysql> start slave; #停止主从同步命令为:stop slave

9. 查看同步状态

  1. mysql> show slave status\G;

注:SlaveIO及SlaveSQL进程必须正常运行,即YES状态,否则都是错误的状态(如:其中一个NO均属错误)
说明们的主从同步配置成功

注意:如果如果从库宕机,重新启动,要连接上mysql服务,执行 start slave 这个命令,开启主从同步

3.3 测试主从复制

分别查询两台服务器的数据

在主数据库创建test表

  1. mysql> create database test;


查询从数据

我们刚刚在主数据库创建的test库在从数据库有的 说明我们的主从是成功的

注: 编写一shell脚本,用nagios监控slave的两个yes(SlaveIO及SlaveSQL进程),如发现只有一个或零个yes,就表明主从有问题了,发短信警报吧

3.4 读写分离

1. 在主数据库创建ds0:

  1. SET NAMES utf8mb4;

  2. SET FOREIGN_KEY_CHECKS = 0;


  3. -- ----------------------------

  4. -- Table structure for user

  5. -- ----------------------------

  6. DROP TABLE IF EXISTS `user`;

  7. CREATE TABLE `user` (

  8. `id` int(11) NOT NULL AUTO_INCREMENT,

  9. `age` int(11) DEFAULT NULL,

  10. `name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,

  11. PRIMARY KEY (`id`)

  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


  13. SET FOREIGN_KEY_CHECKS = 1;

从数据库会自动同步

2.项目搭建 复制上一篇的项目在基础上加以改动

application.properties 配置

  1. # 配置真实数据源

  2. sharding.jdbc.datasource.names=master1,slave0

  3. # 主数据库

  4. sharding.jdbc.datasource.master1.type=com.zaxxer.hikari.HikariDataSource

  5. sharding.jdbc.datasource.master1.hikari.driver-class-name=com.mysql.cj.jdbc.Driver

  6. sharding.jdbc.datasource.master1.jdbc-url=jdbc:mysql://192.168.0.4:3306/ds0?characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai

  7. sharding.jdbc.datasource.master1.username=test

  8. sharding.jdbc.datasource.master1.password=12root

  9. # 从数据库

  10. sharding.jdbc.datasource.slave0.type=com.zaxxer.hikari.HikariDataSource

  11. sharding.jdbc.datasource.slave0.hikari.driver-class-name=com.mysql.cj.jdbc.Driver

  12. sharding.jdbc.datasource.slave0.jdbc-url=jdbc:mysql://192.168.0.3:3306/ds0?characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai

  13. sharding.jdbc.datasource.slave0.username=test

  14. sharding.jdbc.datasource.slave0.password=12root

  15. # 配置读写分离

  16. # 配置从库选择策略,提供轮询与随机,这里选择用轮询

  17. sharding.jdbc.config.masterslave.load-balance-algorithm-type=round_robin

  18. sharding.jdbc.config.masterslave.name=ms

  19. sharding.jdbc.config.masterslave.master-data-source-name=master1

  20. sharding.jdbc.config.masterslave.slave-data-source-names=slave0

  21. # 开启SQL显示,默认值: false,注意:仅配置读写分离时不会打印日志

  22. sharding.jdbc.config.props.sql.show=true

  23. spring.main.allow-bean-definition-overriding=true

主要改动application.properties配置 其他地方不做改动

3.5 测试读写分

打开浏览器访问: http://localhost:8080/select 查询用户集

控制台打印:

可以查询看到走的从数据库

2.打开浏览器访问: http://localhost:8080/insert?id=1&name=lhd&age=12 插入一条数据 控制台打印:

可以看到插入数据走的主数据库 主库负责写 从库负责读 这样读写分离就这样做好了

项目地址: https://github.com/LiHaodong888/SpringBootLearn

1. 这样的老板哪里有?给我来一打!

2. 盘点那些 牛X 的代码注释

3. IDEA 中用好 Lombok

4. 分库分表就能无限扩容吗?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存