读写分离是解决MySQL单机性能瓶颈的重要方案。当业务读多写少时,把写操作保留在主库,读操作分发到一或多个从库,可以显著减轻主库压力。直接在应用层配置多个数据源虽然可行,但难以统一处理从库延迟、故障转移和连接管理。ProxySQL以中间件形态驻留在应用与MySQL之间,通过灵活的规则引擎实现细粒度SQL路由,是生产环境常用的选择。

ProxySQL核心工作原理与架构定位
ProxySQL本身是用C++编写的反向代理,它在TCP层与MySQL协议层之间工作,对客户端表现为一个普通MySQL服务器,对后端MySQL节点则是连接池客户端。它维护两组连接:一是客户端到ProxySQL的前端连接,二是ProxySQL到后端MySQL的后端连接。前端连接与后端连接解耦,使得少量前端长连接可以复用大量后端短连接,从而降低MySQL的握手与线程创建开销。
在读写分离场景中,ProxySQL依赖mysql_servers表定义后端节点,用mysql_replication_hostgroups表关联写组与读组,再通过mysql_query_rules表匹配SQL指纹决定路由目标。例如,可以设定所有以SELECT开头且不属于特定事务的查询进入读组,其余进入写组。由于规则在内存中匹配,且支持正则与摘要(digest)方式,性能损耗通常低于毫秒级。
值得注意的是,ProxySQL不会自动保证从库数据绝对新。若业务要求刚写入后立即读取,需要在规则中将该类查询强制走主库,或利用mysql_query_rules中的transaction_persistent属性,让同一事务内的所有语句保持同一路由,避免跨节点一致性问题。
环境准备与后端MySQL主从配置
开始配置前,需准备好一台独立服务器或容器运行ProxySQL,版本建议不低于2.4。后端应已部署MySQL主从复制,主库开启binlog且从库Slave_IO_Running与Slave_SQL_Running均为Yes。ProxySQL通过单独账号连接后端,因此要在MySQL中创建监控账号与业务账号,并授予相应权限。
以下是在主库创建ProxySQL所需账号的示例。监控账号用于检测节点存活与复制状态,业务账号供应用通过ProxySQL访问数据。请替换其中的密码为强密码,并在从库也执行相同账号创建,因为从库可能被提升为主库。
-- 在主库执行 CREATE USER 'proxysql_mon'@'192.168.0.%' IDENTIFIED BY 'MonPass_2023'; GRANT REPLICATION CLIENT, PROCESS ON *.* TO 'proxysql_mon'@'192.168.0.%'; CREATE USER 'app_user'@'192.168.0.%' IDENTIFIED BY 'AppPass_2023'; GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'app_user'@'192.168.0.%'; -- 在从库执行相同语句,确保故障切换后账号可用
网络层面要保证ProxySQL所在主机能访问主从库的3306端口,且应用服务器只能连接ProxySQL的6033端口(默认SQL流量端口),不能直接连后端MySQL。这样ProxySQL才能完全掌控路由逻辑。若使用防火墙,需明确放行相关IP与端口,避免半连接导致连接池耗尽。
ProxySQL读写分离规则配置流程
ProxySQL的配置分为内存层与磁盘层,修改后需执行LOAD ... TO RUNTIME使其生效,再用SAVE ... TO DISK持久化。首先通过管理端口6032登录,将主库加入写组(如组10),从库加入读组(如组20)。随后在mysql_replication_hostgroups中声明写组与读组的映射关系,ProxySQL会基于复制状态自动管理组内节点角色。
下面是一段典型的配置序列,展示如何添加节点与设定组映射。注意hostgroup_id可自定义,但写组与读组必须成对出现,且writer_hostgroup指向写组。
INSERT INTO mysql_servers(hostgroup_id, hostname, port, weight)
VALUES (10, '192.168.0.10', 3306, 100),
(20, '192.168.0.11', 3306, 100),
(20, '192.168.0.12', 3306, 100);
INSERT INTO mysql_replication_hostgroups(writer_hostgroup, reader_hostgroup, comment)
VALUES (10, 20, 'master-slave split');
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
路由规则是读写分离的核心。一般做法是让所有非事务内的SELECT进入读组,而写操作与带锁查询进入写组。以下规则先匹配写类语句到组10,再匹配SELECT到组20,并设定apply=1终止后续匹配。还可利用digest缓存某类查询的固定路由,减少正则开销。
INSERT INTO mysql_query_rules(rule_id, active, match_digest, destination_hostgroup, apply)
VALUES (1, 1, '^SELECT.*FOR UPDATE', 10, 1),
(2, 1, '^SELECT', 20, 1),
(3, 1, '^(INSERT|UPDATE|DELETE|REPLACE)', 10, 1);
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
配置完成后,从应用使用app_user连接ProxySQL的6033端口执行混合SQL,再通过stats_mysql_query_digest表观察各规则命中次数与路由组分布。若发现某报表查询因从库延迟而读到旧数据,可单独为其编写规则强制走组10,或调整max_replication_lag让延迟过大从库暂时退出读组。经过压测与观察,读写分离层即可稳定承载生产流量。
MySQLProxySQLread_write_splitting修改时间:2026-08-13 23:51:29