引言
在现代数据库管理中,数据的高可用性和负载均衡是至关重要的。MySQL 的主从复制功能提供了一种有效的解决方案,可以通过将数据从一个主服务器复制到一个或多个从服务器,来实现数据的备份、读取负载分担和高可用性。本篇文章将深入探讨 MySQL 主从复制的原理、配置步骤以及实际应用场景。
一、主从复制原理
MySQL 的主从复制是基于事件的复制机制,主要包含以下几个关键概念:
-
主服务器(Master) :
- 主服务器负责处理所有的写操作和事务。所有的更改(如 INSERT、UPDATE 和 DELETE)首先在主服务器上执行。
-
从服务器(Slave) :
- 从服务器通过读取主服务器的二进制日志(binlog)来获取数据更改信息,并将这些更改应用到自身的数据库中。
-
二进制日志(binlog) :
- binlog 是 MySQL 中记录所有更改数据的日志文件。主服务器在执行每个更改操作时,会将该操作以事件的形式记录到 binlog 中。
-
复制线程:
- 从服务器通过一个 I/O 线程连接到主服务器,读取 binlog 并将其存储到本地的中继日志(relay log)中。然后,由一个 SQL 线程从中继日志中读取事件并应用到从服务器的数据库中。
主实例搭建
-
使用以下命令启动 MySQL 主实例:
bashdocker 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 容器。
-
创建配置文件
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
错误为主键重复错误,常用于忽略主从数据库不一致导致的特定问题。
-
配置完成后重启 MySQL 主实例
使用以下命令重启
mysql-master
容器,使新配置生效:bashdocker restart mysql-master
-
进入
mysql-master
容器重启后,可以使用以下命令进入正在运行的
mysql-master
容器:bashdocker exec -it mysql-master bash
-
登录到 MySQL 客户端
进入容器后,使用以下命令以
root
用户身份登录 MySQL:bashmysql -u root -p123456
-
创建数据同步用户
在 MySQL 控制台中,创建一个用于数据同步的专用用户,确保该用户具备
REPLICATION SLAVE
权限。执行以下 SQL 命令:sqlCREATE 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
,用于从实例同步数据:sqlCREATE USER 'slave'@'%' IDENTIFIED BY '123456'; GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%'; FLUSH PRIVILEGES;
配置完成后,slave
用户即可用于从实例的数据同步连接,接下来可以继续配置从实例。
从实例搭建
-
使用以下命令启动 MySQL 从实例:
bashdocker 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
-
创建配置文件
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
:在主从复制过程中,跳过指定的错误,避免复制中断。
-
重启从实例容器
完成配置文件设置后,使用以下命令重启
mysql-slave
容器以使更改生效:bashdocker restart mysql-slave
主从数据库连接
-
登录主实例 MySQL 客户端并查看主数据库状态
首先,通过以下命令进入
mysql-master
容器并登录 MySQL 客户端:bashdocker exec -it mysql-master bash mysql -u root -p123456
-
查看主数据库状态
登录后,使用以下命令查看主实例的状态,以获取二进制日志的文件名和位置:
iniSHOW MASTER STATUS;
主数据库的状态如下:
记下
File
和Position
字段的值(例如mysql-bin.000001
和749
),稍后将用于配置从实例连接到主实例。 -
进入从实例容器
使用以下命令进入
mysql-slave
容器:bashdocker exec -it mysql-slave bash
-
登录从实例的 MySQL 客户端
在
mysql-slave
容器中,使用以下命令登录 MySQL 客户端:mysql -u root -p123456
-
配置主从复制
登录 MySQL 后,使用以下命令配置从实例连接到主实例。请将
MASTER_HOST
、MASTER_PORT
、MASTER_USER
、MASTER_PASSWORD
、MASTER_LOG_FILE
和MASTER_LOG_POS
的值替换为实际的主实例 IP 地址、端口号、同步用户及其密码,以及在主实例中通过SHOW MASTER STATUS
命令获取的File
和Position
值。包含所有必要的选项:inisql 复制代码 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 秒。
示例配置
我们按照上面配置的主实例参数来配置主从复制,示例如下:
inisql 复制代码 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_USER
和MASTER_PASSWORD
:用于同步的用户为slave
,密码为123456
。MASTER_PORT
:主实例的端口号为3306
。MASTER_LOG_FILE
和MASTER_LOG_POS
:主实例的二进制日志文件为mysql-bin.000001
,位置为749
。MASTER_CONNECT_RETRY
:设置为 30 秒,即从实例在连接失败时会每 30 秒重试一次。
-
验证复制状态
使用以下命令查看复制状态,确保配置成功:
iniSHOW SLAVE STATUS\G;
- 从数据库状态显示如下:
在输出中,确认 Slave_IO_Running
和 Slave_SQL_Running
的值为 No
,表示主从复制还没开始工作。
-
启动从实例的复制进程
运行以下命令启动从实例的复制进程:
iniSTART SLAVE;
查看同步状态
运行
SHOW SLAVE STATUS\G;
,查看从数据库状态,确认已经同步:如果
Slave_IO_Running
和Slave_SQL_Running
均为Yes
,则表示主从复制成功。
测试主从复制是否已成功搭建
-
登录主实例数据库并创建一个测试数据库
首先,进入
mysql-master
容器并登录 MySQL:bashbash 复制代码 docker exec -it mysql-master bash mysql -u root -p123456
然后在主实例中创建一个测试数据库:
sqlsql 复制代码 CREATE DATABASE test_replication;
创建完成后,您应该会看到如下输出,表示数据库已成功创建:
-
登录从实例数据库并检查是否已同步该数据库
接下来,进入
mysql-slave
容器并登录 MySQL:bashbash 复制代码 docker exec -it mysql-slave bash mysql -u root -p123456
在从实例中检查是否已同步
test_replication
数据库:sqlsql 复制代码 SHOW DATABASES;
在从实例中看到 test_replication
数据库已经存在,说明主从复制已经成功搭建。