多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ProxySQL mysqlx 插件运维级测试工具链:行为验证与压力测试实战指南

ProxySQL mysqlx 插件运维级测试工具链:行为验证与压力测试实战指南 后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载导读ProxySQL 的 mysqlx 插件为 MySQL X Protocol 提供代理能力但常规的 TAP 单元测试无法覆盖真实运行环境下的停机、路由热更新与高并发连接压力。本文以仓库中的 test/scripts/mysqlx/README.md 为骨架结合 behavioral_validation.py、stress.py 两个运维级测试脚本及插件源码完整讲解如何在真实基础设施上验证 mysqlx 插件的关键运行时行为——优雅停机通知、运行中路由重载、长时间高并发稳定性并给出可直接复制的环境搭建与执行配方。读者读完后可以搭建一套针对 mysqlx 插件的 smoke soak 验证流程并理解其底层实现依据。一、工具定位为什么需要运维级测试而不是 TAP 单测仓库 test/tap 目录下的测试是标准的 TAP 单元测试可在隔离环境中运行。而 mysqlx 插件的两个运维测试脚本 behavioral_validation.py 与 stress.py 则完全不同它们不是 TAP 单元测试而是针对运行中的 ProxySQL 实例做端到端验证它们依赖真实基础设施一台启用 X Protocol 的 MySQL 8.x 后端默认端口 33060、一个加载了 mysqlx 插件的 ProxySQL 实例以及通过mysqlx_users/mysqlx_routes映射好的测试用户它们存在的目的是服务于issue #5677、#5678、#5681所跟踪的合并后置信度工作——即代码合并之后通过真实流量验证其在生产形态下是否按设计工作。换句话说这两个脚本弥补了单元测试到真实运行之间的验证断层单元测试保证逻辑正确运维测试保证在真实网络、真实 MySQL、真实插件加载形态下依然正确。二、环境前置条件根据 README运行这些脚本需要满足三项前置ProxySQL 已构建并加载 mysqlx 插件构建时需要启用PROXYSQLGENAI1插件动态库位于plugins/mysqlx/ProxySQL_MySQLX_Plugin.so插件的完整构建入口见 plugins/mysqlx/Makefile。MySQL 8.x 后端启用 X Protocol默认端口 33060并有一个测试用户通过 ProxySQL 的mysqlx_users/mysqlx_routes映射到后端。Python 依赖mysql-connector-python提供 X DevAPI 绑定pip install mysql-connector-python两个脚本在ImportError时都会直接打印提示并退出见 behavioral_validation.py 与 stress.py因此依赖缺失时失败信息是明确的。三、behavioral_validation.py两个关键运行时行为验证该脚本对应issue #5678通过真实 X-Protocol 流量验证两个对运维至关重要的行为。脚本默认同时运行两个场景也可用--scenario单独执行。3.1 完整命令行参数源码 behavioral_validation.py 中定义的参数如下参数默认值说明--proxysql-host127.0.0.1ProxySQL X-Protocol 监听地址--proxysql-port6603ProxySQL 上的 X-Protocol 监听端口--admin-host127.0.0.1ProxySQL admin 地址--admin-port6032ProxySQL admin 端口走经典 MySQL 协议--admin-useradminadmin 用户名--admin-passadminadmin 密码--user必填X-Protocol 测试用户--password必填测试用户密码--clients5并发客户端数--external-shutdown关闭不由本进程发起PROXYSQL SHUTDOWN SLOW而等待外部角色发起适用于 docker 隔离的 TAP 封装运行--shutdown-wait-sec5.0等待外部触发的停机通知时间--scenarioallshutdown/reload/all三选一--route-namer1reload 场景中要删除的路由名客户端会话的建立方式open_session显式禁用 TLS 与压缩ssl-modeDISABLED、compressiondisabled以保证验证聚焦于 X Protocol 数据面本身。3.2 场景一PROXYSQL SHUTDOWN SLOW运行中停机该场景打开 N 个并发 X-Protocol 客户端持续执行SELECT 1然后通过 admin 端口经典协议发出PROXYSQL SHUTDOWN SLOW最后逐一核对每个客户端收到的是干净的Mysqlx::Error帧错误码 1053Server is shutting down而不是未经宣布的 TCP RST。脚本的判定逻辑利用了mysql-connector-python的异常语义连接断开时它抛出mysqlx.errors.OperationalError但TCP RST 与收到Mysqlx::Error帧都表现为同类异常只能靠错误码区分——errno为1053说明是干净的停机通知否则包括没有errno属性视为 TCP RST见 steady_traffic_thread。最终统计中只有当clean_close args.clients每个客户端都收到 1053时脚本才返回 PASS。该行为对应的底层实现是MysqlxSession::shutdown_notify_client()README 标注的提交55e90d1a7源码位于 plugins/mysqlx/src/mysqlx_session.cpp#L2399-L2425。其实现要点尽力而为客户端写侧已关闭fd 0或会话已处于X_SESSION_CLOSED/X_SESSION_CLOSING时直接返回不让停机悬挂在半关闭的对端上发送致命错误帧调用send_error(1053, Server is shutting down, /*fatal*/true)构造Mysqlx::Error消息FATAL严重级别、HY000SQL 状态并封装为ServerMessages_Type_ERROR帧入队见 send_error冲刷到线缆单次write_to_net()尽力将队列中的帧写出TLS 干净关闭若会话启用 TLS通过SSL_set_quiet_shutdown(1)SSL_shutdown()发出close_notify使对端 TLS 栈看到干净关闭而非被撕裂的记录最后将状态置为X_SESSION_CLOSING并标记会话不健康。这一链路正是脚本断言客户端看到 1053 而非 TCP RST的实现基础。3.3 场景二LOAD MYSQLX ROUTES TO RUNTIME运行中路由重载该场景先让 N 个客户端在路由r1上跑流量随后通过 admin 端口执行DELETE FROM mysqlx_routes WHERE namer1并LOAD MYSQLX ROUTES TO RUNTIME然后断言两件事存量会话继续工作已建立的 in-flight 会话继续向该路由原先对应的后端执行查询脚本以无错误且查询数 100判定存活新连接被拒绝向该路由发起的新连接得到 connection-refused。该行为对应 README 指出的remove_listener_for_route语义实现分布在两个文件中路由协调层plugins/mysqlx/src/mysqlx_listener_reconcile.cpp#L107-L132 中协调逻辑对不再期望存在或bind 地址已变化的路由调用threads[tidx]-remove_listener_for_route()并关闭其监听套接字bind 地址变化按先删后加处理监听器管理plugins/mysqlx/src/mysqlx_thread.cpp#L406-L420 中remove_listener_for_route()在listener_mutex_保护下close()对应 fd并同步从listener_fds_/listener_addrs_/listener_ports_/listener_route_names_四组并行数组中移除该路由条目。值得注意的实现细节源码注释 plugins/mysqlx/src/mysqlx_thread.cpp#L400-L405 明确说明路由名只在认证阶段的后端目标解析时被查阅因此一个已认证的会话不依赖路由名仍然存活——这从原理上解释了为什么移除路由 重载不会打断 in-flight 会话只会拒绝新连接。这正是脚本场景二断言成立的底层依据。注释同时指出若未来需要路由移除时主动断开存量会话可以在sessions_中匹配default_route并对每个会话调用shutdown_notify_client()——即场景一验证的那条路径。3.4 管理面命令的预期断开处理脚本通过 admin 端口经典协议mysql.connector执行管理命令。源码对管理面断开做了容错执行PROXYSQL SHUTDOWN SLOW或路由重载后若 admin 连接报errno 2006/2013或错误信息含Lost connection/gone away会视为预期断开而非失败见 issue_admin_shutdown。这是停机过程本身会关闭 admin 连接这一真实行为的正确处理。四、stress.py长时间高并发压力与资源稳定性验证该脚本对应issue #5681目标是验证 mysqlx 插件在长时间、高并发、连接持续更替churn下的稳定性。4.1 完整命令行参数参数默认值说明--proxysql-host/--proxysql-port127.0.0.1/6603X-Protocol 入口--admin-host/--admin-port127.0.0.1/6032admin 入口采集stats_mysqlx_routes--admin-user/--admin-passadmin/adminadmin 凭证--user/--password必填X-Protocol 测试用户--concurrent100并发客户端数目标规模 N1000--duration60m运行时长支持60s/30m/24h等后缀见 parse_duration--churn-interval30s连接更替周期--churn-fraction0.1每个 churn tick 要更替的客户端比例--metrics-out/tmp/mysqlx_stress_metrics.csv指标输出 CSV 路径--metrics-interval-sec10指标采样间隔秒4.2 工作负载模型每个ClientWorkerstress.py是一个守护线程其运行模式为反复mysqlx.get_session()建立会话 → 在会话内循环执行SELECT 1→ 出现异常时错误计数 1 并sleep(0.5)退避避免后端故障时占满 CPU。会话在每次循环迭代中重新建立这本身就提供了自然的连接级 churn。源码注释还如实说明了一个实现现状churn tick按errors降序挑选最挣扎的 worker目前只记录更替意图到日志并未强制重启线程连接级 churn 由主循环的get_session()天然提供stress.py——读者理解指标时应以此为准。4.3 指标采集维度脚本每个采样周期采集五类数据并写入 CSV表头见 stress.py吞吐total_queries与增量计算的queries_per_sec错误率total_errors结束时以errors / max(1, queries)计算进程资源通过pidof proxysql定位进程find_proxysql_pid读取/proc/pid/status的VmRSSKiB与Threads并统计/proc/pid/fd目录条数proc_status路由统计周期查询 admin 端SELECT * FROM stats_mysqlx_routesfetch_route_stats结束时打印最终快照。CSV 列为t_sec, rss_kib, threads, fds, total_queries, total_errors, queries_per_sec可直接绘图观察 RSS / fd / 线程数是否存在单调增长。4.4 通过标准与判定脚本内置的通过标准对应 issue #568160 分钟运行无崩溃、无内存/fd 单调增长、错误率 0.1%、吞吐稳定。程序化判定为最终error_rate 0.001时输出PASS: error rate under 0.1%并返回 0否则输出 FAILstress.py其余维度崩溃、资源单调增长需要结合 CSV 曲线与进程存活情况人工确认。脚本还会收集最多 5 个不同的 worker 错误样本打印出来便于定位错误类型。五、端到端实操配方Smoke Soak5.1 第一步拉起 MySQL 8.x 后端README 提供两种方式任选其一方式 A——Dockerdocker run -d --nametest_mysql -p 3306:3306 -p 33060:33060 \ -e MYSQL_ROOT_PASSWORDroot mysql:8.4方式 B——dbdeployer参见仓库内已提供的自动化脚本 test/tap/groups/mysqlx-e2e/setup-infras.bash它完成安装 dbdeployer、下载并解包 MySQL 8.4、以--port13306部署单实例 sandbox、等待就绪并创建mysqlx_test用户mysql_native_password、全部权限。5.2 第二步在 admin shell 中配置用户、后端与路由通过 classic 协议连接 ProxySQL admin默认127.0.0.1:6032用户admin/ 密码admin执行以下配置mysql -h 127.0.0.1 -P 6032 -u admin -padmin SQL INSERT INTO mysqlx_users(username, default_route) VALUES(alice,r1); INSERT INTO mysqlx_backend_endpoints(hostname, mysql_port, mysqlx_port) VALUES(127.0.0.1, 3306, 33060); INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES(10, 127.0.0.1, 3306); INSERT INTO mysqlx_routes(name, bind, destination_hostgroup) VALUES(r1, 0.0.0.0:6603, 10); LOAD MYSQLX USERS TO RUNTIME; SAVE MYSQLX USERS TO DISK; LOAD MYSQLX ROUTES TO RUNTIME; SAVE MYSQLX ROUTES TO DISK; LOAD MYSQLX BACKEND ENDPOINTS TO RUNTIME; SAVE MYSQLX BACKEND ENDPOINTS TO DISK; SQL要点mysqlx_users.default_route指定用户默认路由mysqlx_routes的bind决定 X-Protocol 监听地址这里为0.0.0.0:6603destination_hostgroup指向mysql_servers中的后端主机组每次修改后都要LOAD ... TO RUNTIME生效SAVE ... TO DISK持久化。5.3 第三步先跑 Smoke行为验证python3 test/scripts/mysqlx/behavioral_validation.py \ --proxysql-host 127.0.0.1 --proxysql-port 6603 \ --user alice --password whatever --duration 30s注README 示例中的--duration 30s属于验收流程描述实际脚本中场景时长为固定节奏场景一启动流量后约 5 秒完成停机验证场景二约 7 秒完成重载验证--duration参数在脚本的 argparse 定义中并未出现运行时请以--clients、--scenario等实际参数为准。建议先用--scenario reload --clients 5单独验证路由重载再跑--scenario all全量。5.4 第四步再跑 Soak24–72 小时压测python3 test/scripts/mysqlx/stress.py \ --proxysql-host 127.0.0.1 --proxysql-port 6603 \ --user alice --password whatever \ --concurrent 100 --duration 24h \ --metrics-out /tmp/mysqlx_soak_metrics.csv5.5 第五步周期性采集辅助指标Soak 期间README 建议配合以下外部监控命令与脚本自身指标交叉验证# 进程资源RSS 与线程数 cat /proc/$(pidof proxysql)/status # 文件描述符数量 ls /proc/$(pidof proxysql)/fd | wc -l # 路由级统计 mysql -h 127.0.0.1 -P 6032 -u admin -padmin -e SELECT * FROM stats_mysqlx_routes--metrics-out生成的 CSV含t_sec, rss_kib, threads, fds, ...各列可直接绘图用于验证无单调增长——这是判断内存/句柄泄漏的关键证据。六、当前状态与验证边界README 的 Status 部分给出了重要的事实边界引用时必须如实传达这两个测试工具目前是脚手架scaffolds——可运行但尚未在真实基础设施上跑过。它们晚于 PR #5651 的合并窗口置信度提升取决于有人在 staging 环境运行并将结果反馈到关联 issue#5677、#5678、#5681。因此本文所介绍的全部通过标准1053 干净通知、路由移除后存量会话存活、错误率 0.1% 等是脚本与插件源码中定义的预期行为读者应将其视为验证目标而非已实测达成的结论。运行环境方面脚本假定 ProxySQL 构建时启用了PROXYSQLGENAI1且 mysqlx 插件已加载这些前提不满足时脚本无法给出有意义的结论。七、延伸阅读mysqlx 插件整体架构doc/mysqlx/ARCHITECTURE.md插件源码目录plugins/mysqlx/src、头文件 plugins/mysqlx/include停机通知实现plugins/mysqlx/src/mysqlx_session.cpp#L2399-L2425路由监听协调plugins/mysqlx/src/mysqlx_listener_reconcile.cpp#L107-L132监听器移除实现plugins/mysqlx/src/mysqlx_thread.cpp#L406-L430dbdeployer 后端自动部署脚本test/tap/groups/mysqlx-e2e/setup-infras.bash赞分享后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载相关推荐ProxySQL MySQLX 插件综合测试计划三层测试架构与 400 断言实战指南ProxySQL MySQLX 插件综合测试计划三层测试架构与 400 断言实战指南 本文以仓库内 docs/superpowers/plans/2026后端数据库负载均衡vue-fastapi-admin性能优化秘籍前后端分离架构的性能提升策略vue fastapi admin性能优化秘籍前后端分离架构的性能提升策略 vue fastapi admin是基于FastAPIVue3Naive UI后端前端认证鉴权Navigation2 行为插件系统级测试Behavior Tests指南架构、测试用例与实战运行Navigation2 行为插件系统级测试Behavior Tests指南架构、测试用例与实战运行 本篇技术指南聚焦 ROS 2 Navigation2机器人ROS自动驾驶上一篇为什么你需要zvec-grep统一ripgrep、BM25与向量搜索的Local-First混合检索神器下一篇Sinon Promises创建可控制状态与手动兑现的 JavaScript 假 Promise创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表