Mysql主从复制+读写分离

Mysql主从复制+读写分离

前言:最近一个项目用到了ShardingSphere 用于读写分离,于是琢磨着在本地写个demo玩玩,所以就有了这。一般而言:mysql读写分离的前提就是主从复制。如果没有主从复制,那么读写分离就没什么用了。比如你从主库写数据,然后从从库读数据,但是主库的数据都没同步到从库,那你岂不是读了个寂寞,对吧,显然是读取不到主库写入的数据的。

本篇大概内容

  1. windows下安装3个mysql服务,端口分别是3306(主),3307(从),3308(从);
  2. 配置好3个mysql服务的信息,模拟一主两从,主库写,从库读;
  3. 整合Sharding-jdbc+jpa+druid+springboot2实现读写分离。

篇幅有点长,需要点耐心

环境说明: 我这里是基于mysql5.7.29模拟一主二从的操作,其他mysql版本可能会有不兼容,暂不在本篇讨论范围之内。具体实现原理这里不做说明,感兴趣的朋友可自行了解。

一 首先在windows下安装3个mysql服务

相信很多朋友原本就已经安装过了mysql服务,所以只需要再安装两个mysql服务即可,那么,如何安装呢?
我这里给出的方法如下:

  • 原本已安装mysql不做处理,重新解压之前的安装包,并且解压两次,分别重命名,至于如何命名,请大家随意,没有影响的,我这里如下所示:
    Mysql主从复制+读写分离_第1张图片
    相信这一步,大家都没有任何问题。那么,我们继续下一步。

  • 复制之前mysql服务的my.ini文件(没有就新建一个),也就是mysql的配置文件分别复制到两个新的目录之下,我这里是D:/AllDownload/mysql-5.7.29-winx64-3307D:/AllDownload/mysql-5.7.29-winx64-3308,因为3307和3308的操作完全是一样的,所以我这里仅详细介绍3307的操作,3308就交给大家自己处理啦。

  • 复制之后,需要对配置文件进行修改,我这里贴出我的3307对应的my.ini配置文件:

[client]
# 设置mysql客户端默认字符集
default-character-set=utf8
 
[mysqld]
# 设置3307端口 默认是3306
port = 3307
# 设置mysql的安装目录
basedir=D:/AllDownload/mysql-5.7.29-winx64-3307
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
datadir=D:/AllDownload/mysql-5.7.29-winx64-3307/data
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
# 允许最大连接数
max_connections=500
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

group_concat_max_len = 1024000
max_allowed_packet=1073741824

大家看一眼应该就能明白了,3306、3307、3308的配置文件区别就在于port以及basedir以及datadir不一样,我这里只是贴出我的3307配置文件,大家根据自己实际情况来填写就好

  • 看到上面配置文件的datadir了吗,其值为D:/AllDownload/mysql-5.7.29-winx64-3307/data 。其中data文件夹是不存在的,需要我们去到对应的文件夹下新建。新建之后如下:
    Mysql主从复制+读写分离_第2张图片
  • 到此,准备工具完毕,接下来执行mysql3307服务的初始化操作,以管理员身份打开cmd控制台,一定要以管理员身份,否则可能会因为权限问题导致后续命令执行失败!
    打开cmd控制台后后,进入到mysql3307的bin目录下,如下所示:
    Mysql主从复制+读写分离_第3张图片
  • 首先执行install操作,即执行以下命令,注意不要直接执行
mysqld install mysql3307 --defaults-file="D:\AllDownload\mysql-5.7.29-winx64-3307\my.ini"

为什么不要直接执行呢?因为很多朋友肯定都是已经配置了mysql环境变量的,直接执行意味着什么呢?聪明的你,应该已经想到了,直接执行的话,会执行mysql3306服务的bin目录下的mysqld命令,而不是当前3307服务bin目录下的mysqld,那么,可能就会发生服务已存在之类的错误,或者其他错误。
所以,如何处理?最好是先删除mysql环境变量的配置,也就是 MYSQL_HOME啥的。
删除之后,再次执行上述命令,其中mysql3307是服务名,是为了区分于mysql服务的。
如果不想删除的话,试试加上.\,表示执行当前目录的mysqld,我没试过不知道效果

  • install之后,就是初始化,初始化命令如下(务必记下末尾的密码):
    mysqld --initialize --user=mysql3307 --console
    其实初始化就是生成data目录以及其中的文件,执行失败请删除data目录,找到问题后重新执行初始化。

    如果一切ok,那么接下来,启动mysql3307服务即可,启动命令:
    net start mysql3307

    启动成功,登录看看,一定要加-P 3307 不然就会默认登录到3306端口了
    mysql -u root -p -P 3307

    然后提示要求输入密码,初始化的时候会打印出密码。

