mysql之主从复制原理及实践

引言

在现代数据库管理中,数据的高可用性和负载均衡是至关重要的。MySQL 的主从复制功能提供了一种有效的解决方案,可以通过将数据从一个主服务器复制到一个或多个从服务器,来实现数据的备份、读取负载分担和高可用性。本篇文章将深入探讨 MySQL 主从复制的原理、配置步骤以及实际应用场景。

一、主从复制原理

MySQL 的主从复制是基于事件的复制机制,主要包含以下几个关键概念:

  1. 主服务器(Master)

    • 主服务器负责处理所有的写操作和事务。所有的更改(如 INSERT、UPDATE 和 DELETE)首先在主服务器上执行。
  2. 从服务器(Slave)

    • 从服务器通过读取主服务器的二进制日志(binlog)来获取数据更改信息,并将这些更改应用到自身的数据库中。
  3. 二进制日志(binlog)

    • binlog 是 MySQL 中记录所有更改数据的日志文件。主服务器在执行每个更改操作时,会将该操作以事件的形式记录到 binlog 中。
  4. 复制线程

    • 从服务器通过一个 I/O 线程连接到主服务器,读取 binlog 并将其存储到本地的中继日志(relay log)中。然后,由一个 SQL 线程从中继日志中读取事件并应用到从服务器的数据库中。

主实例搭建

  1. 使用以下命令启动 MySQL 主实例:

    bash 复制代码
    docker run -p 3307:3306 --name mysql-master \
    -v /docker/mysql-master/log:/var/log/mysql \
    -v /docker/mysql-master/data:/var/lib/mysql \
    -v /docker/mysql-master/conf:/etc/mysql \
    -e MYSQL_ROOT_PASSWORD=123456 \
    -d mysql:5.7

    参数说明:

    • -p 3307:3306:将容器的 3306 端口映射到主机的 3307 端口。
    • --name mysql-master:设置容器的名称为 mysql-master
    • -v /docker/mysql-master/log:/var/log/mysql:将容器内的日志目录挂载到主机上,方便查看和管理日志。
    • -v /docker/mysql-master/data:/var/lib/mysql:将 MySQL 数据存储目录挂载到主机上,确保数据持久化。
    • -v /docker/mysql-master/conf:/etc/mysql:将配置文件目录挂载到主机上,便于修改配置。
    • -e MYSQL_ROOT_PASSWORD=123456:设置 MySQL 根用户密码(此处为示例,生产环境应设置复杂密码)。
    • -d mysql:5.7:在后台运行 MySQL 5.7 容器。
  2. 创建配置文件 my.cnf

    /docker/mysql-master/conf/ 目录下创建 my.cnf 文件,并添加以下配置内容:

    ini 复制代码
    [mysqld]
    ## 设置 server_id,同一局域网中需要唯一
    server_id = 1
    
    ## 指定不需要同步的数据库名称
    binlog-ignore-db = mysql
    
    ## 开启二进制日志功能
    log_bin = /var/log/mysql/mysql-bin.log
    
    ## 设置二进制日志使用内存大小(事务)
    binlog_cache_size = 1M
    
    ## 设置使用的二进制日志格式(mixed, statement, row)
    binlog_format = mixed
    
    ## 二进制日志过期清理时间。默认值为0,表示不自动清理
    expire_logs_days = 7
    
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免 slave 端复制中断
    ## 1062 错误为主键重复,1032 错误为主从数据库数据不一致
    slave_skip_errors = 1062

    配置说明:

    • server_id = 1:为主服务器设置一个唯一的 ID。在主从复制环境中,每个服务器的 server_id 必须唯一。
    • binlog-ignore-db = mysql:指定不需要同步的数据库,这里忽略 mysql 数据库。通常 mysql 数据库包含用户权限信息,可以选择不同步。
    • log_bin = /var/log/mysql/mysql-bin.log:启用二进制日志功能,并将日志文件存储在指定路径 /var/log/mysql/mysql-bin.log 下。二进制日志是主从复制的基础。
    • binlog_cache_size = 1M:设置每个会话使用的二进制日志缓存大小,默认值为 1MB。适当的缓存大小可以提升大事务的写入效率。
    • binlog_format = mixed:设置二进制日志的格式为 mixed,此格式可以在 row(行格式)和 statement(语句格式)之间切换,以适应不同的写入需求。
    • expire_logs_days = 7:设置二进制日志的自动清理周期为 7 天,避免日志文件占用过多磁盘空间。可以根据需要调整。
    • slave_skip_errors = 1062:在主从复制过程中,跳过指定错误以避免复制中断。例如,1062 错误为主键重复错误,常用于忽略主从数据库不一致导致的特定问题。
  3. 配置完成后重启 MySQL 主实例

    使用以下命令重启 mysql-master 容器,使新配置生效:

    bash 复制代码
    docker restart mysql-master
  4. 进入 mysql-master 容器

    重启后,可以使用以下命令进入正在运行的 mysql-master 容器:

    bash 复制代码
    docker exec -it mysql-master bash
  5. 登录到 MySQL 客户端

    进入容器后,使用以下命令以 root 用户身份登录 MySQL:

    bash 复制代码
    mysql -u root -p123456
  6. 创建数据同步用户

    在 MySQL 控制台中,创建一个用于数据同步的专用用户,确保该用户具备 REPLICATION SLAVE 权限。执行以下 SQL 命令:

    sql 复制代码
    CREATE USER 'replica_user'@'%' IDENTIFIED BY 'replica_password';
    GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';
    FLUSH PRIVILEGES;
    • CREATE USER 'replica_user'@'%' IDENTIFIED BY 'replica_password';:创建名为 replica_user 的用户,并设置密码为 replica_password
    • GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';:授予该用户 REPLICATION SLAVE 权限,以便该用户用于主从复制的数据同步。
    • FLUSH PRIVILEGES;:刷新权限,使新用户权限立即生效。
    具体示例

    比如,我们创建一个名为 slave 的同步用户,密码为 123456,用于从实例同步数据:

    sql 复制代码
    CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
    GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%';
    FLUSH PRIVILEGES;

