一、背景介绍:为什么需要 MySQL 主从复制?
在实际生产环境中,单台 MySQL 服务器存在明显的风险和性能瓶颈:
- 单点故障:一旦服务器宕机,业务将完全中断;
- 性能瓶颈:读写请求全部集中在一台服务器,高并发场景下响应缓慢;
- 数据安全:单节点存储数据,硬件故障可能导致数据丢失。
MySQL 主从复制(Master-Slave Replication)是解决上述问题的经典方案:
- 主库(Master):负责处理所有写操作(增删改),是数据的 “源头”;
- 从库(Slave):通过复制主库的二进制日志(binlog)同步数据,主要处理读操作(查询);
- 核心价值:实现读写分离、数据备份、故障转移,提升系统可用性和性能。
本文基于 CentOS 7 系统和 MySQL 5.7 版本,从零开始拆解主从复制的搭建流程,包含环境准备、安装配置、同步测试和问题排查,适合运维工程师和后端开发人员学习实践。
二、核心关键词解释
- 二进制日志(binlog):主库记录所有数据变更操作的日志文件,是主从复制的 “数据源”;
- 中继日志(relay log):从库接收主库的 binlog 后,先写入中继日志,再逐步执行,避免直接执行 binlog 导致的性能问题;
- server-id:主从服务器的唯一标识(必须不同),用于区分复制拓扑中的节点;
- 复制用户:主库中专门用于从库连接并获取 binlog 的用户,需授予
REPLICATION SLAVE权限; - GTID(全局事务标识符):MySQL 5.6 + 引入的特性,通过全局唯一 ID 标识事务,简化复制配置(本文使用传统的日志文件 + 位置方式)(暂时与本文无关)。
三、环境准备
1. 基础要求
- 两台 CentOS 7 服务器(分别作为主库、从库):硬件配置建议 2 核 4G 以上,确保网络互通;
- 安装相同版本 MySQL(推荐 5.7.x):版本不一致可能导致 binlog 解析错误,本文以 5.7.44 为例;
- 关闭防火墙及 SELinux:避免端口拦截或权限限制(生产环境可按需配置规则,而非直接关闭)。
2. 网络与主机配置
主服务器操作(IP:192.168.238.134)
bash
# 设置主机名(便于识别节点角色,替换为实际域名/名称)
hostnamectl set-hostname master.yourdomain.com
# 配置静态IP(编辑网卡文件,CentOS 7默认网卡为ens33,可通过ip addr查看)
vim /etc/sysconfig/network-scripts/ifcfg-ens33
# 网卡配置内容(根据实际网络环境修改):
BOOTPROTO=static # 静态IP模式(避免DHCP分配导致IP变化)
IPADDR=192.168.238.134 # 主服务器固定IP
PREFIX=24 # 子网掩码前缀(24对应255.255.255.0)
GATEWAY=192.168.238.2 # 网关地址(与路由器/交换机配置一致)
DNS1=114.114.114.114 # DNS服务器(国内常用114或阿里云DNS)
ONBOOT=yes # 开机自动激活网卡
# 重启网络服务使配置生效
systemctl restart network
从服务器操作(IP:192.168.238.133)
bash
# 设置主机名(区分主从节点)
hostnamectl set-hostname slave.yourdomain.com
# 配置静态IP(网卡名称需与主库一致)
vim /etc/sysconfig/network-scripts/ifcfg-ens33
# 网卡配置内容(网关/DNS与主库保持一致):
BOOTPROTO=static
IPADDR=192.168.238.133 # 从服务器固定IP
PREFIX=24
GATEWAY=192.168.238.2 # 与主库同一网关
DNS1=114.114.114.114
ONBOOT=yes
# 重启网络
systemctl restart network
3. 基础环境配置(两台服务器均执行)
bash
# 关闭NetworkManager(避免与network服务冲突,按需选择)
systemctl stop NetworkManager && systemctl disable NetworkManager
# 配置hosts文件(绑定IP与主机名,避免DNS解析问题)
vim /etc/hosts
# 添加内容(替换为实际IP和主机名):
192.168.238.134 master.yourdomain.com
192.168.238.133 slave.yourdomain.com
# 关闭防火墙和SELinux(临时+永久)
systemctl stop firewalld && systemctl disable firewalld # 关闭防火墙
setenforce 0 # 临时关闭SELinux
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config # 永久关闭SELinux(需重启生效)
# 时间同步(确保主从服务器时间一致,避免复制延迟判断错误)
yum install -y ntp # 安装ntp工具
ntpdate time1.aliyun.com # 同步阿里云NTP服务器时间(生产环境建议用内部NTP)
# 检查3306端口是否被占用(避免端口冲突)
# 方法1:使用netstat(需安装net-tools)
yum install -y net-tools
netstat -tulpn | grep 3306
# 方法2:使用lsof(需安装lsof)
yum install -y lsof
lsof -i :3306
# 若端口被占用,终止占用进程(替换<PID>为实际进程ID)
# kill -9 <PID>
四、安装 MySQL(两台服务器均执行)
1. 安装 MySQL 5.7
bash
# 创建安装脚本(批量执行命令,避免手动输入错误)
vim mysql_install.sh
#!/bin/bash
# 安装依赖库(MySQL运行需要libaio)
yum install libaio -y
# 下载MySQL 5.7.44安装包(官网地址,若失效可换备用链接)
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
# 备用链接(MySQL官方镜像)
# wget https://repo.mysql.com/mysql-5.7/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
# 解压并移动到/usr/local/mysql(标准安装路径)
tar -xf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
rm -rf /usr/local/mysql # 清理旧安装目录
mv mysql-5.7.44-linux-glibc2.12-x86_64 /usr/local/mysql
# 创建mysql系统用户(无登录权限,用于运行MySQL服务)
useradd -r -s /sbin/nologin mysql
# 清理旧配置并创建数据目录
rm -rf /etc/my.cnf # 删除系统默认配置文件
cd /usr/local/mysql
mkdir mysql-files # 创建MySQL文件目录(用于secure_file_priv参数)
chown mysql:mysql mysql-files # 设置目录权限
chmod 750 mysql-files
# 赋予脚本执行权限并运行
chmod +x mysql_install.sh
./mysql_install.sh
2. 初始化与配置
bash
# 初始化MySQL(生成临时密码,--user指定运行用户,--basedir指定安装目录)
cd /usr/local/mysql
bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql &> /root/password.txt
bin/mysql_ssl_rsa_setup --datadir=/usr/local/mysql/data # 生成SSL/RSA证书(用于加密连接)
# 查看初始密码(务必记录,登录MySQL需使用)
cat /root/password.txt
# 配置MySQL服务并启动
cp support-files/mysql.server /etc/init.d/mysqld # 复制服务脚本
service mysqld start # 启动服务
# 确认3306端口监听(验证MySQL是否启动成功)
netstat -tulpn | grep 3306 # 应显示mysqld进程监听3306端口
# 配置环境变量(将MySQL命令添加到系统PATH,避免每次输入绝对路径)
echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile # 使环境变量生效
# 安全配置(必做!加固MySQL安全,按提示操作)
mysql_secure_installation
# 操作步骤:输入初始密码→设置新root密码→删除匿名用户→禁止root远程登录→删除test库→刷新权限
五、主服务器配置(master)
1. 修改 my.cnf 配置(核心步骤)
bash
# 编辑MySQL配置文件(/etc/my.cnf是MySQL默认读取的配置路径)
vim /etc/my.cnf
# 配置内容如下(带详细注释):
[mysqld]
# 基础路径配置
datadir=/var/lib/mysql # 数据存储目录(需确保mysql用户有读写权限)
socket=/var/lib/mysql/mysql.sock # 服务端socket文件路径(与客户端保持一致)
basedir=/usr/local/mysql # MySQL安装根目录
pid-file=/var/run/mysqld/mysqld.pid # PID文件路径(记录服务进程ID)
port=3306 # 监听端口(默认3306)
# 网络配置
bind-address=0.0.0.0 # 允许所有IP访问(生产环境可指定从库IP)
# 主从复制核心配置
log-bin=mysql-bin # 开启二进制日志(主库必须开启,命名为mysql-bin)
server-id=10 # 主库唯一ID(建议1-100,从库需不同)
binlog_format=ROW # 日志格式(ROW模式记录行变更,最安全,适合复制)
expire_logs_days=7 # 日志自动过期时间(7天,避免日志文件占满磁盘)
character-set-server=utf8mb4 # 默认字符集(utf8mb4支持emoji等特殊字符)
collation-server=utf8mb4_unicode_ci # 字符集排序规则
log-error=/var/log/mysqld.log # 错误日志路径(便于排查问题)
symbolic-links=0 # 禁用符号链接(避免数据目录被篡改)
# 客户端配置(解决socket路径不匹配导致的连接错误)
[client]
socket=/var/lib/mysql/mysql.sock # 与服务端socket路径一致
[mysqld_safe]
log-error=/var/log/mysqld.log
socket=/var/lib/mysql/mysql.sock
bash
# 重启MySQL使配置生效(修改my.cnf后必须重启)
service mysqld restart
# 确认端口监听(验证服务是否正常启动)
netstat -tulpn | grep 3306
2. 创建复制用户
bash
# 登录MySQL(使用安全配置时设置的root密码)
mysql -uroot -p
# 若报错"Can't connect to local MySQL server through socket '/tmp/mysql.sock'",执行以下命令解决:
# ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock # 创建socket软链接
# chown mysql:mysql /tmp/mysql.sock # 设置链接权限
# 再次登录
sql
-- 创建复制用户(仅允许从库IP段访问,增强安全性,替换%为具体从库IP更佳)
CREATE USER 'repl_user'@'192.168.238.%' IDENTIFIED BY 'YourPassword123!'; # 密码需复杂,避免破解
-- 授予复制权限(仅授予REPLICATION SLAVE,最小权限原则)
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.238.%';
FLUSH PRIVILEGES; # 刷新权限使配置生效
3. 锁定表并记录日志状态
sql
-- 锁定所有表(禁止写入操作,确保数据一致性,避免备份时数据变更)
FLUSH TABLES WITH READ LOCK;
-- 查看二进制日志状态(记录File和Position值,后续从库配置需用)
SHOW MASTER STATUS;
示例输出(需记录实际值):
plaintext
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000003 | 154 | | | |
+---------------+----------+--------------+------------------+-------------------+
- File:当前正在写入的 binlog 文件名(如 binlog.000003);
- Position:binlog 的当前位置(如 154);
- 注意:锁定表后不要关闭 MySQL 终端,否则锁会释放,需保持终端打开直到数据同步完成。
六、从服务器配置(slave)
1. 修改 my.cnf 配置
bash
# 编辑配置文件
vim /etc/my.cnf
# 配置内容如下:
[mysqld]
# 基础路径配置(与主库保持一致)
datadir=/var/lib/mysql # 数据目录(需与主库同步,后续会复制主库数据)
socket=/var/lib/mysql/mysql.sock # 服务端socket路径
basedir=/usr/local/mysql # 安装根目录
pid-file=/var/run/mysqld/mysqld.pid # PID文件路径
port=3306 # 与主库端口一致
# 网络配置
bind-address=0.0.0.0 # 允许远程访问(便于管理)
# 从库核心配置
relay-log=/var/lib/mysql/relaylog # 中继日志路径(存储主库binlog副本)
relay-log-index=/var/lib/mysql/relaylog.index # 中继日志索引文件
log-bin=mysql-bin # 级联复制时开启(普通从库可选,若从库作为其他库的主库则必须开启)
server-id=100 # 从库唯一ID(必须与主库不同,建议100+)
binlog_format=ROW # 与主库保持一致
expire_logs_days=7 # 日志过期时间
read-only=1 # 从库只读(非root用户无法写入,防止误操作)
super-read-only=1 # 从库只读(包括root用户,MySQL 5.7+特性,增强安全性)
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
log-error=/var/log/mysqld.log
symbolic-links=0
# 客户端配置(解决socket路径不匹配)
[client]
socket=/var/lib/mysql/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
socket=/var/lib/mysql/mysql.sock
2. 同步主库数据(关键步骤)
主服务器操作:
bash
# 停止主库(确保数据复制时无写入操作,保持一致性)
service mysqld stop
# 删除auto.cnf(避免UUID冲突,从库启动时会自动生成新UUID)
rm -rf /var/lib/mysql/auto.cnf
# 安装rsync(用于高效同步数据,主从均需安装)
yum install -y rsync
# 同步主库数据到从库(替换从库IP和路径,-av表示归档+详细输出)
rsync -av /var/lib/mysql/ root@192.168.238.133:/var/lib/mysql/
# 启动主库(数据同步完成后恢复服务)
service mysqld start
# 确认主库端口监听
netstat -tulpn | grep 3306
从服务器操作:
bash
# 修复数据目录权限(rsync同步后权限可能异常,需设置为mysql用户)
chown -R mysql:mysql /var/lib/mysql
# 创建中继日志目录并授权(确保从库可写入中继日志)
mkdir -p /var/lib/mysql/relaylog
chown -R mysql:mysql /var/lib/mysql/relaylog
chmod 755 /var/lib/mysql/relaylog
# 创建PID目录并授权(避免启动时权限不足)
mkdir -p /var/run/mysqld
chown -R mysql:mysql /var/run/mysqld
chmod 755 /var/run/mysqld
# 启动从库
service mysqld start
# 确认从库端口监听
netstat -tulpn | grep 3306
七、配置主从同步(从服务器执行)
1. 配置主从连接
bash
# 登录从库MySQL(使用从库root密码)
mysql -uroot -p
sql
-- 配置主库信息(替换为实际值,与主库SHOW MASTER STATUS结果对应)
CHANGE MASTER TO
MASTER_HOST='192.168.238.134', # 主库IP地址
MASTER_USER='repl_user', # 主库创建的复制用户
MASTER_PASSWORD='YourPassword123!', # 复制用户密码
MASTER_PORT=3306, # 主库端口
MASTER_LOG_FILE='binlog.000003', # 主库SHOW MASTER STATUS中的File值
MASTER_LOG_POS=154; # 主库SHOW MASTER STATUS中的Position值
-- 启动从库复制进程(开始同步数据)
START SLAVE;
2. 验证同步状态(关键!)
sql
-- 查看从库状态(重点关注Slave_IO_Running和Slave_SQL_Running)
SHOW SLAVE STATUS\G
需满足以下条件(同步成功):
Slave_IO_Running: Yes:从库 IO 线程正常(成功连接主库并获取 binlog);Slave_SQL_Running: Yes:从库 SQL 线程正常(成功执行中继日志);Seconds_Behind_Master: 0:从库无延迟(实时同步)。
3. 主服务器解锁表(同步配置完成后)
回到主库 MySQL 终端,执行以下命令释放表锁,允许写入操作:
sql
UNLOCK TABLES;
八、测试主从复制
1. 主服务器操作(写入数据)
sql
-- 创建测试数据库
CREATE DATABASE test_replication;
USE test_replication;
-- 创建测试表
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入测试数据
INSERT INTO test_table (id, name) VALUES (1, '测试数据1');
INSERT INTO test_table (id, name) VALUES (2, '测试数据2');
-- 确认数据插入
SELECT * FROM test_table;
2. 从服务器验证(同步数据)
sql
-- 查看是否同步了测试数据库
SHOW DATABASES; # 应包含test_replication
-- 查看同步的数据
USE test_replication;
SELECT * FROM test_table; # 应显示主库插入的两条数据
若从库能查询到主库插入的数据,说明主从复制配置成功!
九、常见问题排查
1. 复制错误处理(从库执行)
sql
-- 停止复制进程
STOP SLAVE;
-- 重置复制配置(谨慎使用,会清除现有同步状态)
RESET SLAVE;
-- 重新配置主从连接(参考步骤七第1点)
CHANGE MASTER TO ...;
-- 重启复制进程
START SLAVE;
2. 网络和权限检查
bash
# 检查主从网络连通性(从库ping主库)
ping 192.168.238.134
# 检查主库3306端口是否可访问(从库telnet测试)
telnet 192.168.238.134 3306
# 开放防火墙端口(若未关闭防火墙)
firewall-cmd --add-port=3306/tcp --permanent
firewall-cmd --reload
# 检查复制用户权限(主库执行)
mysql -uroot -p -e "SHOW GRANTS FOR 'repl_user'@'192.168.238.133';"
3. 端口占用问题
bash
# 检查3306端口占用情况
netstat -tulpn | grep 3306
# 终止占用进程(替换<PID>为实际进程ID)
kill -9 $(lsof -t -i:3306)
# 重启MySQL
service mysqld start
4. 日志查看(排查问题的关键)
- 主库二进制日志:
/var/lib/mysql/mysql-bin.xxxxxx(通过SHOW BINLOG EVENTS IN 'binlog.000003'查看内容); - 错误日志:
/var/log/mysqld.log(包含启动失败、复制错误等关键信息); - 从库中继日志:
/var/lib/mysql/relaylog.xxxxxx(通过SHOW RELAYLOG EVENTS查看内容)。
十、总结
MySQL 主从复制的核心是主库记录 binlog→从库 IO 线程获取 binlog→SQL 线程执行 binlog,搭建过程需注意以下关键点:
- 主从服务器
server-id必须唯一,主库需开启log-bin; - 复制用户需授予最小权限(
REPLICATION SLAVE),并限制访问 IP; - 数据同步时需锁定主库表,确保一致性;
- 验证同步状态时重点关注
Slave_IO_Running和Slave_SQL_Running是否均为Yes。
通过本文的步骤,你可以快速搭建一套稳定的 MySQL 主从复制环境,实现读写分离和数据备份。生产环境中还可结合keepalived实现主从自动切换,进一步提升系统可用性。
3129

被折叠的 条评论
为什么被折叠?



