MySQL的主从复制

371 阅读5分钟

MySQL的主从复制

什么是主从复制

​ 介绍:

​ master(主服务器)

​ slave (从服务器)

​ mysql主从是异步复制过程

​ master开启bin-log功能,日志文件用于记录数据库的读写增删 ​ 需要开启3个线程,master IO线程,slave开启 IO线程 SQL线程, ​ Slave 通过IO线程连接master,并且请求某个bin-log,position之后的内容。 ​ MASTER服务器收到slave IO线程发来的日志请求信息,io线程去将bin-log内容,position返回给slave IO线程。 ​ slave服务器收到bin-log日志内容,将bin-log日志内容写入relay-log中继日志,创建一个master.info的文件,该文件记录了master ip 用户名 密码 master bin-log名称,bin-log position。 ​ slave端开启SQL线程,实时监控relay-log日志内容是否有更新,解析文件中的SQL语句,在slave数据库中去执行。

准备工作

两台数据库,分布在不同主机上,相互可以通信。(相同版本数据库)

MySQL配置

主数据库配置 修改 my.cnf配置文件

# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mysqld according to the
# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld]

# 开启bin-log日志 记录数据库的读写增删
log-bin=mysql-bin

# 设置服务id, 主从不能一致
server_id=1

# 设置需要同步的数据库
binlog-do-db=user_db

# 屏蔽系统库同步
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysql/mysqld.log
pid-file=/run/mysqld/mysqld.pid

从数据库配置

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html

[mysqld]

# binlog文件名
log-bin=mysql-bin
# 选择ROW 模式
binlog_format=ROW 
# 设置服务id 主从不能一致
server_id=2 

# 设置需要同步的数据库
replicate_wild_do_table=user_db.%
# 屏蔽系统库同步
replicate_wild_ignore_table=mysql.%
replicate_wild_ignore_table=information_schema.%
replicate_wild_ignore_table=performance_schema.%

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

主从搭建

  1. 重启 主、从数据库

  2. 在主数据新增用户,用于从数据库读取bin-log 日志

    -- 创建用户
    GRANT REPLICATION SLAVE ON *.* TO 'db_sync'@'%' IDENTIFIED BY 'db_sync';
    
    CREATE USER 'db_sync'@'%' IDENTIFIED BY  'db_sync'
    
    -- 授权
    GRANT ALL PRIVILEGES ON *.* TO 'db_sync'@'%' WITH GRANT OPTION
    
    -- 刷新权限
    FLUSH PRIVILEGES;
    
    -- 显示主数据库状态
    SHOW MASTER STATUS;
    

    image-20220405162735975

FIlePosisionBinloh_Do_DBBinloh_Ignore_DBExecuted_Gtid_Set
bin-log 日志文件名称当前bin-log 已记录坐标进行主从复制的数据库已忽略不同步的数据库事务集
  1. 从数据库连接主数据库

    -- 停止同步策略
    STOP SLAVE;
    
    -- 与主数据库建立连接 
    CHANGE MASTER TO 
    MASTER_HOST = '172.25.3.199',  -- 主数据库IP
    MASTER_USER = 'db_sync',	   -- 访问用户名
    MASTER_PASSWORD = 'db_sync',   -- 访问密码
    MASTER_LOG_FILE = 'mysql-bin.000001', -- bin-log 文件名称
    MASTER_LOG_POS = 255615584;			-- bin-log日志坐标(决定从哪个坐标的记录开始复制)
    
    -- 启动从库 主从复制
    START SLAVE
    
    -- 显示从库状态
    SHOW SLAVE STATUS;
    

    image-20220405163634821

    | Mster_Host | Master_User | Master_Port | Master_Log_File | Read_Master_Log_pos | Slave_IO-Running | Slave_SQL_Runing | | ---------- | ------------ | ------------ | --------------- | ---------------------- | ---------------- | ----------------------- | | 主机IP | 访问主机用户 | 主数据库端口 | 日志文件名 | 已读取主机日志文件坐标 | 从机IO是否运行 | 从机读取日志SQL是否执行 |

  2. 检查主从连接是否成功

    | Slave_IO-Running | Slave_SQL_Runing | | ---------------- | ---------------- | | YES | YES |

    **如: ** Slave_IO-RunningSlave_SQL_Runing 都为YES状态。则代表主从复制搭建成功

  3. 主从复制不成功,检查

    • 排查主从数据库配置文件是否遗漏
    • 排查主数据库用户账号密码是否正确
    • 排查主数据BIN-LOG 是否已开启

填坑

