1. 为什么需要ProxySQL + MySQL MGR实现读写分离?
在分布式数据库架构中,读写分离是提升系统吞吐量的经典方案。传统的MySQL主从复制虽然能实现基础分离,但存在三个致命缺陷:
- 应用层需要硬编码读写路由逻辑,任何拓扑变更都需修改代码
- 从库故障时缺乏自动剔除机制,可能导致查询雪崩
- 多从库场景下缺乏负载均衡策略
ProxySQL作为高性能中间件,配合MySQL Group Replication(MGR)的强一致性特性,能完美解决这些问题。我在金融级系统中实测发现,该组合可使查询吞吐量提升3-5倍,同时将主库CPU负载降低60%以上。
关键优势对比:
方案 自动故障转移 读写分离 负载均衡 配置复杂度 原生主从 ❌ 手动实现 ❌ 高 MGR直连 ✅ ❌ ❌ 中 ProxySQL+MGR ✅ ✅ ✅ 低
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与组件部署
2.1 硬件配置建议
生产环境推荐以下最小规格:
- ProxySQL节点:2核4GB内存(每个查询约消耗3-5MB内存)
- MySQL MGR节点:4核8GB内存起步(InnoDB缓冲池建议4GB+)
- 网络延迟:节点间<1ms(MGR对网络抖动敏感)
2.2 MySQL MGR集群搭建
bash复制# 每个节点的my.cnf关键配置
[mysqld]
server_id = 1 # 各节点不同
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = NONE
log_slave_updates = ON
log_bin = binlog
binlog_format = ROW
master_info_repository = TABLE
relay_log_info_repository = TABLE
plugin_load_add = 'group_replication.so'
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "node1:33061"
loose-group_replication_group_seeds = "node1:33061,node2:33061,node3:33061"
loose-group_replication_bootstrap_group = OFF
loose-group_replication_single_primary_mode = ON
loose-group_replication_enforce_update_everywhere_checks = OFF
初始化集群时需特别注意:
- 所有节点先设置
group_replication_bootstrap_group=ON启动第一个节点 - 执行
START GROUP_REPLICATION后立即改回OFF - 其他节点加入时确保
server_uuid不重复
3. ProxySQL核心配置详解
3.1 基础服务配置
sql复制-- 登录ProxySQL管理接口
mysql -u admin -padmin -h 127.0.0.1 -P 6032
-- 添加MGR节点
INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES
(10,'mgr-node1',3306),
(10,'mgr-node2',3306),
(10,'mgr-node3',3306),
(20,'mgr-node1',3306); -- hostgroup 20用于写节点
-- 设置监控账号
UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
UPDATE global_variables SET variable_value='monitor_password' WHERE variable_name='mysql-monitor_password';
-- 配置读写分离规则
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,destination_hostgroup,apply) VALUES
(1,1,'^SELECT.*FOR UPDATE',20,1), -- 写操作路由到主库
(2,1,'^SELECT',10,1), -- 读操作路由到从库
(3,1,'^INSERT',20,1),
(4,1,'^UPDATE',20,1),
(5,1,'^DELETE',20,1);
-- 启用配置
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
3.2 高级流量控制策略
实际生产环境中,我们需要更精细的控制:
sql复制-- 按用户分片(例如报表用户走特定从库)
INSERT INTO mysql_users(username,password,default_hostgroup) VALUES
('report_user','secure_pass',15),
('app_user','app_pass',10);
-- 按模式分片(分库分表场景)
INSERT INTO mysql_query_rules (rule_id,active,schemaname,match_pattern,destination_hostgroup) VALUES
(10,1,'user_db','^SELECT',11),
(11,1,'order_db','^SELECT',12);
-- 读写分离例外处理(某些SELECT需要强一致性)
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,destination_hostgroup,attributes) VALUES
(20,1,'^SELECT.*FROM account_balance',20,'{"comment":"critical read"}');
4. 故障转移与一致性保障
4.1 MGR状态监控集成
ProxySQL通过定期检查group_replication_member_status表实现自动拓扑发现:
sql复制-- 配置MGR监控
UPDATE mysql_group_replication_hostgroups SET
writer_hostgroup=20,
backup_writer_hostgroup=25,
reader_hostgroup=10,
offline_hostgroup=9999,
active=1,
max_writers=1,
writer_is_also_reader=0;
典型故障场景处理流程:
- 主节点宕机 → MGR自动选举新主
- ProxySQL 10秒内检测到变化(通过
monitor_group_replication_healthcheck_interval调整) - 写流量自动切换到新主(hostgroup 20)
- 旧主恢复后自动加入读池(hostgroup 10)
4.2 读写分离一致性方案
对于需要读己之写的场景,推荐两种解决方案:
方案A:会话级粘滞路由
sql复制-- 在事务内临时强制读主
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,destination_hostgroup,apply,comment) VALUES
(30,1,'^SELECT',20,1,'force master read')
WHERE transaction_active=1;
方案B:GTID动态跟踪
bash复制# 在ProxySQL配置文件中启用
mysql-track_gtid = true
mysql-hostgroup_manager_verbose = 1
5. 性能调优实战经验
5.1 连接池优化参数
sql复制-- 调整全局连接设置(根据实际并发量调整)
UPDATE global_variables SET variable_value='3000' WHERE variable_name='mysql-max_connections';
UPDATE global_variables SET variable_value='true' WHERE variable_name='mysql-use_tcp_keepalive';
-- 每个后端连接池配置
UPDATE mysql_servers SET max_connections=200 WHERE hostgroup_id=10;
UPDATE mysql_servers SET max_connections=100 WHERE hostgroup_id=20;
5.2 查询缓存与重写
sql复制-- 启用查询缓存(适合报表类SQL)
UPDATE mysql_query_rules SET cache_ttl=60000 WHERE rule_id=2;
-- SQL重写示例:将SELECT * 优化为具体字段
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,replace_pattern,destination_hostgroup) VALUES
(40,1,'^SELECT \* FROM products','SELECT id,name,price FROM products',10);
-- 阻止危险操作
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,error_msg,apply) VALUES
(50,1,'^DROP TABLE','Table drops are disabled',1);
6. 生产环境踩坑记录
坑1:MGR节点状态误判
现象:ProxySQL偶尔将健康节点标记为OFFLINE
根因:默认1秒检测间隔在网络抖动时可能误判
解决:调整参数并添加重试机制
sql复制UPDATE global_variables SET variable_value='3000'
WHERE variable_name='mysql-monitor_group_replication_healthcheck_interval';
坑2:长事务导致写节点切换失败
现象:新主选举后旧主仍有活跃事务
解决:配置事务超时
sql复制-- 在MySQL端设置
SET GLOBAL group_replication_transaction_size_limit=1000000;
SET GLOBAL group_replication_flow_control_mode="DISABLED";
坑3:ProxySQL内存泄漏
版本:2.0.x系列存在内存管理问题
解决方案:升级到2.4.4+并限制最大内存
bash复制# 启动时添加限制
proxysql -c /etc/proxysql.cnf -M 4096M
7. 监控与告警配置
推荐监控指标体系:
| 指标类别 | 关键指标 | 预警阈值 |
|---|---|---|
| 连接池 | ConnUsed/ConnFree | >80%利用率 |
| 查询性能 | Query_ResponseTime_95th | >500ms |
| 节点健康 | MGR_member_state | != ONLINE |
| 流量分布 | Hostgroup_Requests | 写比例>30%持续5分钟 |
Prometheus监控示例配置:
yaml复制scrape_configs:
- job_name: 'proxysql'
static_configs:
- targets: ['proxysql:6032']
metrics_path: '/metrics'
params:
module: [ 'proxysql_stats' ]
Grafana面板应重点关注:
- 查询延迟热力图
- 主机组流量对比
- 连接池水位线
- MGR成员状态变化时序
8. 典型架构演进路径
根据业务规模推荐不同架构:
阶段1:基础高可用(<1000 QPS)
code复制Client → ProxySQL → MySQL MGR(3节点)
阶段2:读写分离扩展(1000-5000 QPS)
code复制Client → LVS → [ProxySQL×2] → MySQL MGR(1主+2从)
阶段3:水平分库(>5000 QPS)
code复制Client → ShardingSphere → [ProxySQL集群] → [MGR分片1][MGR分片2][MGR分片N]
在金融级系统中,我们最终采用了双ProxySQL集群+多MGR分片的架构,每个ProxySQL实例处理约3000 QPS,通过Keepalived实现VIP漂移,全年可用性达到99.99%。
