应用层读写分离不可靠,因重启、网络抖动等会导致SELECT误落主库;ProxySQL通过连接建立时钉死路由、实时感知节点状态并自动摘除故障从库来保障分流准确性。

为什么直接在应用层做读写分离不靠谱
因为一旦应用重启、连接池重建,或者中间网络抖动,SELECT 请求就可能落到主库——你根本没法靠代码逻辑 100% 保证「只读走从」。ProxySQL 的核心价值不是“多一层转发”,而是它能在连接建立时就按规则把流量钉死到后端节点,并且实时感知 mysql_servers 状态变化,自动摘除不可用从库。
mysql_replication_hostgroups 表必须手动维护
ProxySQL 不会自动识别 MySQL 的主从关系,它只认你配的 hostgroup_id 和 role 字段。常见错误是只改了 MySQL 的复制拓扑,却忘了在 ProxySQL 里执行:
INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment) VALUES (10, 20, 'prod'); LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;
注意:writer_hostgroup 和 reader_hostgroup 是整数 ID,不是字符串名;comment 字段只是备注,不影响逻辑;这条语句只生效一次,后续增减从库仍需手动调 mysql_servers 表。
路由规则里 destination_hostgroup 写错 ID 就全走主库
很多人配完 hostgroup 后,在 mysql_query_rules 里写:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) VALUES (1, 1, '^SELECT', 20, 1);
但实际查 SELECT * FROM mysql_servers WHERE hostgroup_id = 20 发现为空——说明从库根本没加进 hostgroup 20。容易踩的坑包括:
-
mysql_servers.hostgroup_id必须和mysql_replication_hostgroups.reader_hostgroup完全一致 - 从库的
status字段要是ONLINE,不是SHUNNED或OFFLINE_SOFT -
match_digest匹配的是归一化后的 SQL,^SELECT能匹配SELECT /*+ USE_INDEX(t1) */ id FROM t1,但不匹配select(大小写敏感)
监控 stats_mysql_connection_pool 比看日志更准
别依赖 tail -f /var/lib/proxysql/proxysql.log 判断读写是否分流成功。真正反映实际流向的是:
SELECT hostgroup, srv_host, status, ConnUsed, ConnFree, Queries FROM stats_mysql_connection_pool;
重点关注三列:ConnUsed 是否有从库连接被复用、Queries 数量是否随 SELECT 增长、status 是否为 ONLINE。如果某从库 ConnUsed = 0 且 Queries = 0,大概率是 weight 设为 0,或被自动 shunned 了——这时候得查 monitor 模块日志,而不是重 reload 规则。
复杂点在于:ProxySQL 的健康检查默认每 3000ms 执行一次 SELECT @@read_only,但如果你的从库开启了 super_read_only=ON,这个检查会失败并触发 shun。得在 mysql_servers 表里显式设 max_replication_lag = 0 或调大 check_interval_ms,否则半夜主从延迟抖动,整个读流量就切回主库了。

















