ProxySQL读写分离需手动配置mysql_query_rules表:首条规则用(?i)^s*select匹配大小写及空白变体并路由至读组20,次条规则将SELECT FOR UPDATE等写操作优先路由至写组10,规则按rule_id升序匹配且active=1、apply=1后执行LOAD+SAVE生效。

ProxySQL 的 mysql_query_rules 路由规则怎么写才不踩坑
直接用 ^SELECT 匹配读请求看似简单,但实际会漏掉带注释、换行或空格的 SELECT,比如 /* comment */ SELECT ... 或 select(小写)也会被忽略。更稳妥的做法是用正则忽略大小写并覆盖常见变体:
-
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply) VALUES (1, 1, '(?i)^\s*select\b', 20, 1);——(?i)启用忽略大小写,\s*匹配开头空白,\b防止匹配到SELECTED这类单词 - 必须加
^SELECT.*FOR UPDATE规则(优先级高于普通SELECT),否则事务中带锁查询会被错误路由到从库,引发ERROR 1785: Statement violates GTID consistency或数据不一致 - 规则顺序很重要:
mysql_query_rules按rule_id升序匹配,所以写操作规则(如FOR UPDATE、INSERT、UPDATE)必须排在读规则前面,否则会被提前拦截
从库节点间负载均衡用什么策略最稳
轮询(roundrobin)在从库硬件配置一致时可用,但现实中从库延迟、CPU 使用率、网络 RTT 差异很大。ProxySQL 默认的 least_connections 策略只看连接数,不能反映真实负载。推荐启用监控指标驱动的动态权重:
- 在
mysql_servers表中为每个从库设置初始权重,例如weight=1000 - 通过
mysql_server_connect_timeout_ms和mysql_server_read_only等状态字段,配合定期执行SELECT * FROM monitor.mysql_server_ping_log判断节点健康度 - 对延迟超过阈值(如
Seconds_Behind_Master > 300)的从库,用UPDATE mysql_servers SET weight=0 WHERE hostname='slave2'临时下线,避免查询发到严重延迟节点
主从延迟导致读不到最新数据怎么办
这不是负载均衡能解决的问题,而是读写分离架构固有的权衡。强制所有读走主库会失去读扩展价值,完全放任又可能出错。关键是在业务层做分级处理:
- 普通列表页、搜索结果等对实时性不敏感的场景,直连从库即可
- 用户刚提交订单后立刻查“我的订单”,这类强一致性读必须走主库——可在应用侧加
@ReadOnly(false)注解或透传/*+ MAX_EXECUTION_TIME(1000) */提示中间件升权路由 - ProxySQL 支持基于 GTID 的一致性读:开启
mysql-gtid-mode=ON后,在会话中执行SET gtid_consistency=ON,再发SELECT,中间件可识别并自动路由到已同步该 GTID 的从库(需从库开启gtid_mode=ON)
为什么 ProxySQL 比 HAProxy 更适合 MySQL 读写分离
HAProxy 是四层 TCP 代理,只能按连接分发,无法识别 SQL 类型;而 ProxySQL 是七层数据库代理,能真正解析协议。这意味着:
- HAProxy 的
backend配置只能把全部流量打到某组从库,做不到“同一个事务里先UPDATE再SELECT FOR UPDATE全部走主库” - ProxySQL 可缓存
SELECT结果(启用mysql-query-cache),对高频低更新的配置类查询有明显收益;HAProxy 完全无此能力 - ProxySQL 的
mysql_users表支持 per-user 默认 hostgroup,不同业务模块可绑定不同主从组,HAProxy 只能靠端口或 IP 做粗粒度隔离
真实线上环境里,最容易被忽略的是从库的 read_only=ON 是否真正生效——有些运维会在从库上手动执行 SET GLOBAL read_only=OFF 调试,重启后失效,但若没检查 SHOW VARIABLES LIKE 'read_only',写入就会悄悄发生,后续复制直接中断。每次上线前,务必跑一遍 SELECT @@read_only 校验所有从库。


















