当前位置: 首页 > news >正文

ProxySQL选型实战:从手写读写分离到中间件的踩坑全记录

📌关键词:ProxySQL、数据库中间件、读写分离、MyCAT、ShardingSphere、主从复制、查询路由、高可用


👋 大家好,我是数据库小学妹!

我们前面学完主从复制、读写分离,感觉动态数据源、AOP 注解、强制读主,这条路终于走通了。后面发现在Spring 配了两套数据源,事务里还要手动处理,加个从库就得改代码重新发版。连接池管理、故障切换这些更麻烦的事,我压根没考虑到。

最近我就把市面上主流的数据库中间件翻了个遍,最后选了 ProxySQL。今天把选型和踩坑的过程捋一遍,省得你再走我的弯路。


一、手写读写分离的痛点

初学读写分离时,手写代码确实轻量好用。但系统跑起来之后,问题一个个冒出来:

痛点手写代码中间件
新增从库改代码、发版、重启改配置,秒级生效
从库故障代码判断连接失败再切主库自动摘除故障节点
连接池每个数据源单独配统一管控
多语言Java 写一套,Python 再写一套任何语言连过来都行
负载均衡自己实现轮询/权重内置支持

说白了,中间件就是在应用和数据库之间加一层代理,脏活累活它全包了。


二、选型:为什么是 ProxySQL?

市面上做读写分离的中间件我重点看了三个:ProxySQL、MyCAT、ShardingSphere。

维度ProxySQLMyCATShardingSphere
定位轻量级 MySQL 代理分布式数据库中间件生态最全的数据库中间件
部署复杂度低,单进程中,依赖 ZooKeeper高,概念多、配置复杂
读写分离原生支持,规则灵活支持支持
分库分表不支持支持强项
故障自动切换内置健康检查需额外部署需配合其他组件
配置方式SQL 语句配置XML 配置YAML/Java API
性能损耗很低(C++ 开发)中等中等
学习曲线平缓中等陡峭
适合场景纯读写分离分库分表分库分表 + 企业级需求

我当时只需要读写分离,没有分库分表的需求。MyCAT 和 ShardingSphere 功能太重,为了一个读写分离引入一套复杂架构,成本和收益不成正比。ProxySQL 轻量、专注、性能好,够用就行。

当然,如果你已经在用 ShardingSphere 做分库分表,直接用它做读写分离也顺理成章。选型没有绝对对错,看现状。


三、ProxySQL 核心概念

动手之前,先搞清楚几个核心概念,不然配置的时候会一脸懵。

3.1 三层配置体系

ProxySQL 的配置分三层,这是最容易搞混的地方:

┌─────────────┐ │ RUNTIME │ ← 正在生效的配置(内存中,最快) ├─────────────┤ │ MEMORY │ ← 你正在编辑的配置(还没生效) ├─────────────┤ │ DISK │ ← 持久化到 SQLite 的配置(重启不丢) └─────────────┘

操作逻辑:改 MEMORY → LOAD 到 RUNTIME → SAVE 到 DISK

刚开始我老是忘了 SAVE,重启 ProxySQL 后配置全没了,又得重新配一遍 😭

3.2 几个关键表

ProxySQL 的配置存在表里,不是配置文件,这点和传统中间件很不一样:

表名作用
mysql_servers后端 MySQL 实例(主库、从库都在这登记)
mysql_users应用连接 ProxySQL 用的账号
mysql_query_rules核心:定义读写分离规则
mysql_replication_hostgroups主从组别管理(自动故障切换用)

四、实战:从零搭起来

4.1 Docker 启动

dockerrun-d\--nameproxysql\-p6033:6033\-p6032:6032\proxysql/proxysql:2.5# 6033 是应用连接端口,6032 是管理端口

连接管理端口,开始配置:

mysql-uadmin-padmin-h127.0.0.1-P6032--prompt='ProxySQL> '

4.2 添加后端 MySQL 实例

-- 添加主库(写节点)INSERTINTOmysql_servers(hostgroup_id,hostname,port,weight,comment)VALUES(10,'mysql-master',3306,1000,'主库-写');-- 添加从库(读节点)INSERTINTOmysql_servers(hostgroup_id,hostname,port,weight,comment)VALUES(20,'mysql-slave1',3306,500,'从库1-读');INSERTINTOmysql_servers(hostgroup_id,hostname,port,weight,comment)VALUES(20,'mysql-slave2',3306,500,'从库2-读');-- 加载到 RUNTIME 并持久化LOADMYSQL SERVERSTORUNTIME;SAVEMYSQL SERVERSTODISK;