配置完成后,slave 用户即可用于从实例的数据同步连接,接下来可以继续配置从实例。

从实例搭建

  1. 使用以下命令启动 MySQL 从实例:

    bash 复制代码
    docker run -p 3308:3306 --name mysql-slave \
    -v /docker/mysql-slave/log:/var/log/mysql \
    -v /docker/mysql-slave/data:/var/lib/mysql \
    -v /docker/mysql-slave/conf:/etc/mysql \
    -e MYSQL_ROOT_PASSWORD=123456 \
    -d mysql:5.7
  2. 创建配置文件 my.cnf

    /docker/mysql-slave/conf/ 目录下创建 my.cnf 文件,并添加以下配置内容:

    ini 复制代码
    [mysqld]
    ## 设置 server_id,与主服务器不同
    server_id = 2
    
    ## 设置中继日志路径
    relay_log = /var/log/mysql/mysql-relay-bin.log
    
    ## 指定不需要同步的数据库名称
    binlog-ignore-db = mysql
    
    ## 二进制日志设置(如果需要从服务器充当主服务器进行多级复制)
    log_bin = /var/log/mysql/mysql-slave-bin.log
    
    ## 设置二进制日志使用内存大小(事务)
    binlog_cache_size = 1M
    
    ## 设置二进制日志格式
    binlog_format = mixed
    
    ## 二进制日志过期清理时间
    expire_logs_days = 7
    
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免 slave 端复制中断
    ## 1062 错误为主键重复,1032 错误为主从数据库数据不一致
    slave_skip_errors = 1062

    配置说明:

    • server_id = 2:设置从服务器的唯一 ID,确保与主服务器不同。
    • relay_log = /var/log/mysql/mysql-relay-bin.log:设置中继日志的文件路径,用于存储从服务器接收到的主服务器更改记录。
    • binlog-ignore-db = mysql:忽略同步 mysql 数据库(如不需要同步用户权限)。
    • log_bin = /var/log/mysql/mysql-slave-bin.log:设置从服务器的二进制日志文件路径(可选,适用于多级复制)。
    • binlog_cache_size = 1M:设置二进制日志缓存大小。
    • binlog_format = mixed:设置二进制日志格式为 mixed
    • expire_logs_days = 7:设置二进制日志保留 7 天,防止日志占用过多磁盘空间。
    • slave_skip_errors = 1062:在主从复制过程中,跳过指定的错误,避免复制中断。
  3. 重启从实例容器

    完成配置文件设置后,使用以下命令重启 mysql-slave 容器以使更改生效:

    bash 复制代码
    docker restart mysql-slave

