- 后端
- 数据库
- 负载均衡
【免费下载链接】proxysql
High-performance proxy for MySQL and PostgreSQL
ProxySQL 是一个用 C++17 编写的高性能、协议感知的 MySQL / PostgreSQL 代理,提供连接池、查询路由、缓存与监控能力,基于 GPL 协议开源。本文以仓库根目录的 CLAUDE.md 为骨架,结合源码、Makefile 与测试基础设施,系统讲解本仓库的构建管线、Feature Tier 编译模型、TAP 测试流程、双协议架构与编码规范,帮助开发者和 AI 编码代理快速、正确地在本仓库中完成构建、测试与代码提交。
构建系统总览:deps → lib → src 三段式管线
ProxySQL 的构建系统基于 GNU Make,采用经典的三段式流水线,全部通过根目录的 Makefile 驱动:
deps/ → 构建 25+ 个 vendored 第三方依赖,产物为静态库 lib/ → 编译 lib/ 下约 128 个 .cpp 文件,产出 lib/libproxysql.a src/main.cpp → 链接 libproxysql.a,生成最终 proxysql 可执行文件- 根 Makefile 负责编排三段,并向下传递编译参数(
OPTZ、PROXYSQL*系列特性开关等); deps/中的依赖均以源码形式 vendored,例如jemalloc、sqlite3、mariadb-client-library、postgresql、libev、re2、libinjection、lz4/zstd、prometheus-cpp、libscram等;- src/main.cpp 是程序入口,负责守护进程初始化与线程启动(CLAUDE.md 中标注约 95K 行,当前实际 3513 行——注意文档数据偏旧,以仓库现状为准)。
常用构建命令(取自 CLAUDE.md 并补充说明):
# 完整 release 构建(自动根据 nproc/hw.ncpu 检测 -j) make # Debug 构建(-O0、-ggdb、-DDEBUG) make debug # 带 ASAN 的构建(必须 NOJEMALLOC=1,因为 jemalloc 与 ASAN 不兼容) NOJEMALLOC=1 WITHASAN=1 make build_deps_debug && make debug && make build_tap_test_debug # 构建 TAP 测试二进制(前提:先构建出 proxysql 可执行文件) make build_tap_tests # release 版测试 make build_tap_test_debug # debug 版测试 # 清理 make clean # 清理 src/lib 的目标文件与 libproxysql.a make cleanall # 全量清理,包括 deps 下的第三方依赖 # 构建发行包(rpm/deb/tar 等,见 Makefile 中 amd64-packages/arm64-packages 目标) make packages注意 Makefile 中build_tap_tests/build_tap_test_debug均依赖build_src/build_src_debug,即测试二进制必须在 proxysql 二进制构建成功之后才能编译。
Feature Tier:同一份代码编译出三种产品形态
本仓库最具辨识度的构建机制是Feature Tier(特性层级):通过编译期特性开关,同一份代码库产出三种产品形态。每个 Tier 都继承更低一层的全部特性。
| Tier | 开关标志 | 对应版本 | 追加特性 |
|---|---|---|---|
| Stable | (默认,不传标志) | v3.0.x | 核心代理(连接池、路由、缓存、监控) |
| Innovative | PROXYSQL31=1 | v3.1.x | FFTO、TSDB |
| Plugin Chassis | PROXYSQL40=1 | v4.0.x | 插件加载器 + ABI(4 阶段生命周期、query-hook、共享 Prometheus),并构建打包全部 v4.0 插件,含 mysqlx 与 genai/MCP |
标志蕴含关系(源码级证据见根 Makefile):
PROXYSQL40=1 ⇒ PROXYSQL31=1 ⇒ PROXYSQLFFTO=1 + PROXYSQLTSDB=1 + PROXYSQLED25519=1Makefile 中的ifeq链自动完成上述蕴含展开:设置PROXYSQL40=1会同时开启PROXYSQL31;设置PROXYSQL31=1会同时开启 FFTO、TSDB 与 ED25519。
关键澄清(与很多新贡献者的直觉相反):
- 没有独立的
PROXYSQLGENAI标志。所有 AI / MCP / RAG / LLM 功能都位于 plugins/genai/,通过PROXYSQL40=1统一构建与打包,运行时以.so插件形式通过dlopen加载; - 默认的裸
make编译的是Stable Tier,明确不含 FFTO 与 TSDB(MySQLFFTO.cpp/PgSQLFFTO.cpp被排除,#ifdef PROXYSQLFFTO保护的符号如mysql_thread___ffto_max_buffer_size不会定义); - 因此 CI 从不构建裸默认版本:每个 CI 包构建/测试构建都会设置 Tier 标志(
PROXYSQL31=1或PROXYSQL40=1),这在 .github/workflows/CI-*.yml 中有大量实例,例如PROXYSQL31=1 make -j$(sysctl -n hw.ncpu)(macOS v31 构建)与PROXYSQL40=1 make ${{ env.MAKE_TARGET }}(AlmaLinux genai 包构建)。
切换 Tier 必须 clean:stale-object tier mismatch
Makefile 不会在两次调用之间追踪 Tier 标志。在某 Tier 下编译出的目标文件与lib/libproxysql.a,会在下一次不同 Tier(或他人构建过的目录树)下被静默复用。经典症状是链接失败:
undefined reference to `mysql_thread___ffto_max_buffer_size' undefined reference to `pgsql_thread___ffto_max_buffer_size'这不是真实损坏,也不是默认构建的 bug——它是陈旧的Tier 不匹配(例如启用了 FFTO 的libproxysql.a链接了未带PROXYSQLFFTO编译的main.o)。不要试图通过去掉 Tier 标志来“修复”。
正确做法(CLAUDE.md 原文强调)是:切换 Tier 时先清理,并且在一个会话中对每次 make 都传递同一个Tier 标志:
# 切换 Tier(或不确定目录树上次用什么 Tier 构建):先 clean make clean # 清除 lib/ + src/ 目标文件与 libproxysql.a PROXYSQL31=1 make -j$(nproc) # 然后统一用想要的 Tier 构建 # 如果 deps 也是在别的 Tier 下构建的,还需要:make cleanall(会重建 deps,较慢)构建标志速查
NOJEMALLOC=1— 禁用 jemalloc 内存分配器;WITHASAN=1— 启用 AddressSanitizer(要求NOJEMALLOC=1);WITHGCOV=1— 启用代码覆盖率采集;PROXYSQLCLICKHOUSE=1— 当前构建中默认启用(根 Makefile 在 deps/lib/src 各阶段均显式传入)。
架构:MySQL 与 PostgreSQL 的双协议并行设计
ProxySQL 的核心架构特点是双协议并行:MySQL 与 PostgreSQL 使用同一套架构设计、但各自协议专属的实现类,形成镜像的类层级:
| 架构层 | MySQL 实现 | PostgreSQL 实现 |
|---|---|---|
| 协议 | MySQL_Protocol | PgSQL_Protocol |
| 会话 | MySQL_Session | PgSQL_Session |
| 线程 | MySQL_Thread | PgSQL_Thread |
| HostGroups | MySQL_HostGroups_Manager | PgSQL_HostGroups_Manager |
| 监控 | MySQL_Monitor | PgSQL_Monitor |
| 查询处理器 | MySQL_Query_Processor | PgSQL_Query_Processor |
| 日志 | MySQL_Logger | PgSQL_Logger |
上述类均有对应的 include/ 头文件与 lib/ 实现文件,例如MySQL_Session.h/MySQL_Session.cpp与PgSQL_Session.h/PgSQL_Session.cpp,读者可直接对照阅读。
核心组件
- Admin 接口(lib/ProxySQL_Admin.cpp、lib/Admin_Handler.cpp)——基于 SQLite3 的 SQL 式配置管理,支持无需重启的运行期配置变更;配置库 schema 版本在 include/ProxySQL_Admin_Tables_Definitions.h 中追踪。
- HostGroups Manager——按 hostgroup 分配路由连接,支持 master-slave、Galera、Group Replication 与 Aurora 拓扑。
- Query Processor——解析查询、匹配路由规则,通过
Query_Cache处理查询缓存。 - Monitor——对后端做健康检查,监测复制延迟、read-only 状态与连通性。
- 线程模型——基于 libev 的事件驱动 I/O;
Base_Thread为基类,协议专属的线程管理器派生其上。 - HTTP/REST(
ProxySQL_HTTP_Server、ProxySQL_RESTAPI_Server)——提供指标与管控端点。
条件编译组件
- FFTO(Fast Forward Traffic Observer)——lib/MySQLFFTO.cpp / lib/PgSQLFFTO.cpp;
- TSDB——时序指标与内嵌 Dashboard;
- ClickHouse——原生 ClickHouse 协议支持;
- GenAI / MCP / RAG / LLM——自插件拆分(carve-out)完成后全部位于 plugins/genai/,不属于
libproxysql.a与proxysql二进制本体。其加载路径可通过源码确认:src/main.cpp 使用dlopen加载插件;src/proxysql.cfg 中的genai_variables=用于相关配置;注释明确指出 GenAI 的变量初始化、handler 构造与 shutdown 均已移交至 genai 插件的 init/start 回调(见 src/main.cpp 相关注释)。
测试:TAP 协议 + Docker 后端基础设施
测试采用 TAP(Test Anything Protocol)协议,运行在 Docker 化的后端基础设施之上。测试代码位于 test/tap/,基础设施脚本位于 test/infra/。
铁律:不要手动搭建 Docker 环境
永远使用run-tests-isolated.bash,它统一负责基础设施搭建、ProxySQL 启动、测试执行与清理。绝不要手动创建 Docker 网络、启动容器或运行 init 脚本——runner 会全部代劳。
被测试的 proxysql 二进制必须是 DEBUG 构建。隔离测试 harness(
proxysql-tester.py)会下发 debug-only 的 admin 命令(LOAD DEBUG FROM DISK、admin-debug变量,两者均为#ifdef DEBUG保护),release 二进制会报Unknown global variable: 'admin-debug'或near "LOAD": syntax error而无法(重新)配置。这一点在 test/infra/README.md 中有同步印证。
标准流程:
# 1) 先构建 DEBUG 版二进制,并保持 Tier 标志一致 PROXYSQL31=1 make debug # 2) 搭建基础设施(后端 + ProxySQL 容器) WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 test/infra/control/ensure-infras.bash # 3) 运行一个 TAP group 的全部测试 WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 test/infra/control/run-tests-isolated.bash # 4) 运行组内单个测试 —— 用 TEST_PY_TAP_INCL 正则过滤器 # 不要为隔离单个测试而临时建组;测试仍属于其真实分组,只是做过滤 # (详见 test/infra/SKILL.md 与 test/infra/README.md) WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=legacy-g4 \ TEST_PY_TAP_INCL="pgsql-reg_test_5866_result_format-t" \ test/infra/control/run-tests-isolated.bash # 5) 在不拆除后端的情况下换入重建的二进制: # ProxySQL 容器运行的是工作区构建的二进制,重建后需重新执行此脚本 # (它只重建 ProxySQL 容器,保留后端;普通 ensure-infras.bash 不会拾取 # 已运行 ProxySQL 的重建二进制,docker restart 也不是受支持的机制) WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 test/infra/control/start-proxysql-isolated.bash可用的 TAP group 定义在 test/tap/groups/groups.json,组名遵循<infra>-g<N>模式(如mysql84-g1、legacy-g2、pgsql16-g1、unit-tests-g1等)。TEST_PY_TAP_INCL是与组内测试名匹配的正则——这是文档规定的运行单个测试的方式。从 groups.json 可以看到,测试条目可携带版本门控注解(如"@proxysql_min_version:4.0"),同一测试可同时挂到多个组。
DO NOT 清单
- 不要手动创建 Docker 网络(
docker network create); - 不要手动启动容器(
docker start、docker run); - 不要直接运行
docker-compose-init.bash——请用ensure-infras.bash; - 不要在 worktree 之间符号链接构建产物——每个 worktree 单独构建;
- 不要在 worktree 或仓库之间复制源文件;
- 不要直接
cd test/tap/tests && make并期望无基础设施也能通过。
测试文件约定
测试文件位于 test/tap/tests/,命名遵循test_*.cpp或*-t.cpp模式。测试二进制通过 test/tap/tests/Makefile 中的模式规则构建:make <testname>-t会把<testname>-t.cpp编译成<testname>-t。新增测试无需改 Makefile——只要添加.cpp文件并在groups.json中注册即可。
CI/测试失败的处理纪律
项目的测试质量要求极高,永远不要把 CI 失败当作"pre-existing"或"flaky"来打发——这些词是观察而非分析,把它们当结论会让真实 bug 存活下来。当分支或 PR 上的 CI 失败时:
- 阅读真实失败:打开失败的测试日志、其产生的 proxysql 服务日志与测试源码,定位具体的断言、超时、崩溃或非零退出,并在报告中引用相关行。
- 陈述根因而非症状:"Test X failed" 是症状;根因是为什么——竞态条件、陈旧 fixture、资源泄漏、协议回归、环境不匹配等。
- 拆成两个独立问题并分别用证据回答:
- 本次改动是否导致该失败?——通过逐 commit 推理与代码路径分析回答,而不是只对比基线的通过/失败率;
- 该测试是否与本次改动无关地本身就是坏的?——这是独立问题,早于本改动就存在的失败仍是要修复或登记的问题,而不是"带病合并"的理由。
- 若本次会话内无法确定根因,明确说出来并给出下一步调查建议(带日志重跑、插桩测试、登记跟踪 issue),不要用"flaky"掩盖不确定性。
- 反复失败的测试是更高优先级的 bug,而不是更低优先级的——复现本身就是失败模式可复现的证据,这正是它能被修复的原因。
单元测试 harness
单元测试位于 test/tap/tests/unit/,通过自定义 harness 链接libproxysql.a。测试必须使用test_globals.h与test_init.h(完整模式见 doc/agents/project-conventions.md,其中明确要求#include "test_globals.h"与#include "test_init.h")。从单元测试文件即可看到大量直接面向内部类的用例,例如auth_unit-t.cpp、connection_pool_unit-t.cpp、backend_sync_unit-t.cpp、caching_sha2_rsa_unit-t.cpp、duckdb_config_unit-t.cpp等。
关键依赖一览
deps/下 vendored 的第三方依赖及其用途(见 CLAUDE.md 与 deps/Makefile):
jemalloc— 内存分配器(可用NOJEMALLOC=1关闭,ASAN 构建必须关闭);sqlite3— admin 配置存储;mariadb-client-library— MySQL 协议;postgresql— PostgreSQL 协议;re2、pcre2— 正则引擎;libev— 事件循环;libinjection— SQL 注入检测;lz4、zstd— 压缩;curl、libmicrohttpd、libhttpserver— HTTP;prometheus-cpp— 指标;libscram— SCRAM 认证。
代码布局
- include/ — 全部头文件(.h/.hpp),头文件保护采用
#ifndef __CLASS_*_H风格; - lib/ — 核心库源码(约 128 个 .cpp,通常一文件一类);
- src/main.cpp — 程序入口、守护进程初始化、线程启动;
- test/tap/ — TAP 测试框架与用例;
- test/infra/ — 基于 Docker 的测试环境;
- .github/workflows/ — CI/CD 流水线(selftests、TAP 测试、包构建、CodeQL),架构总览见 doc/GH-Actions/README.md(ProxySQL 使用双分支 caller/reusable 拆分:
CI-*.yml在v3.0,ci-*.yml在GH-Actions分支,该文档是权威参考)。
Agent 协作指南与编码规范
仓库为 AI 编码代理准备了专门文档(doc/agents/):
- doc/agents/project-conventions.md — ProxySQL 专属规则(目录、构建、测试 harness、git 工作流);
- doc/agents/task-assignment-template.md — 可分配给 AI agent 的 issue 编写模板;
- doc/agents/common-mistakes.md — 已知的 agent 失败模式及预防/检测方法。
编码约定
- 类名:
PascalCase并带协议前缀(MySQL_、PgSQL_、ProxySQL_); - 成员变量:
snake_case; - 常量/宏:
UPPER_SNAKE_CASE; - 必须 C++17;条件编译使用
#ifdef PROXYSQL31、#ifdef PROXYSQL40、#ifdef PROXYSQLFFTO、#ifdef PROXYSQLTSDB、#ifdef PROXYSQLCLICKHOUSE; PROXYSQLGENAI已不再守卫任何核心代码(GenAI 插件拆分完成后,它只存在于 plugins/genai/ 内部);- 性能关键代码:注意对热路径的影响;
- 资源管理使用 RAII;内存分配使用 jemalloc;
- 同步使用 pthread mutex;计数器使用
std::atomic<>。
总结:给开发者的最小正确工作流
把以上要点浓缩成一个可复制的起步流程:
# 1) 选好目标 Tier,并保持一致 PROXYSQL31=1 make -j$(nproc) # 日常开发推荐 v3.1(或 PROXYSQL40=1 用于 genai 插件) # 2) 切换 Tier 时务必先 clean make clean PROXYSQL40=1 make -j$(nproc) # 3) 跑 TAP 测试(debug 二进制 + 隔离 runner) PROXYSQL31=1 make debug make build_tap_test_debug WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 \ test/infra/control/run-tests-isolated.bash遵循"同一 Tier 贯穿构建会话 + 切换即 clean + 始终用隔离 runner 跑测试 + 以根因分析对待 CI 失败"这几条纪律,即可避免本仓库绝大多数构建与测试陷阱。更详细的规则请随时回查 CLAUDE.md、doc/agents/project-conventions.md 与 test/infra/SKILL.md。
- 后端
- 数据库
- 负载均衡
【免费下载链接】proxysql
High-performance proxy for MySQL and PostgreSQL
相关推荐
Streamlit 仓库开发指南:架构布局、uv/make 构建策略与四层测试体系详解
Streamlit 仓库开发指南:架构布局、uv/make 构建策略与四层测试体系详解 本文以仓库根目录 AGENTS.md https://link.gitc
数据可视化后端前端Trigger.dev 仓库开发协作指南:读懂 AGENTS.md 与 CLAUDE.md 分层的构建、测试与架构体系
Trigger.dev 仓库开发协作指南:读懂 AGENTS.md 与 CLAUDE.md 分层的构建、测试与架构体系 本指南以 Trigger.dev 开源仓
AI Agent后端任务调度开发工具可观测性AI 应用Uppy 仓库开发指南:Monorepo 架构、插件体系与构建测试实践
Uppy 仓库开发指南:Monorepo 架构、插件体系与构建测试实践 本文是基于 Uppy 开源仓库根目录 CLAUDE.md https://link.gi
前端UI组件后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考