hostgroup_id是分组用的:10 是写组,20 是读组。权重weight决定流量分配比例,两个从库都是 500,流量就是对半分。

4.3 配置应用账号

-- 添加应用连接账号(应用用这个连 ProxySQL)INSERTINTOmysql_users(username,password,default_hostgroup)VALUES('app_user','app_pass',10);LOADMYSQL USERSTORUNTIME;SAVEMYSQL USERSTODISK;

default_hostgroup=10的意思是:默认请求都走写组(主库),除非后面的规则明确指定读组。

4.4 核心:配置读写分离规则

这是最关键的一步,规则决定了哪些 SQL 走主库、哪些走从库。

-- 规则1:SELECT 且不在事务中 → 走读组(20)INSERTINTOmysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)VALUES(1,1,'^SELECT.*',20,1);-- 规则2:事务中的 SELECT → 要走主库(保证一致性)INSERTINTOmysql_query_rules(rule_id,active,match_digest,match_pattern,destination_hostgroup,apply)VALUES(2,1,'^SELECT.*FOR UPDATE',10,1);-- 规则3:写操作(INSERT/UPDATE/DELETE)→ 走写组(10)INSERTINTOmysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)VALUES(3,1,'^(INSERT|UPDATE|DELETE)',10,1);-- 规则4:默认兜底,走写组INSERTINTOmysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)VALUES(4,1,'.*',10,1);LOADMYSQL QUERY RULESTORUNTIME;SAVEMYSQL QUERY RULESTODISK;

规则按rule_id从小到大匹配,匹配到就停止。所以顺序很重要:先匹配 SELECT FOR UPDATE(要读主),再匹配普通 SELECT(读从),再匹配写操作,最后兜底走主库。


五、验证效果

应用连接改成 ProxySQL 的地址:

spring:datasource:url:jdbc:mysql://proxysql:6033/mydbusername:app_userpassword:app_pass

然后用stats_mysql_query_digest表查看路由情况:

SELECTdigest_text,sum_time,count_star,hostgroupFROMstats_mysql_query_digestORDERBYcount_starDESCLIMIT10;

如果看到 SELECT 的hostgroup是 20,INSERT/UPDATE 的hostgroup是 10,恭喜,读写分离生效了 ✅


六、踩坑实录(血泪史)

💣 坑 1:事务里的读操作被路由到从库

现象:一个事务里先 INSERT 了一条数据,紧接着 SELECT 查出来是空的。

原因:SELECT 被规则匹配到读组,去从库查了,但从库还没同步完这条数据(主从延迟)。

解决:开启事务时,ProxySQL 会自动把所有请求路由到同一个 hostgroup(默认是事务开始的那个)。但我当时没用事务包裹,就出问题了。

正确做法:涉及"写后立即读"的逻辑,要么放事务里,要么在 SQL 前加注释强制走主库:

/* hostgroup=10 */SELECT*FROMordersWHEREuser_id=123;

💣 坑 2:从库挂了,流量没自动切走

现象:一个从库宕机后,ProxySQL 还在往上面发请求,导致部分查询报错。

原因:没配健康检查,或者检查间隔太长。

解决:用mysql_replication_hostgroups表让 ProxySQL 自动管理主从状态:

INSERTINTOmysql_replication_hostgroups(writer_hostgroup,reader_hostgroup,comment)VALUES(10,20,'主从自动管理');LOADMYSQL SERVERSTORUNTIME;SAVEMYSQL SERVERSTODISK;

配上之后,从库挂了会自动摘流量,主库挂了会触发切换(配合 MGR 或 Orchestrator 效果更好)。

💣 坑 3:规则写得太宽泛,漏匹配

现象:有些查询没被规则匹配到,全走到了默认的主库,从库闲置。

原因match_digest用的是正则,^SELECT.*看起来能匹配所有 SELECT,但如果 SQL 里有换行或者注释,就可能匹配不上。

解决:用SELECT ... FOR UPDATE这种明确的模式做精确匹配,普通 SELECT 放最后兜底。规则宁可写细一点,别贪多。

💣 坑 4:忘了 SAVE 到 DISK

现象:重启 ProxySQL 后,所有配置都没了。

解决:每次改完配置,记得SAVE MYSQL ... TO DISK;。后来我写了个脚本,改完自动 LOAD + SAVE,再也没丢过配置。

