MySQL的主从复制和读写分离

以下内容首发于我的个人网站:https://riun.xyz/

一、主从复制

Mysql的主从复制是一个异步的复制过程:一台或多台Mysql数据库(slave,即从库)从另一台Mysql数据库(master,即主库)进行日志的复制然后再解析日志应用到自身。最终实现只对主库进行写操作,但是从库却和主库数据保持一致的效果。这是基于Mysql自带的二进制日志实现的,无需第三方工具。

主从复制一般配合读写分离使用。写主库,读从库。

具体来说Mysql主从复制分三步:

1、master将自身改变记录到二进制日志(binary log)。

2、slave将master的binary log拷贝到它的中继日志(relay log)中。

3、slave执行中继日志中的事件,将改变应用到自己的数据库中。

注意:

  • 在Mysql的主从复制中,主库一般只有一个,从库可以多个。

  • 配置主从复制时,主库不能进行任何写操作。

  • 先安装好两台Mysql服务,再做以下配置。

主库配置

1、修改Mysql数据库配置文件my.cnf

[mysqld]
# 启动二进制日志功能
log-bin=mysql-bin
#服务器唯一id,需要在这几个主从复制的机器当中是唯一的
server-id=100

2、重启Mysql服务:systemctl restart mysqld

3、登录Mysql执行:GRANT REPLICATION SLAVE ON . to ‘xiaoming’@‘%’ identified by ‘Root@123456’;

如果你使用的是Mysql8,则会报错。因为Mysql8不允许GRANT 和identified一起执行,创建用户和分配权限必须分开执行:

# 创建用户xiaoming,并设置密码,运行任何主机连接
CREATE USER 'xiaoming'@'%' IDENTIFIED BY 'Root@123456';
# 授予xiaoming权限REPLICATION SLAVE,作用在任何库表上
GRANT REPLICATION SLAVE ON *.* TO 'xiaoming'@'%';
# 刷新权限
FLUSH PRIVILEGES;

上述sql创建了一个用户xiaoming,密码是Root@123456,并给这个用户赋予REPLICATION SLAVE权限。这是为了让从库可以从主库复制binary log。

创建完成之后,建议在navicat之类的工具中使用这个新创建的用户xiaoming尝试连接, 如果连接失败且报错密码cachexxx错误,则可以用以下方式解决:

-- 设置密码并同时修改身份验证插件为 caching_sha2_password
ALTER USER 'xiaoming'@'%' IDENTIFIED WITH caching_sha2_password BY 'Root@123456';

-- 再次修改身份验证插件为 mysql_native_password
ALTER USER 'xiaoming'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123456';

# 刷新权限
FLUSH PRIVILEGES;

这是因为默认创建出来的密码是caching_sha2_password身份验证的,我们需要将验证方式改为mysql_native_password。如果使用caching_sha2_password则在你的主库上需要做额外的配置否则从库和客户端都无法连接。

4、在Mysql中执行:show master status

执行完这个操作后主库不要再执行任何命令,停止读写。因为一旦执行其他操作,File和Position都会变化。

从库配置

有几个从库,这几个从库就都要配置

1、修改Mysql数据库配置文件my.cnf

[mysqld]
#服务器唯一id
server-id=101

2、重启Mysql服务:systemctl restart mysqld

3、登录Mysql执行sql:

# 这里需要修改为你的主库ip、用户名、密码、File、Position
change master to master_host='192.168.188.100',master_user='xiaoming',master_password='Root@123456',master_log_file='mysql-bin.000005',master_log_pos=441;

# 启动slave,开启io_thread线程
start slave;

4、执行:show slave status;

把输出内容粘贴到记事本看起来方便,查看到两个Yes,就是正常的。(前者代表io-thread,后者代表sql-thread。都是yes代表都在运行)

问题排查

如果你不慎在主库上执行了change master to xxx的命令,则可能需要做以下操作

# 停止复制进程
stop slave;

# 清除服务器上的复制信息和中继日志文件:
RESET SLAVE;

# 如果存在中继日志文件,删除它们:
# 在 MySQL 数据目录下找到并删除中继日志文件
rm -f relay-log.info
rm -f relay-log.[index_number]

测试效果与注意事项

接着就能测试了:在主库创建数据库、表、插入数据,都会自动同步到从库中去。