到此,mysql3307服务安装启动完成,mysql3308也是同样的流程,我就不再赘述啦。

都ok的话,记得把mysql环境变量再配置一下。

异常问题处理: 上面是一切顺利的情况下,如果中途出现问题了,如何处理呢?因为大家情况不一,我也无法全部说到,反正百度基本就完事了。

但是,严格按照我上面的流程,基本都ok的。
我再贴一下mysql3307 mysql3308服务安装ok之后,我的注册表编辑器的信息:
Mysql主从复制+读写分离_第4张图片
这个注册表信息的mysql3307 mysql3308,当你执行完相应的install操作的时候,就会出现,我这里mysql3307服务的数值数据具体如下:

D:\AllDownload\mysql-5.7.29-winx64-3307\bin\mysqld --defaults-file=D:\AllDownload\mysql-5.7.29-winx64-3307\my.ini mysql3307

如果遇到什么问题,可以看看这里是否正确,因为事先安装了mysql环境变量,没有删除环境变量而直接install的话,你这里的目录就会对应到3306那边去了,就会导致后续一系列的操作无法成功。

如果没有按照流程而导致失败的,卸载重装吧,或者直接修改注册表的信息也行,这里说说如何卸载
管理员身份打开cmd窗口,首先查询对应的mysql服务是否存在,查询命令:sc query mysql3307

如果存在,直接删除,删除命令:sc delete mysql3307 ,再次查询就查不到了;

删除data目录(文件夹)下的所有文件,其实data目录也是可以删除的,初始化的时候会生成;

重新执行安装流程。

mysql3307和mysql3308服务均启动成功后,接下来就得配置主从复制了。

二 配置主从复制(3306主 3307从 3308从)

主从数据库的配置和代码无关,只需要配置mysql相关的设置即可。
我这里贴出3306的 my.ini 配置文件

default-character-set=utf8
 
[mysqld]
# 设置3306端口
port = 3306
# 设置mysql的安装目录
basedir=D:\AllDownload\mysql-5.7.29-winx64
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
datadir=D:\AllDownload\mysql-5.7.29-winx64\data
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
# 允许最大连接数
max_connections=500
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

group_concat_max_len = 1024000
max_allowed_packet=1073741824


# 主从复制配置 3306端口为主 其他为从

# 服务id,在主从中需要保证唯一
server-id=1

# 启用二进制日志 其实主从同步就是通过线程读取该日志文件执行的 每次mysql服务重新启动都会生成新的二进制文件
log-bin=mysql-bin

# 需要执行主从同步复制的数据库名称
binlog-do-db=test
# 不需要执行主从同步复制的数据库名称,一般Mysql自带的数据库就没必要了
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
# 自动清理20天前的log文件
expire_logs_days=20

具体什么意思已经写了注释了,3307和3308也是一样的,唯一的区别在于server-id不一样
然后,重新启动3306服务,windows下如何重启mysql我就不多说什么了(2种方法):
1.cmd窗口 net stop mysql 先停止,net start mysql 再启动
2.直接打开服务,就是在win+r 输入 services.msc 回车,找到mysql,点击重启即可,如下:
Mysql主从复制+读写分离_第5张图片
重启之后,首先查看是否开启了log_bin日志:
show variables like "%log_bin%";
Mysql主从复制+读写分离_第6张图片
然后配置一个新用户,并且配置主从复制的权限,用于执行主从复制,一般不会使用root用户,所以这里配置一个新用户,用户名大家随意取,开心就好。

//说明:创建用户slave01,密码是ccc 
//@后面表示允许连接的客户端ip地址 %表示允许所有ip地址
create user 'slave01'@'%' identified by 'ccc';

//格式:grant 权限 on 数据库名.表名 to 用户@登录主机 identified by "用户密码";
//@后面的ip地址为允许连接的客户端ip地址 %表示允许所有ip地址
//如果是mysql8 这个命令是不可用的 会报错 可用这条(grant replication slave on *.* to 'slave01'@'%' with grant option;)
grant replication slave on *.* to 'slave01'@'%' identified by 'ccc';

新增的slave01用户可以在mysql库的user表看到。