💣 坑 5:监控没跟上,出问题了才知道

现象:ProxySQL 本身挂了,应用全连不上,半小时后才被发现。

解决:监控 ProxySQL 的关键指标:

  • ProxySQL_Threadpool_TrxNum:当前事务数
  • mysql_server_ping_errors:后端节点健康状态
  • stats_mysql_connection_pool:连接池使用情况

配合 Prometheus + Grafana,ProxySQL 出问题能秒级告警。


七、总结

选型这件事,说难也难,说简单也简单。

我目前只需要读写分离,没有分库分表的需求。ProxySQL 做不了分库分表,但恰好够用,这就是最合适的选择。

手写代码做读写分离,短期轻松长期痛苦。中间件看似多引入一层,省掉的是后面无限叠加的维护成本。

规则顺序和事务一致性,是读写分离最容易翻车的两个地方。配规则的时候多测几遍,别等上线了再翻车。

👋 我是数据库小学妹,一个用设计师思维学数据库的转行人。你们在读写分离选型上踩过什么坑?


本文基于 ProxySQL 2.5 + MySQL 8.0 环境。不同版本配置略有差异,建议参考官方文档确认参数。

http://www.cnnetsun.cn/news/2610011.html

相关文章:

  • 【MATLAB源码-第450期】基于MATLAB的GMSK调制系统中IQ相干、差分、鉴频与Viterbi解调算法对比仿真
  • AI品牌命名避坑清单(含12个高危词根、6类语音陷阱、4种文化禁忌),错过本次更新将影响全球市场准入
  • 论文同时踩查重和AI检测红线?双效处理工具实测推荐
  • NASM到底怎么用 汇编转机器码实战详解
  • 开源语音AI的边界:从 `luongnv89/claude-howto` 看前沿技术的落地实践
  • 从野外数据到地下构造:手把手教你用地震时距曲线做一次‘虚拟勘探’
  • Python 新手入门,用 AI 写个自动诗歌生成器
  • rtx3060把一个10个中等零件组成的装配体变成点云要多久
  • 信号处理避坑指南:当你的Welch法谱估计分辨率上不去,问题可能出在这几个参数上
  • CC Debugger在Keil μVision中的配置与调试技巧
  • 开发者速围观!Android 17 适配关键全解读丨OTalk 直播回顾
  • PyCharm 2024.1 新UI搭配 Anaconda 2024.02:从安装到创建第一个AI项目的完整流程
  • 腾讯会议共享PPT时,如何偷偷看备注?用这个隐藏技巧,演讲者模式秒开启
  • 别再满屏找配置文件了!Windows 11下DOSBox窗口大小调整保姆级教程(含隐藏文件夹显示)
  • Win10家庭版也能用组策略!保姆级DISM命令安装gpedit.msc教程(附一键脚本)
  • 别再满盘找nvidia-smi了!Win10下CUDA 11.0+的GPU监控工具藏在这儿
  • 别再浪费钢网了!嘉立创/捷配下单时,这个关于Mark点的勾选项你注意了吗?
  • 别再只看准确率了!用Python手把手教你计算混淆矩阵、精准率和召回率(附完整代码)
  • Ubuntu 装英伟达显卡驱动
  • OpenMV串口数据收发的那些坑:解码错误、数据丢失?手把手教你调试与避雷
  • 拆开家里坏掉的LED灯,发现厂家用这个‘发热电阻’故意缩短寿命,教你一招搞定
  • 新手别乱买!保姆级盘点:FPV穿越机遥控器/接收机品牌怎么选(从乐迪到黑羊)
  • Outfit字体终极指南:为什么这款开源几何无衬线字体值得你立即使用?
  • Java AI Agent内存架构:分层模型、检索优化与生产实践
  • GR-RL 具身强化学习框架 内部未公开原始技术密档(接续续篇·纯工业裸数据)
  • GD32单片机环境搭建避坑实录:从Keil 5安装到固件库配置,我踩过的雷你别踩
  • 避坑指南:CentOS 7.6下bond模式从1改到4,为什么网络服务重启后不生效?
  • 别再手动改稿了!ChatGPT抖音脚本自动化流水线(含自动分镜/口型同步/违禁词实时拦截模块)
  • 告别环境噩梦:基于Docker与VSCode的gem5-GCN3 GPU模拟器一站式开发指南
  • intel 有没有挖台积电的墙角 ,否则怎么突然行了呢