ProxySQL实现MySQL主从集群的读写分离

基于 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\GLast_IO_ErrorLast_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 是否匹配到正确规则。

七、总结

通过以上步骤,已实现:

  1. MySQL 主从复制,即 主库写入,从库同步;

  2. ProxySQL 读写分离,即 写请求走主库,读请求走从库;

  3. 读库负载均衡,即 按权重分发读请求到多个从库。

后续可根据业务需求扩展从库数量,或通过 ProxySQL 配置高可用,比如 双机热备。

相关推荐
handler019 小时前
【MySQL】教你库与表的增删查改操作(基础)
运维·数据库·笔记·sql·mysql·数据·分析
姚不倒10 小时前
从零实现一个基于 Ollama + Go + MySQL 的 Text-to-SQL 智能体(M1 实战)
sql·mysql·云原生·golang
染指111010 小时前
9.LangChain框架(实现RAG)
数据库·人工智能·算法·机器学习·ai·大模型
2401_8734794010 小时前
主流IP离线库(IP数据云、纯真、IPIP.NET)怎么选?全面对比分析
服务器·网络·数据库
毋语天10 小时前
Redis 零基础实战指南:从核心原理到生产落地的完整路线
数据库·redis·缓存
weixin_4083180411 小时前
教育行业直播系统搭建指南
java·大数据·数据库
yuyuyui11 小时前
Mysql事物的持久性及原子性
mysql·.net core
それども12 小时前
redis scan和keys对比
数据库·redis·缓存
basketball61612 小时前
SQL 基础面试考点总结
数据库·sql·面试