ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MySQL Proxy性能测试与优化实战

MySQL Proxy性能测试与优化实战

1. MySQL Proxy测试报告:从原理到实战的全方位解析

上周刚完成公司核心系统的MySQL Proxy压力测试,趁着记忆新鲜把完整测试过程和关键结论整理出来。这份报告不仅包含常规性能指标,更会深入分析Proxy在不同业务场景下的表现差异,以及我们趟过的那些坑。如果你正在评估或使用MySQL Proxy,这篇实测数据或许能帮你少走弯路。

MySQL Proxy作为轻量级中间件,本质上是在客户端和MySQL服务器之间建立了一个透明代理层。它通过Lua脚本实现查询拦截、改写、负载均衡等核心功能,特别适合需要灵活控制数据库流量的场景。我们这次测试主要针对Proxy在高并发写入、复杂查询路由和故障转移三个核心场景的表现。

2. 测试环境与架构设计

2.1 硬件配置与拓扑结构

测试采用生产级环境配置:

  • 代理层:3台16核32G内存的VM,分别部署MySQL Proxy 0.8.5
  • 数据库层:6台物理服务器组成主从集群(2主4从)
  • 网络:万兆光纤互联,模拟IDC内网延迟(<1ms)
# Proxy启动命令示例 ./mysql-proxy \ --proxy-lua-script=/usr/share/mysql-proxy/rw-splitting.lua \ --proxy-backend-addresses=10.0.0.1:3306 \ --proxy-backend-addresses=10.0.0.2:3306 \ --proxy-read-only-backend-addresses=10.0.0.3:3306 \ --daemon

2.2 测试数据集设计

为模拟真实业务,我们构造了三种典型数据模型:

  1. 用户行为日志表(高频写入)
  2. 订单交易表(事务密集型)
  3. 商品信息表(大字段查询)

每类表初始数据量5000万条,采用与实际业务相符的字段结构和索引设计。

3. 核心性能测试结果

3.1 吞吐量对比测试

测试场景直连MySQL QPS通过Proxy QPS性能损耗
纯写入12,4589,32725.1%
纯查询23,67121,8457.7%
混合读写(7:3)18,99215,33619.3%

注意:Proxy的性能损耗主要来自网络跳转和Lua脚本解析开销。在写入密集型场景尤其明显

3.2 延迟分布统计

通过99线(P99)指标观察长尾延迟:

  • 简单查询:直连8ms → Proxy 12ms
  • 复杂联表查询:直连35ms → Proxy 53ms
  • 批量插入(100条/事务):直连110ms → Proxy 168ms

实测发现当并发连接数超过500时,Proxy的延迟波动会显著增大。这与其单线程事件循环的设计有关。

4. 关键功能验证

4.1 读写分离实现

我们修改了默认的rw-splitting.lua脚本,增加基于SQL特征的路由逻辑:

function read_query(packet) if string.match(packet, "FOR UPDATE") then return proxy.PROXY_SEND_QUERY end -- 将分析型查询路由到特定从库 if is_analytic_query(packet) then proxy.connection.backend_ndx = 3 -- 指向专用分析从库 end end

这种细粒度控制带来两个收益:

  1. 将报表查询隔离到独立实例,避免影响交易业务
  2. 强制关键事务走主库,解决读写分离导致的数据一致性问题

4.2 连接池管理

Proxy默认不维护连接池,我们通过以下参数优化连接复用:

proxy-connection-max-age=600 proxy-connection-pool-size=200 proxy-connection-pool-timeout=60

实测表明合理的连接池配置可以降低30%的连接建立开销,特别是在微服务频繁创建短连接的场景。

5. 生产环境踩坑实录

5.1 内存泄漏问题

连续运行72小时后,Proxy进程内存从初始的800MB增长到3.2GB。通过valgrind检测发现是Lua脚本中的全局变量未及时释放导致。解决方案:

-- 错误写法 query_cache = {} -- 正确写法 local query_cache = setmetatable({}, {__mode = "v"}) -- 使用弱引用表

5.2 故障转移陷阱

测试模拟主库宕机时,发现Proxy不会自动重连新的主库。需要配合keepalived实现VIP漂移,并在脚本中添加心跳检测:

function connect_server() local ok, err = proxy.connection.backend:connect() if not ok then -- 触发告警并尝试切换备用节点 alert_system("DB failure detected!") proxy.connection.backend_ndx = (proxy.connection.backend_ndx % #proxy.global.backends) + 1 return connect_server() end end

6. 性能优化实践

6.1 批量操作加速

针对批量插入场景,我们在Proxy层实现了写合并优化:

  1. 收集短时间内相同表的INSERT语句
  2. 合并为多值插入语法(INSERT INTO t VALUES(a),(b)...)
  3. 批量提交到后端数据库

测试显示该优化使批量写入吞吐量提升4-5倍,但需要注意:

  • 合并窗口不宜超过200ms,否则会影响业务感知延迟
  • 必须保证同批次操作属于相同业务上下文

6.2 查询缓存策略

对于热点查询,在Proxy层实现结果缓存:

local cache = require "resty.lrucache" local query_cache, err = cache.new(200) -- 缓存200条查询结果 function read_query(packet) local key = packet:sub(2) -- 跳过命令字节 local cached = query_cache:get(key) if cached then proxy.response = { type = proxy.MYSQLD_PACKET_OK, resultset = cached } return proxy.PROXY_SEND_RESULT end end function read_query_result(inj) if not inj.resultset.error then query_cache:set(inj.query, inj.resultset) end end

7. 替代方案对比

当测试发现Proxy在某些场景不满足需求时,我们对比了其他方案:

特性MySQL ProxyProxySQLMySQL Router应用层Sharding
协议支持完整完整完整依赖实现
配置复杂度中等高低极高
动态调整需重启热加载热加载需发布
监控指标简单丰富中等自定义
最大QPS支持~15k~50k~30k无上限

最终我们决定在交易核心链路采用ProxySQL,而在需要高度定制的分析场景保留MySQL Proxy。

8. 监控指标体系建设

完善的监控是稳定运行的基础,我们采集的关键指标包括:

基础资源层

  • Proxy进程CPU/内存占用
  • 网络吞吐量(区分进出流量)
  • TCP连接数统计

业务逻辑层

  • 查询类型分布(SELECT/INSERT等)
  • 各后端节点响应时间
  • 错误代码统计(如1062主键冲突)

自定义指标

  • Lua脚本执行耗时
  • 连接池利用率
  • 缓存命中率

这些数据通过Telegraf采集后,在Grafana上呈现为统一监控看板。当P99延迟超过阈值或错误率突增时,会触发企业微信告警。

9. 稳定性测试特别发现

在72小时持续压力测试中,我们观察到几个有趣现象:

  1. TCP端口耗尽:当客户端使用短连接且QPS>3000时,Proxy机器会出现TIME_WAIT状态端口堆积。解决方案:
# 调整内核参数 sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_max_tw_buckets=20000
  1. Lua GC卡顿:脚本中频繁创建临时表会导致每隔5-7分钟出现一次200ms级别的延迟毛刺。通过调整GC参数缓解:
collectgarbage("setpause", 80) -- 降低GC频率 collectgarbage("setstepmul", 200) -- 增加单步处理量
  1. 协议解析异常:某些ORM框架生成的SQL包含非常规字符,导致Proxy解析失败。需要在脚本开头添加预处理:
function packet_to_string(pkt) pkt = string.gsub(pkt, "[^%w%p%s]", function(c) return string.format("\\x%02x", string.byte(c)) end) return pkt end

10. 生产部署建议

根据测试结果,我们总结出这些最佳实践:

  1. 拓扑设计
  • 每个Proxy实例建议承载不超过800个客户端连接
  • 采用双层Proxy架构:前端用HAProxy做LB,后端才是MySQL Proxy
  • 代理层与数据库节点保持同机房部署
  1. 参数调优
# 关键参数调整 event-threads=4 # 与CPU核数匹配 proxy-address=0.0.0.0:4040 admin-address=0.0.0.0:4041 admin-username=monitor admin-password=SuperSecret!
  1. 高可用方案
  • 使用Keepalived实现VIP故障转移
  • 每台Proxy配置独立的管理端口用于健康检查
  • 部署ZooKeeper集群维护后端数据库状态

这套配置在我们生产环境已稳定运行6个月,日均处理20亿+查询。虽然Proxy有性能损耗,但其灵活的流量控制能力在业务高峰时多次救场。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进