配置完毕之后,查看此时msater的状态:
Mysql主从复制+读写分离_第7张图片
File:二进制文件,用户主从复制的,每次mysql服务重启该文件都会改变;
Position:二进制文件的位置,主从复制开始的位置;
其他参数大家有兴趣可以自行查阅。

到此,主服务信息配置完毕,接下来重启mysql3307服务,配置文件和3306几乎一样,除了server-id以及各自的安装目录,数据存放目录。

重启之后,登录 mysql -u root -p -P 3307 执行如下命令开启从库复制功能

change master to master_host='127.0.0.1', master_port=3306, master_user='slave01', master_password='ccc', master_log_file='mysql-bin.000001', master_log_pos=154;
命令解析:
//master_host: 主服务器的IP  注意:大家根据自己实际情况填写
//master_user: 主服务器上新创建的用户名
//master_password: 用户的密码
//master_port: 主服务器的端口,如果未曾修改,默认即可。
//master_log_file: 主服务器二进制日志文件的名称,填写查看主服务器的master状态时显示的File的值
//master_log_pos: 日志的位置,填写查看主服务器的master状态时显示的Position的值

//然后开启从库功能
start slave;

以上两条命令执行完毕,查看从库状态:
show slave status \G
查看结果如下:

*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: slave01
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 688
               Relay_Log_File: LAPTOP-FRT2GIQ8-relay-bin.000002
                Relay_Log_Pos: 854
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 688
              Relay_Log_Space: 1071
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: 3751bfa8-8784-11ea-8e5b-5c80b6566b2e
             Master_Info_File: D:\AllDownload\mysql-5.7.29-winx64-3307\data\master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:

如果 Slave_IO_RunningSlave_SQL_Running 的值都为 Yes,则说明主从复制的所有配置已成功,即从服务器已经可以自动与主服务器的数据库数据实现同步了。

mysql3308也是同样的操作,我就不再重复了。

一切OK之后,我们可以试一试,我这里用navicat分别连接3个mysql服务,然后在3306创建test数据库,并且添加t_user表。3307和3308也会跟着自动创建test数据库库和t_user表主从复制完成
Mysql主从复制+读写分离_第8张图片
如果在主服务器执行test库之外的操作,从服务器是不会有任何变化的,因为设置为仅同步test库;
如果在从服务器的任何库执行写入操作,主服务器是不会有任何变化的,除非设置成互为主从。

好了,主从复制完成,接下来是读写分离操作,这块主要涉及到代码,上面更多的是安装配置。

三 ShardingSphere+jpa+druid+SpringBoot2实现读写分离

首先是ShardingSphere官方文档
感兴趣的可以看看,话不多说,直接上代码,因为是个小demo,所以代码很简单,基本没有,更多的是配置。
代码层面我们完全无需考虑读写分离这些,只要配置文件配置好了就行,该框架会帮我们处理这些问题。
首先引入相关依赖,我这里仅贴出关键依赖

	    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- Sharding-JDBC -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <!-- druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

然后是配置文件application.yml

spring:
  shardingsphere:
    datasource:
      #主从数据源 多个则以逗号分隔开
      names: master,slave0,slave1

      #主数据源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
        username: root
        password: root

      #从1数据源
      slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3307/test?useSSL=false&serverTimezone=UTC
        username: root
        password: root

      #从2数据源
      slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3308/test?useSSL=false&serverTimezone=UTC
        username: root
        password: root

    masterslave:
      name: ms
      master-data-source-name: master
      slave-data-source-names: slave0,slave1
      #负载均衡算法 round_robin 代表轮询
      load-balance-algorithm-type: round_robin

    props:
      sql:
        show: true

需要注意的是: druid数据源springboot版本和sharding-jdbc的配置存在冲突,如果这样配置直接启动的话,是无法启动的。
解决办法如下(3种):
1.在启动类排除druid数据源的配置@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class}) 即可;
2.druid数据源maven依赖不要引入spirngboot版本的;
3.使用hikari数据源,但是datasource下的url需要改成jdbc-url;
4.看你们的了…

然后随便写了两个方法,一个查询所有用户,一个添加用户,执行结果如下:
Mysql主从复制+读写分离_第9张图片
OK,完成。
其他什么分表分库,ShardingSphere也是可以胜任的,主要都是在配置这一块,代码层面就像操作单个数据库一样,非常简单好用。更多功能的话,等待大家自行尝试~

你可能感兴趣的:(学习篇,java,mysql)