注意,主从复制配置完成之前,主库的所有库表都不会自动同步到从库中去。因此需要在change master to之前,把主库已存在的库表都手动同步到从库上。

二、读写分离

为什么要读写分离?对于大量系统而言都是读多写少的,面对日益增加的系统访问量,数据库的吞吐量面临巨大瓶颈。将数据库拆分为主库和从库,能够有效的避免由数据更新导致的行所,使得整个系统的查询性能得到极大改善。

分离前:

分离后:

0、sharding-jdbc

Sharding-jdbc是轻量级Java框架,在jdbc层提供额外服务。可以理解为增强版的JDBC驱动,完全兼容jdbc和各种orm框架。因此使用起来非常方便:

  • 适用于任何orm框架,如jpa、Hibernate、Mybatis、Spring JDBC Template或直连jdbc。
  • 支持任何第三方数据库连接池,如DBCP、C3PO、BoneCP、Druid、HikariCP等。
  • 支持任意实现jdbc规范的数据库,如MySQL、Oracle、SQLServer、PostgreSQL等。

1、导入依赖

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

2、配置读写分离规则

spring:
  main:
    # 允许bean定义覆盖配置项 否则druid的dataSource会和Sharding-jdbc的dataSource互相覆盖
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names:
        master,slave
      # 主数据源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://47.116.177.56:3306/sharding-test?characterEncoding=utf-8
        username: root
        password: hanxuxu
      # 从数据源
      slave:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://47.116.177.56:3307/sharding-test?characterEncoding=utf-8
        username: root
        password: hanxuxusalve
    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  方便我们观察读写是哪个库(此配置非必须)

读写分离效果和代码

package com.example.shardingdemo;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.shardingdemo.entity.Person;
import com.example.shardingdemo.mapper.PersonMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

/**
 * @author: HanXu
 * on 2024/7/10
 * Class description:
 */
@SpringBootTest
public class PersonTest {

    @Resource
    private PersonMapper personMapper;


    @Test
    void test() {
        Person person = new Person();
        person.setAge(18);
        person.setName("riun");
        person.setDepartment("研发部");
        personMapper.insert(person);


        Integer integer = personMapper.selectCount(new QueryWrapper<>());
        System.out.println("integer = " + integer);
    }

    /* 可以看到,插入是操作的master数据库;查询是操作的slave数据库

    2024-07-10 14:27:59.346  INFO 21620 --- [           main] ShardingSphere-SQL                       : Rule Type: master-slave
    2024-07-10 14:27:59.347  INFO 21620 --- [           main] ShardingSphere-SQL                       : SQL: INSERT INTO person  ( id,
    name,
    age,
    department )  VALUES  ( ?,
    ?,
    ?,
    ? ) ::: DataSources: master
    2024-07-10 14:27:59.392  INFO 21620 --- [           main] ShardingSphere-SQL                       : Rule Type: master-slave
    2024-07-10 14:27:59.393  INFO 21620 --- [           main] ShardingSphere-SQL                       : SQL: SELECT COUNT( 1 ) FROM person ::: DataSources: slave
    integer = 1
     */
}

使用sharding-jdbc我们可以非常简单的实现读写分离。

完整版代码:https://github.com/hanhanhanxu/Sharding-demo

结语

其实,阿里云有现成的主从复制读写分离服务可以买来用。是一个代理服务器,后面连一个主库,连两个从库(可能更多)。不用我们配置任何东西,只需要将项目中数据库的url配置为代理服务器即可。其他都不用改,就自动实现主从复制读写分离了。

而在企业级开发中,如果我们的数据、流量都很小。那完全用不到主从复制读写分离。也不建议使用。用了有时候反而会有奇怪的问题。如果我们的数据、流量都很大,在增加了缓存、MQ、异步化、数据库表拆分之后还是存在数据库读写瓶颈,那就需要考虑使用主从复制读写分离了。

在使用时,一般不会选择上述方式,因为对于大数据、大流量下,上述方式可能会对已有服务有侵入,对运维和开发人员也不友好。

对于中小型企业,使用时建议直接购买阿里云已有的主从复制读写分离rds服务就可以。

对于大型企业,则需要基础设施团队自研内部的MySQL服务,包装为上述阿里云的方式,对企业内部使用时也是只需要修改数据库url地址即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值