基于 CentOS 7 + MySQL 5.7,MySQL将配置主从复制集群,ProxySQL实现 SQL 语句执行的读写分离,请求的负载均衡
一、环境说明与架构图
1. 服务器角色与 IP 规划
| 角色 | IP 地址 | 系统版本 | 软件版本 | 备注 |
|---|---|---|---|---|
| 主库(Master) | 192.168.1.10 | CentOS 7 | MySQL 5.7 | 处理写请求,同步数据到从库 |
| 从库 1(Slave1) | 192.168.1.11 | CentOS 7 | MySQL 5.7 | 处理读请求,同步主库数据 |
| 从库 2(Slave2) | 192.168.1.12 | CentOS 7 | MySQL 5.7 | 处理读请求,同步主库数据 |
| ProxySQL | 192.168.1.13 | CentOS 7 | ProxySQL 2.5.5 | 读写分离中间件,分发请求 |
2. 架构图
bash
应用程序 → ProxySQL(192.168.1.13:6033)
├→ 主库(192.168.1.10:3306)【写请求:INSERT/UPDATE/DELETE】
├→ 从库1(192.168.1.11:3306)【读请求:SELECT,负载均衡】
└→ 从库2(192.168.1.12:3306)【读请求:SELECT,负载均衡】
二、环境准备
1. 关闭防火墙与 SELinux
bash
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 临时关闭SELinux
setenforce 0
# 永久关闭SELinux,重启生效
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
2. 安装 MySQL 5.7
bash
# 安装MySQL官方仓库
rpm -Uvh https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
# 安装MySQL 5.7
yum install -y mysql-community-server
# 启动MySQL并设置开机自启
systemctl start mysqld
systemctl enable mysqld
# 获取初始密码(MySQL 5.7默认生成随机密码)
grep 'temporary password' /var/log/mysqld.log
# 示例输出:A temporary password is generated for root@localhost: xxxxxxxx
# 登录MySQL并修改root密码(需符合复杂度:大小写+数字+符号)
mysql -u root -p
# 输入初始密码后执行以下SQL
ALTER USER 'root'@'localhost' IDENTIFIED BY 'Root@123456';
FLUSH PRIVILEGES;
三、MySQL 主从复制配置
1. 主库配置
- 修改 MySQL 配置文件
bash
vim /etc/my.cnf
添加以下内容:
-----------------------------------------------------------------------------
[mysqld]
server-id = 10 # 主库唯一ID
log_bin = /var/lib/mysql/mysql-bin # 开启binlog
binlog_format = ROW # 行级复制,避免SQL模式差异导致同步失败
expire_logs_days = 7 # binlog保留7天,避免磁盘占满
sync_binlog = 1 # 每次事务提交同步binlog到磁盘(可选,增强安全性)
-----------------------------------------------------------------------------
重启 MySQL 使配置生效:
systemctl restart mysqld
- 创建主从复制用户
登录主库 MySQL:
bash
mysql -u root -pRoot@123456
允许从库 IP 连接,需要创建复制用户
bash
CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'Repl@123456'; # 从库IP前缀匹配
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';
FLUSH PRIVILEGES;
- 查看主库 binlog 状态
sql
FLUSH TABLES WITH READ LOCK; # 锁表,防止配置期间数据写入
SHOW MASTER STATUS;
记录输出结果,后续从库配置需要
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
解锁表:
UNLOCK TABLES;
2. 从库配置
- 修改 MySQL 配置文件
bash
vim /etc/my.cnf
添加以下内容:
-----------------------------------------------------------------------------
[mysqld]
server-id = 11 # 从库1用11,从库2用12
relay_log = /var/lib/mysql/relay-bin # 中继日志:同步主库binlog用
log_bin = /var/lib/mysql/mysql-bin # 若需级联复制:从库再作为主库 则开启,否则可选
read_only = ON # 从库设置为只读,root用户不受限,避免误写
-----------------------------------------------------------------------------
重启 MySQL:
systemctl restart mysqld
- 配置从库连接主库
登录从库 MySQL
bash
mysql -u root -pRoot@123456
配置主库信息,替换为实际主库 IP、binlog 文件和位置
sql
CHANGE MASTER TO
MASTER_HOST = '192.168.1.10',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'Repl@123456',
MASTER_LOG_FILE = 'mysql-bin.000001', # 主库SHOW MASTER STATUS的File值
MASTER_LOG_POS = 154; # 主库SHOW MASTER STATUS的Position值
启动从库复制进程:
sql
START SLAVE;
- 验证主从同步状态
sql
SHOW SLAVE STATUS\G
关键参数需满足:
Slave_IO_Running: Yes(IO 线程正常)
Slave_SQL_Running: Yes(SQL 线程正常)
Seconds_Behind_Master: 0(无延迟,或数值较小)
四、ProxySQL 部署与配置
1. 安装 ProxySQL
bash
# 添加ProxySQL仓库
cat > /etc/yum.repos.d/proxysql.repo << EOF
[proxysql_repo]
name=ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.5.x/centos/7
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key
EOF
# 安装ProxySQL
yum install -y proxysql
# 启动并设置开机自启
systemctl start proxysql
systemctl enable proxysql
ProxySQL 默认端口:
管理接口:6032 --- 用于配置 ProxySQL
数据库接口:6033 --- 应用连接的端口,模拟 MySQL
2. 配置 ProxySQL
- 登录 ProxySQL 管理界面
默认账号密码:admin/admin,建议后期修改
bash
mysql -u admin -padmin -h 127.0.0.1 -P 6032
- 添加 MySQL 集群服务器
ProxySQL 通过 "主机组" 区分读写节点,通常:
主机组 10:写组(主库)
主机组 20:读组(从库)
执行以下 SQL 添加主库和从库:
sql
# 添加主库到写组(10)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (10, '192.168.1.10', 3306, 1);
# 添加从库1到读组(20)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (20, '192.168.1.11', 3306, 1); # weight=1表示权重,值越高分配请求越多
# 添加从库2到读组(20)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (20, '192.168.1.12', 3306, 2); # 从库2性能更好,权重设为2
- 配置读写分离规则
通过
mysql_query_rules定义 SQL 路由规则:
sql
# 所有SELECT语句(除SELECT ... FOR UPDATE)路由到读组(20)
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (1, 1, '^SELECT .*FOR UPDATE$', 10, 0); # SELECT FOR UPDATE强制走写组,因为会加锁
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (2, 1, '^SELECT', 20, 1); # 普通SELECT走读组
# 其他语句(INSERT/UPDATE/DELETE)路由到写组(10)
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (3, 1, '.', 10, 1);
- 添加应用访问用户
假设后端应用通过
app_user用户连接数据库,则需要在 ProxySQL 中配置该用户,并映射到后端 MySQL 的实际用户:
sql
# 在ProxySQL中添加用户,用户名/密码需与后端MySQL集群的一致
INSERT INTO mysql_users (username, password, default_hostgroup)
VALUES ('app_user', 'App@123456', 10); # 防止无规则匹配,default_hostgroup默认走写组
# 授权用户访问所有数据库
UPDATE mysql_users SET default_schema='test' WHERE username='app_user';
注意 :需在主库创建
app_user用户,从库会自动同步:
sql
-- 在主库执行
CREATE USER 'app_user'@'%' IDENTIFIED BY 'App@123456';
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%';
FLUSH PRIVILEGES;
- 加载配置并保存
登录控制台6032,保存配置
ProxySQL 配置需加载到运行时(runtime)并保存到磁盘(disk),否则重启后失效:
sql
# 加载mysql_servers和mysql_users到runtime
LOAD MYSQL SERVERS TO RUNTIME;
LOAD MYSQL USERS TO RUNTIME;
# 加载mysql_query_rules到runtime
LOAD MYSQL QUERY RULES TO RUNTIME;
# 保存配置到磁盘
SAVE MYSQL SERVERS TO DISK;
SAVE MYSQL USERS TO DISK;
SAVE MYSQL QUERY RULES TO DISK;
3. 配置健康检查
ProxySQL 默认会检测后端节点状态,可通过以下参数调整,在管理接口执行
sql
# 检测间隔(毫秒)
UPDATE global_variables SET variable_value=1000 WHERE variable_name='mysql_monitor_ping_interval';
# 连接超时(毫秒)
UPDATE global_variables SET variable_value=2000 WHERE variable_name='mysql_monitor_connect_timeout';
# 检测失败阈值,超过则标记节点不可用
UPDATE global_variables SET variable_value=3 WHERE variable_name='mysql_monitor_ping_max_failures';
# 加载并保存配置
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
五、功能验证
1. 验证主从复制
在主库创建测试库和表,并插入数据:
sql
-- 主库执行
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
CREATE TABLE t_user (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20));
INSERT INTO t_user (name) VALUES ('test1'), ('test2');
在从库 1 和从库 2 验证数据是否同步
sql
-- 从库执行
USE test_db;
SELECT * FROM t_user; # 应看到两条数据,说明同步成功
2. 验证读写分离
使用应用用户,通过 ProxySQL 连接数据库
sql
mysql -u app_user -pApp@123456 -h 192.168.1.13 -P 6033
- 主库写入
在 ProxySQL 连接中执行插入操作
sql
USE test_db;
INSERT INTO t_user (name) VALUES ('proxy_write_test');
到主库查看是否有数据,从库是否同步,确认写操作在主库执行
- 从库读取
在 ProxySQL 连接中执行查询
sql
SELECT * FROM t_user;
在从库 1 和从库 2 执行以下命令,查看当前连接,确认读请求在从库
sql
SHOW PROCESSLIST; # 应看到来自ProxySQL(192.168.1.13)的查询连接
3. 验证读库负载均衡
多次执行查询
sql
SELECT * FROM t_user;
在从库 1 和从库 2 查看
SHOW PROCESSLIST的连接次数,应符合权重比例 从库 1: 从库 2 ≈ 1:2,说明轮询 + 加权策略生效。
六、常见问题排查
1.主从同步失败
-
检查从库
SHOW SLAVE STATUS\G中Last_IO_Error或Last_SQL_Error,通常是网络不通、复制用户密码错误或 binlog 位置错误。 -
解决:重新执行
CHANGE MASTER TO修正主库信息,或用STOP SLAVE; RESET SLAVE ALL;重置后重新配置。
2.ProxySQL 无法连接后端 MySQL
-
检查后端 MySQL 是否允许 ProxySQL IP(192.168.1.13)连接,用户权限是否包含
%或具体 IP -
检查 ProxySQL 中
mysql_users的密码是否与后端一致
3.读写分离规则不生效
-
在 ProxySQL 管理接口执行
SELECT * FROM mysql_query_rules;确认规则active=1。 -
执行
SELECT * FROM stats_mysql_query_digest;查看 SQL 是否匹配到正确规则。
七、总结
通过以上步骤,已实现:
-
MySQL 主从复制,即 主库写入,从库同步;
-
ProxySQL 读写分离,即 写请求走主库,读请求走从库;
-
读库负载均衡,即 按权重分发读请求到多个从库。
后续可根据业务需求扩展从库数量,或通过 ProxySQL 配置高可用,比如 双机热备。