​ 我在进行搭建主从复制数据库的时候遇到过这样一个问题,配置都是对的但是主从复制时 Slave_IO-Running 一直为NO 状态。在仔细检查了我的配置文件、数据库连接、防火墙、用户名密码、BIN-LOG 后发现都没有问题。最后的问题是:因为我的两台数据库所在的服务器是我使用镜像复制的。造成了两台数据库的 server-uuid 是相同的。

image-20220405165458996

linux:/var/lib/mysql/auto.cnf

​ 解决办法就是:这行代码删掉,重启MYSQL。让它自己重新生成。

接入ShardingJDBC

创建maven工程,引入依赖

<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

数据库,主从一致

image-20220405170201554

properties配置

# sharingJDBC 垂直分表 专库专表
spring.shardingsphere.datasource.names=master0,slave0

# 一个实体类对应两张表 覆盖
spring.main.allow-bean-definition-overriding=true


# master数据源基础配置
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://81.68.101.110:3306/user_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=xxxxx

# slave数据源基础配置
spring.shardingsphere.datasource.master0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master0.url=jdbc:mysql://113.110.223.106:3306/user_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.master0.username=root
spring.shardingsphere.datasource.master0.password=xxxxx


# 主从库 配置
#spring.shardingsphere.masterslave.master-data-source-name=master0
#spring.shardingsphere.masterslave.slave-data-source-names=slave0

spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=master0
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=slave0


# 配置公共表  公共表的策略,每个数据源中都有这个表 增删改 数据源同步
spring.shardingsphere.sharding.broadcast-tables=t_udict
# 指定主键 生成策略 SNOWFLAKE 雪花算法
spring.shardingsphere.sharding.tables.t_udict.key-generator.column=dict_id
spring.shardingsphere.sharding.tables.t_udict.key-generator.type=SNOWFLAKE

# 专库专表
#spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{1}.t_user
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds0.t_user

# 指定主键 生成策略 SNOWFLAKE 雪花算法
spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE


# 指定表主键, 表名称
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user



# 指定数据库分片策略 , 约定 user_id 为偶数 添加 m1 表, 奇数添加 m2 表
# 配置方式1 指定所有表 按此规则划分数据
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2}


# 配置方式 2 指定表 使用该策略
#spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}



# 查看底层 SQL 执行
spring.shardingsphere.props.sql.show=true

YAML 配置

spring:
  shardingsphere:
    # 参数配置,显示sql
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名,下面的ds1,ds2,ds3任意取名字
      names: ds1,ds2,ds3
      # 给master-ds1每个数据源配置数据库连接信息
      ds1:
        # 配置druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://119.215.145.270:3306/order_db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2b8
        username: root
        password: mkxiaoer1986.
        maxPoolSize: 100
        minPoolSize: 5
      # 配置ds2-slave
      ds2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://119.215.145.271:3306/order_db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2b8
        username: root
        password: mkxiaoer
        maxPoolSize: 100
        minPoolSize: 5
      # 配置ds3-slave
      ds3:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://114.205.165.208:3306/order_db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT%2b8
        username: root
        password: mkxiaoer
        maxPoolSize: 100
        minPoolSize: 5
    # 配置默认数据源ds1
    sharding:
      # 默认数据源,主要用于写,注意一定要配置读写分离 ,注意:如果不配置,那么就会把三个节点都当做从slave节点,新增,修改和删除会出错。
      default-data-source-name: ds1
    # 配置数据源的读写分离,但是数据库一定要做主从复制
    masterslave:
      # 配置主从名称,可以任意取名字
      name: ms
      # 配置主库master,负责数据的写入
      master-data-source-name: ds1
      # 配置从库slave节点
      slave-data-source-names: ds2,ds3
      # 配置slave节点的负载均衡均衡策略,默认机制是:random_robin 如果你修改成随机RANDOM
      load-balance-algorithm-type: RANDOM

代码

// 写入数据
	@Test
    public void addUser(){
        User user = new User();
        user.setUserName("lisa").setUserStatus(1L);
        userMapper.insert(user);
    }

// 读取数据
    @Test
    public void findByUser(){

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id",718149835269603329L);

        User user = userMapper.selectOne(queryWrapper);

        System.out.println(user);

    }

测试结果

// 插入
Actual SQL: master0 ::: INSERT INTO t_user   (user_name, user_status, user_id) VALUES (?, ?, ?) ::: [b, 1, 718149835269603329]

// 读取
Actual SQL: slave0 ::: SELECT  user_id,user_name,user_status  FROM t_user 
User(userId=718149835269603329, userName=b, userStatus=1)