主从数据库连接

  1. 登录主实例 MySQL 客户端并查看主数据库状态

    首先,通过以下命令进入 mysql-master 容器并登录 MySQL 客户端:

    bash 复制代码
    docker exec -it mysql-master bash
    mysql -u root -p123456
  2. 查看主数据库状态

    登录后,使用以下命令查看主实例的状态,以获取二进制日志的文件名和位置:

    ini 复制代码
    SHOW MASTER STATUS;

    主数据库的状态如下:

    记下 FilePosition 字段的值(例如 mysql-bin.000001749),稍后将用于配置从实例连接到主实例。

  3. 进入从实例容器

    使用以下命令进入 mysql-slave 容器:

    bash 复制代码
    docker exec -it mysql-slave bash
  4. 登录从实例的 MySQL 客户端

    mysql-slave 容器中,使用以下命令登录 MySQL 客户端:

    mysql -u root -p123456
    
  5. 配置主从复制

    登录 MySQL 后,使用以下命令配置从实例连接到主实例。请将 MASTER_HOSTMASTER_PORTMASTER_USERMASTER_PASSWORDMASTER_LOG_FILEMASTER_LOG_POS 的值替换为实际的主实例 IP 地址、端口号、同步用户及其密码,以及在主实例中通过 SHOW MASTER STATUS 命令获取的 FilePosition 值。包含所有必要的选项:

    ini 复制代码
    sql
    复制代码
    CHANGE MASTER TO
        MASTER_HOST='主实例IP地址',
        MASTER_PORT=3306,
        MASTER_USER='replica_user',
        MASTER_PASSWORD='replica_password',
        MASTER_LOG_FILE='mysql-bin.000001',
        MASTER_LOG_POS=154,
        MASTER_CONNECT_RETRY=10;

    参数说明:

    • MASTER_HOST:主实例的 IP 地址。
    • MASTER_PORT:主实例的端口(此处假设为 3306)。
    • MASTER_USER:用于同步的用户(例如 replica_user)。
    • MASTER_PASSWORD:同步用户的密码(例如 replica_password)。
    • MASTER_LOG_FILE:主实例当前的二进制日志文件(例如 mysql-bin.000001)。
    • MASTER_LOG_POS:二进制日志的读取位置(例如 154)。
    • MASTER_CONNECT_RETRY:从实例连接失败时重试的间隔时间(单位为秒),此处设置为 10 秒。

    示例配置

    我们按照上面配置的主实例参数来配置主从复制,示例如下:

    ini 复制代码
    sql
    复制代码
    CHANGE MASTER TO
        MASTER_HOST='172.17.0.10',
        MASTER_USER='slave',
        MASTER_PASSWORD='123456',
        MASTER_PORT=3306,
        MASTER_LOG_FILE='mysql-bin.000001',
        MASTER_LOG_POS=749,
        MASTER_CONNECT_RETRY=30;

    在此示例中:

    • MASTER_HOST:主实例的 IP 地址为 172.17.0.10
    • MASTER_USERMASTER_PASSWORD:用于同步的用户为 slave,密码为 123456
    • MASTER_PORT:主实例的端口号为 3306
    • MASTER_LOG_FILEMASTER_LOG_POS:主实例的二进制日志文件为 mysql-bin.000001,位置为 749
    • MASTER_CONNECT_RETRY:设置为 30 秒,即从实例在连接失败时会每 30 秒重试一次。
  6. 验证复制状态

    使用以下命令查看复制状态,确保配置成功:

    ini 复制代码
    SHOW SLAVE STATUS\G;
    • 从数据库状态显示如下:

在输出中,确认 Slave_IO_RunningSlave_SQL_Running 的值为 No,表示主从复制还没开始工作。

  1. 启动从实例的复制进程

    运行以下命令启动从实例的复制进程:

    ini 复制代码
    START SLAVE;

    查看同步状态

    运行 SHOW SLAVE STATUS\G;,查看从数据库状态,确认已经同步:

    如果 Slave_IO_RunningSlave_SQL_Running 均为 Yes,则表示主从复制成功。

测试主从复制是否已成功搭建

  1. 登录主实例数据库并创建一个测试数据库

    首先,进入 mysql-master 容器并登录 MySQL:

    bash 复制代码
    bash
    复制代码
    docker exec -it mysql-master bash
    mysql -u root -p123456

    然后在主实例中创建一个测试数据库:

    sql 复制代码
    sql
    复制代码
    CREATE DATABASE test_replication;

    创建完成后,您应该会看到如下输出,表示数据库已成功创建:

  2. 登录从实例数据库并检查是否已同步该数据库

    接下来,进入 mysql-slave 容器并登录 MySQL:

    bash 复制代码
    bash
    复制代码
    docker exec -it mysql-slave bash
    mysql -u root -p123456

    在从实例中检查是否已同步 test_replication 数据库:

    sql 复制代码
    sql
    复制代码
    SHOW DATABASES;

在从实例中看到 test_replication 数据库已经存在,说明主从复制已经成功搭建。

相关推荐
老王笔记21 分钟前
GTID详解
mysql
啥都想学的又啥都不会的研究生1 小时前
高性能MySQL-查询性能优化
数据库·笔记·学习·mysql·面试·性能优化
m0_748256142 小时前
前端图表与数据可视化 - 2024 年实战与面试重点
前端·信息可视化·面试
计算机学姐2 小时前
基于SpringBoot的校园求职招聘管理系统
java·前端·vue.js·spring boot·后端·mysql·intellij-idea
core5123 小时前
flink SQL实现mysql source sink
mysql·flink·jdbc·source·cdc·sink·mysql-cdc
卷心菜是俺4 小时前
JVM和数据库面试知识点
jvm·数据库·面试
Marx82014 小时前
英语尬面后,我做了一个生成英语学习视频的小工具
前端·面试·产品
Oneforlove_twoforjob4 小时前
【Java基础面试题026】Java中的String、StringBuffer和StringBuilder的区别是什么?
java·开发语言·面试
山山而川粤4 小时前
时间管理系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
你有抖音吗4 小时前
请说下你对 MYSQL 架构的了解?
mysql·架构