后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载导读本文深入解析 ProxySQL 面向 MySQL/PostgreSQL 的高性能代理中新增的**字面量用户变量跟踪Literal User-Variable Tracking**功能它通过新变量mysql-user_variable_tracking让一类仅把用户变量当作请求元数据的SET var 字面量语句在连接池与多路复用multiplexing场景下继续获得路由与复用而不是被当作未知 SET 触发 hostgroup 锁定。读完本文你将掌握该功能的启用条件与配置步骤、被支持的 SQL 字面量子集、ParserSQL 类型化分析契约、前端/后端会话状态模型、跨后端同步与批量重放机制以及它的安全边界、可观测性与测试策略。一、问题背景一次普通 SET 为何会让连接失去多路复用在默认配置下ProxySQL 把每一个 MySQL 用户自定义变量user-defined variable形如x都视为未跟踪的会话状态。例如如下语句SET browser_lang en-US, browser_time 2026-08-11 18:11:12, browser_timezone GMT2, ip_address 167.235.198.244会落入MySQL_Session::unable_to_parse_set_statement()路径对应实现见 include/MySQL_Session.h。当mysql-set_query_lock_on_hostgroup1时ProxySQL 会把前端会话锁定到当前 hostgroup并禁用其后端连接上的多路复用。这种做法是安全的但对那些只用用户变量赋值携带请求元数据如语言、时区、IP、时间戳的应用来说代价过高本可在连接池中任意复用后端的轻量赋值却导致会话被钉死在一个后端上。设计文档docs/superpowers/specs/2026-08-11-user-variable-literal-tracking-design.md指出ParserSQL 已经能把 SET 的目标target与右侧表达式RHS表示为带类型的 AST 节点。ProxySQL 可以借助这些类型信息从任意表达式中识别出一个小而安全的赋值子集跟踪其产生的会话状态并在池化的后端连接之间同步该状态——这正是本文介绍的功能。二、设计目标与非目标目标对受支持的字面量用户变量赋值保留多路复用与查询路由能力通过把客户端的第一条 SET原样转发给后端保留 MySQL 原生的值、类型、字符集、排序规则、转义与错误语义在多个后端连接与 hostgroup 之间同步被跟踪的用户变量防止用户变量状态在不同前端会话之间泄漏当 ProxySQL 无法证明某操作属于受支持子集时回退到现有的用户变量安全行为包括mysql-set_query_lock_on_hostgroup1时的 hostgroup 锁定功能**显式开启opt-in**且依赖 ParserSQL为未来语义保留高于首个已实现模式的整型配置值。非目标在 ProxySQL 内求值表达式跟踪由 SELECT、预处理语句prepared statements、存储过程、存储函数或触发器执行的赋值检测完全发生在后端内部的用户变量变更支持包含 SET 加其他语句的多语句multi-statement在功能关闭时改变任何行为为部分解析或未知 SQL 放宽安全性。三、配置变量、前置条件与启用步骤3.1 变量定义新增一个整型 MySQL 变量变量默认值初始取值范围含义mysql-user_variable_tracking00..10维持现状1保守的字面量跟踪在 lib/MySQL_Thread.cpp 中该变量以元组形式注册VariablesPointers_int[user_variable_tracking] make_tuple(variables.user_variable_tracking, 0, 1, false)即默认值0、取值范围0..1。取值器会拒绝尚无已实现语义的值未来新增模式时再扩展最大值。对应的线程局部变量为mysql_thread___user_variable_tracking定义于 include/proxysql_structs.h与mysql_thread___set_query_lock_on_hostgroup、mysql_thread___set_parser_algorithm、mysql_thread___query_processor_parser并列。3.2 激活前置条件模式1只有在满足以下任一条件时才生效mysql-set_parser_algorithm3或mysql-query_processor_parser1为完整查询路径选择 ParserSQL。若模式1已加载但两个前置条件都不满足ProxySQL 会发出配置警告并继续使用现有的回退行为。在默认mysql-set_query_lock_on_hostgroup1下该回退会钉住会话。ProxySQL不会静默地强制修改其他解析器设置。从源码看这一前置条件检查位于 lib/Admin_FlushVariables.cpp当user_variable_tracking 1 set_parser_algorithm ! 3 query_processor_parser ! 1时输出一条一次性的聚合安全警告提示需启用两个 ParserSQL 设置之一才能激活跟踪。3.3 启用步骤以下 SQL 通过 ParserSQL SET 解析器启用该功能UPDATE global_variables SET variable_value 1 WHERE variable_name mysql-user_variable_tracking; UPDATE global_variables SET variable_value 3 WHERE variable_name mysql-set_parser_algorithm; LOAD MYSQL VARIABLES TO RUNTIME;若使用mysql-query_processor_parser1替代mysql-set_parser_algorithm3同样满足条件。注意每次在该状态下执行LOAD MYSQL VARIABLES TO RUNTIME会发出一条固定、聚合安全的警告点名两个可选解析器设置但不含任何语句字面量值后续回退的 SET 语句不会重复该前置条件警告。四、支持的 SQL 子集字面量白名单模式1仅当以下条件全部成立时才接受一条文本协议text-protocolSETParserSQL 返回覆盖完整输入的、成功且完整的解析语句是单条 SET而非预处理语句或多语句命令每个赋值目标都是 MySQL 用户变量每个右侧都是受支持的字面量形式全部结果状态保持在资源上限之内。4.1 受支持的右侧字面量单引号与双引号字符串字面量有符号或无符号整数字面量有符号或无符号定点数fixed-point与指数形式exponent-form数字字面量0x...与X...十六进制字面量0b...与B...位bit字面量NULL。符号sign只允许作为直接作用于数字、十六进制或位字面量的一元/-。括号表达式、类型转换cast、字符集引入符introducer、COLLATE子句、标识符、系统变量引用、用户变量引用、函数、子查询、运算符、占位符placeholder以及所有其他表达式节点在模式1中均不支持。4.2 原子性与混合语句一条 SET 中的多个字面量用户变量赋值是受支持的且整体原子处理同时混合用户变量与系统变量的语句模式1不支持走现有未知 SET 回退——这样初始实现不会把ProxySQL 拦截的系统变量语义与后端确认的用户变量语义混在同一条语句里赋值保持源顺序包括对同一名字的重复赋值最后一次成功赋值成为已提交的映射条目。4.3 变量名约束变量名限于 ParserSQL 可以无损规范化normalize并重新输出的形式比较时大小写不敏感并须满足 MySQL 的64 字节名称上限。任何无法表示或格式错误的名称都会让整条语句被判为不支持。此外被跟踪的名称必须是 ASCII以保证大小写不敏感规范化无歧义含反斜杠的带引号目标名因身份依赖 SQL 模式而不被接受。五、ParserSQL 契约类型化分析接口5.1 词法与 AST 区分ParserSQL而非 ProxySQL 适配层拥有字面量与表达式之间的词法、AST 区分权。所需的 ParserSQL 工作先在上游落地并附带聚焦的解析器测试ProxySQL 随后通过更新 vendored 归档来消费一个打了标签的发布版本。AST 至少需要区分整数integer浮点/定点/指数数字floating/fixed/exponent number字符串string十六进制hexadecimal位bitNULL一元符号unary sign非字面量表达式nonliteral expression。5.2 类型化适配层ProxySQL 适配层新增一个类型化分析结果而不是扩展既有的有损mapstring, vectorstringSET 接口。设计文档给出的契约如下enum class UserVariableSetStatus { NOT_USER_VARIABLE_SET, SUPPORTED, UNSUPPORTED, PARSE_ERROR }; enum class UserVariableLiteralKind { STRING, INTEGER, DECIMAL, HEXADECIMAL, BIT, NULL_VALUE }; struct UserVariableAssignment { std::string canonical_name; std::string replay_target; std::string raw_literal; UserVariableLiteralKind kind; uint64_t hash; }; struct UserVariableSetAnalysis { UserVariableSetStatus status; std::vectorUserVariableAssignment assignments; };字段语义canonical_name大小写不敏感的映射键replay_target经 ParserSQL 校验、安全重建的...目标ProxySQL 绝不从未校验的客户端文本构造重放目标raw_literal右侧表达式的精确源码区间含引号与转义hash用于加速比较。分析是**全有或全无all-or-nothing**的只有在验证了每一个赋值与完整输入覆盖之后才返回SUPPORTED绝不给 ProxySQL 返回可部分应用的部分赋值列表。从仓库现状看include/Query_Processor_ParserSQL.h 已落地了面向查询使用分类的判定接口mysql_user_variable_query_disposition()与mysql_user_variable_raw_query_disposition()并定义了UserVariableQueryDisposition枚举LEGACY、SUPPORTED_SET、SAFE、UNSAFE_FALLBACK与UserVariableQueryDecision结构——可见设计文档所述契约在实现中已具体化为可调用的 C 接口。六、状态模型与资源上限前端与后端的MySQL_Connection对象各自持有一张有界映射canonical variable name - { replay target, raw literal, literal kind, hash }前端映射是 ProxySQL 对逻辑客户端会话的视图后端映射是 ProxySQL 对该物理 MySQL 连接上已物化的状态的视图。哈希只用于加速比较正确性绝不只依赖哈希两条相等的条目还必须具有相同的字面量种类、重放目标与原始字面量文本。模式1的初始上限每个前端会话至多128个不同变量每个前端会话至多存储64 KiB的重放目标与字面量文本。后端映射适用同样上限。对已存在名字的重新赋值会替换其旧条目并更新字节记账。一条 SET 若会超过任一上限不会部分跟踪ProxySQL 先向选中的后端同步此前已跟踪的状态转发该 SET再走既有的未知 SET 安全路径。对应实现字段可见于 include/MySQL_Session.h如pending_user_variable_set、user_variable_tracking_latched、user_variable_backend_authoritative等与 include/mysql_connection.h后端连接上的MySQL_User_Variable_State user_variables。七、初始 SET 的完整数据流对于一条受支持的字面量 SET处理流程如下ParserSQL 产出完整的UserVariableSetAnalysisProxySQL 用暂存后的 post-SET 前端映射校验资源上限ProxySQL 把分析结果存为待定pending查询状态暂不修改已提交映射ProxySQL 把客户端的原始 SQL 转发给选中的后端后端报错则丢弃待定状态把原始错误返回给客户端后端成功响应后把全部待定条目原子地同时应用到前端映射与该后端映射查询完成状态分类器被告知这是受支持的已跟踪 SET因此不设置STATUS_MYSQL_CONNECTION_USER_VARIABLE该状态位定义于 include/mysql_connection.h在正常的会话事务与状态检查通过后后端可以归还连接池。转发是有意为之它让 MySQL 对 SQL 模式、字面量校验、警告、转换与版本特定行为保持权威。ProxySQL 存储的是可重放的语法而不是独立求出的值。八、后端选择、同步与批量重放8.1 池匹配扩展既有连接池匹配模型被扩展以包含用户变量映射number_of_matching_session_variables()统计相等的用户变量条目与不匹配项使状态最接近的后端被优先选中requires_CHANGE_USER()当某后端存在前端映射中缺失的用户变量名时返回 true必须重置——因为仅仅赋NULL并不能保证复现未初始化变量生命周期的方方面面类型等一次成功的后端COM_CHANGE_USER或重置会清空其后端用户变量映射。8.2 同步顺序获取后端后ProxySQL 按如下顺序同步用户名与 schema常规已跟踪会话变量含 charset、collation 与sql_mode已跟踪的用户变量客户端查询。把用户变量排在常规会话状态之后可确保重放的原始字面量在与原始赋值相同的相关会话上下文中被解释。8.3 确定性批量重放缺失与不匹配的用户变量在命令能装进后端数据包上限时以一条确定性的批量 SET 命令重放SET name1raw-literal-1, name2raw-literal-2若无法一次性容纳ProxySQL 发送确定性的有界批次。后端映射条目只在该内部 SET 成功后提交。重放出错不会改动前端映射它会令待处理的客户端查询失败并按既有内部 SET 错误路径把后端标记为重置或退役。关于数据包预算用户指南doc/mysql-user-variable-tracking.md补充了具体数值若后端的max_allowed_pkt为 0 或尚未得知重放保守采用 MySQL 服务端 1024 字节下限扣除 4 字节数据包头与 1 字节COM_QUERY命令后每个重放批次至多剩1019 字节的 SQL 文本。放不进该上限的单个赋值无法拆分ProxySQL 会使待处理客户端查询失败并退役该后端。映射匹配的连接无需重放带多余状态extra state的连接可走既有的重置路径而非永久不可用。九、查询使用分类读、写与未知不含字节的查询可跳过额外的使用分类解析但在执行前仍会同步已跟踪状态——因为后端侧代码可能读取用户变量。含的查询由 ParserSQL 用户变量使用分类器解析。设计文档描述的初始分类器有三个结果NO_USER_VARIABLE出现的仅属于字符串、注释或无关语法READ_ONLY所有真实的用户变量 AST 出现都是读UNSAFE_OR_UNKNOWN查询写用户变量、部分解析、格式错误、是多语句或含语义未被显式支持的 AST 形态。READ_ONLY查询包括读取未初始化名字保持可多路复用。池选择保证所选后端要么持有前端值要么没有陈旧的多余值。常规查询后状态分类器接收该安全分类不设置STATUS_MYSQL_CONNECTION_USER_VARIABLE。UNSAFE_OR_UNKNOWN查询先同步当前已跟踪映射再在执行前走既有未知状态回退默认mysql-set_query_lock_on_hostgroup1下会锁定 hostgroup。该类别包括SELECT x : ...以及 SET 之外的赋值SELECT ... INTO x非字面量 SET 赋值使用用户变量的预处理语句占位符部分或失败的解析不支持的 AST 形态。回退使后端会话状态变为**连接绑定connection-bound**后所选后端对用户变量状态具有权威性ProxySQL 对后续用户变量赋值停止修改映射。十、隐藏后端修改的约束MySQL 的会话状态通知协议只报告系统变量不报告用户自定义变量。因此 ProxySQL 无法观察到完全发生在存储过程、存储函数或触发器内部的用户变量修改。模式1支持后端侧代码读取已同步的用户变量——这正是请求元数据的主要使用场景但它不支持这类代码修改它们。该约束会随配置变量显著声明。由于隐藏修改会使后端映射失效并可能让后续客户端拿到陈旧状态这不仅是可观测性限制更是正确性与隔离要求。opt-in 的默认关闭也避免现有部署静默接受这一更窄的安全模型。十一、重置与运行时生命周期前端COM_RESET_CONNECTION清空前端映射前端COM_CHANGE_USER新身份生效前清空旧逻辑会话映射后端COM_CHANGE_USER、连接重置、重连与销毁清空后端映射失败的原始 SET仅丢弃其待定赋值绝不改动已提交映射受支持的重新赋值仅在后端成功后才可见一旦会话因回退使后端状态连接绑定既有已跟踪状态仍可用于诊断与清理但不再更新。运行时关闭drain运行时禁用会阻止新的赋值进入跟踪状态。已拥有跟踪状态的会话会继续同步该状态直到COM_RESET_CONNECTION、COM_CHANGE_USER或断开连接——避免在活跃前端会话中途丢失状态。离开 ParserSQL 前置条件也有同样的 drain 行为既有状态照常同步新 SET 赋值改用当前回退。会话在其首个已跟踪赋值提交时**闩锁latch**基于 ParserSQL 的使用分类因此后续运行时配置变更不会让既有读操作失去分类。十二、错误处理与安全底线没有完整输入覆盖就不信任任何解析结果没有语句会被部分跟踪客户端 SET 失败时返回后端的原始错误重放失败会使待处理查询失败而不是带着错误状态执行ParserSQL 前置条件失败、超限与不支持语法都通过既有未知状态回退fail closedmysql-set_query_lock_on_hostgroup1时锁定 hostgroup该变量为0时保留 pre-2.0.6 的连接状态行为显式禁用多路复用的查询规则继续优先既有的mysql-set_query_lock_on_hostgroup语义对每个回退仍然权威新增的、功能特定的警告、调试原因与指标永不包含用户变量值既有的通用查询日志与解析失败日志策略不变。十三、可观测性新增计数器同时出现在stats_mysql_global与 Prometheus 计数器统计名Prometheus 计数器含义User_variable_assignments_trackedproxysql_mysql_user_variable_assignments_tracked_total已提交的受支持赋值目标User_variable_replay_commandsproxysql_mysql_user_variable_replay_commands_total已执行的内部重放 SET 批次User_variable_replay_failuresproxysql_mysql_user_variable_replay_failures_total失败的重放批次User_variable_fallback_unsupportedproxysql_mysql_user_variable_fallback_unsupported_total不支持的 SET 回退次数User_variable_fallback_limitsproxysql_mysql_user_variable_fallback_limits_total资源上限导致的回退次数PROXYSQL INTERNAL SESSION报告用户变量的count、stored_bytes总量以及按进程键控的聚合状态指纹。它刻意不暴露变量名、重放目标、字面量值或逐条原始哈希——因为请求元数据可能包含凭据、令牌或个人可识别信息。集成测试 test/tap/tests/mysql-user-variable-tracking-t.cpp 中正是通过查询这 5 个计数器的值来断言功能行为。既有的未知 SET 警告对不支持的语句继续生效并继续遵循mysql-parse_failure_logs_digest新增的区分性调试原因可标识 ParserSQL 前置条件、不支持的 AST、资源上限或重放失败且不超出既有查询日志策略添加字面量内容。十四、兼容性模式0无行为变化且是默认值解析算法 1 与 2 保持现有行为未启用用户变量跟踪的 ParserSQL 模式保持现有行为受支持的模式 1 SET 语句继续到达 MySQL服务端错误与警告仍然权威查询规则的multiplex覆盖与全局禁用多路复用保持不变MySQL 与 MariaDB 的版本差异通过转发与重放精确校验过的字面量语法处理跨后端不兼容表现为重放错误而不是静默改变状态。十五、测试策略ParserSQL 测试每种受支持字面量拼写的 AST 节点类型与精确源码覆盖有符号整数、定点数、指数、十六进制与位变体含逗号、引号、反斜杠与的转义字符串多赋值用户变量 SET 语句规范化与 64 字节名称上限对函数、子查询、变量、运算符、cast、COLLATE、引入符、占位符、畸形输入与多语句的拒绝/非字面量分类SELECT 及其他受支持语句类型中的只读与写分类。ProxySQL 单元测试前端/后端映射的插入、替换、哈希与字节记账上限预检preflight的原子性池匹配包含相等与不相等的用户变量映射多余后端名字需要重置后端重置清空状态重放批次的确定性安全引号待定赋值仅在成功时提交状态标志抑制仅发生在受支持的 SET 与经证实的只读使用上。TAP 集成测试文档报告的四变量 SET不产生未知 SET 警告、不锁定 hostgroup在查询之间强制切换不同后端连接与 hostgroup 后值保持正确字符串 charset/collation、数值类型、hex、bit、NULL、覆盖写与未初始化读取均与直连 MySQL 一致两个前端客户端互不可见对方变量带多余状态的后端在服务无此状态的前端前被重置失败的原始赋值不更新跟踪状态重放错误不会用陈旧状态执行待处理查询COM_RESET_CONNECTION与COM_CHANGE_USER清空状态非字面量 SET、混合系统/用户 SET、SET 外的:、INTO、预处理语句、部分解析、超限与缺少 ParserSQL 前置条件均保留既有安全回退运行时关闭安全 drain 既有状态并阻止新跟踪查询规则 multiplex 覆盖保留既有行为。覆盖范围需跑通仓库支持的 MySQL 与 MariaDB 测试组包括禁用多路复用及备选 digest/解析器设置的配置。十六、预期代码改动区域与验收标准预期代码区域ParserSQL 的 tokenizer、AST、SET 解析器、用户变量使用分类器与上游测试随后是 ProxySQL 中 vendored 的 ParserSQL 发布归档include/Query_Processor_ParserSQL.h 与 lib/Query_Processor_ParserSQL.cpp类型化适配层契约include/mysql_connection.h 与 lib/mysql_connection.cpp映射、池匹配、重置行为与诊断include/MySQL_Session.h 与 lib/MySQL_Session.cpp待定 SET 状态、同步、回退与结果处理include/MySQL_Thread.h、include/proxysql_structs.h、lib/MySQL_Thread.cpp 与 admin 校验新整型变量TAP 与单元测试注册文件。验收标准功能完成需满足默认配置下行为不变模式1 ParserSQL 启用时文档报告的字面量 SET 保持可多路复用、可路由每个受支持的值在另一个后端连接上以 MySQL 等价的值与类型复现无后端用户变量状态泄漏到另一前端会话每个不支持、有歧义、超限或部分解析的操作使用现有回退包括mysql-set_query_lock_on_hostgroup1时的 hostgroup 钉住失败的原始或重放 SET 永不提交错误的映射状态重置与换用户操作清空正确状态测试在受支持后端版本与相关配置组上全部通过。结语mysql-user_variable_tracking是 ProxySQL 在安全优先与池化效率之间的一次精确取舍它不尝试在代理层求值任何表达式而是借助 ParserSQL 的类型化 AST 识别出一个可证明安全的字面量赋值子集由 MySQL 保持语义权威ProxySQL 只负责跟踪、同步与确定性重放。对依赖用户变量携带请求元数据的应用而言这一 opt-in 特性让连接池重新变得可用而对所有无法证明安全的情形它严格 fail closed 到既有锁定行为。设计、用户指南doc/mysql-user-variable-tracking.md与集成测试test/tap/tests/mysql-user-variable-tracking-t.cpp三方互为印证值得在启用前完整阅读。赞分享后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载相关推荐ProxySQL 用户变量字面量跟踪mysql-user_variable_tracking实战指南让 MySQL 用户变量安全地跨连接复用ProxySQL 用户变量字面量跟踪mysql user_variable_tracking实战指南让 MySQL 用户变量安全地跨连接复用 本文围绕 P后端数据库负载均衡ProxySQL MySQL 用户变量字面量跟踪mysql-user_variable_tracking实现解析让 SET name literal 保持连接多路复用ProxySQL MySQL 用户变量字面量跟踪mysql user_variable_tracking实现解析让 SET name literal后端数据库负载均衡ProxySQL 的 PostgreSQL 用户凭据同步器pgsql_user_sync设计与实战指南ProxySQL 的 PostgreSQL 用户凭据同步器pgsql_user_sync设计与实战指南 本指南以仓库设计文档 docs/superpower后端数据库负载均衡上一篇GTA5线上小助手免费开源的游戏增强工具终极指南下一篇5分钟快速上手MAA明日方舟自动化助手开源工具效率提升指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?