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

文章详情

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

Vitess v23.0.6 发布详解:VReplication、VTGate 表达式引擎与复制链路的关键修复

Vitess v23.0.6 发布详解:VReplication、VTGate 表达式引擎与复制链路的关键修复 Vitess v23.0.6 发布详解VReplication、VTGate 表达式引擎与复制链路的关键修复【免费下载链接】vitessVitess is a database clustering system for horizontal scaling of MySQL.项目地址: https://gitcode.com/gh_mirrors/vi/vitess本篇文章基于 Vitess 仓库 changelog/23.0/23.0.6/changelog.md 整理系统解读 v23.0.6 补丁版本的全部变更。该版本属于 release-23.0 分支的第六个补丁版聚焦于稳定性与正确性修复覆盖 VReplication/VDiff 数据流、VTGate 的 evalengine 表达式引擎、VTTablet 事务节流与心跳、reparent 候选排序以及 CI 与安全加固。读完本文你将能按模块理解每一项修复的触发场景、底层原理含源码证据以及升级后应当关注的行为变化。版本总览与变更分布v23.0.6 是一个以修复为主的补丁版本按分类统计大致如下Bug fixes缺陷修复覆盖 Build/CI、Documentation、Query Serving、VDiff、VReplication、VTGate、VTTablet、vtctl 多个模块是本版本的主体CI/Build构建与持续集成修复 mysql57 环境依赖、change-detection 过滤器自引用、归档站点下载失败重试Compatibility Bug兼容性缺陷ENUM 在数值上下文中的序数语义对齐 MySQLDependencies依赖升级Docker 构建镜像 Go 版本升级到go1.25.12、go1.25.13Enhancement增强备份恢复强制TZUTC、mysql 协议流式错误语义改进Internal Cleanup / Release / Security维护者列表更新、v23.0.6 代码冻结、CI 权限最小化与密钥传递加固。从变更密度看VTGate含 evalengine与 VReplication是本次修复最集中的两个领域下文逐一展开。VReplication 与 VDiff数据流正确性修复VReplication 是 Vitess 实现在线迁移MoveTables、Reshard与持续数据同步的核心机制v23.0.6 对其做了多项细粒度修复。SET 列第 64 个成员的丢失问题[release-23.0] vstreamer: dont drop a SET columns 64th member (#20450)修复了一个位于 binlog 流解析层的边界 bug。MySQL 的 SET 列最多可定义 64 个成员binlog 事件中以一个 64 位无符号整数位图表示。vstreamer 在把整数位图还原成字符串时必须逐位检查这 64 个 bit。从源码看实现位于 vstreamer.go 的buildSetStringValue// A SET column can have 64 unique values ... // For this reason the binlog event contains the values encoded as an unsigned 64-bit // integer which is really a bitmap. iv, err : value.ToUint64() ... idx : 1 // See what bits are set in the bitmap using bitmasks. A SET can have up to // 64 members, so we need to check all 64 bits, including bit 163 for the // 64th member. The loop terminates when the shift overflows back to 0. for b : uint64(1); b ! 0; b 1 { if ivb 0 { // This bit is set and the SETs string value needs to be provided. ... } idx }此前实现如果漏掉了163这一最高位或位宽判断有误那么定义了 64 个成员的 SET 列在第 64 个值被写入时vstreamer 解码出的字符串会缺少该成员进而导致下游写入的数据与源库不一致。修复后循环依赖位图位移溢出b 1溢出回 0来覆盖全部 64 位保证第 64 个成员也被正确映射。JSON 差异路径转义与 GetTenantClause 标识符转义binlog: escape JSON diff paths when generating diff SQL (#20461)VReplication 在检测到 JSON 列内容差异并生成 diff SQL 时需要转义 JSON 路径中的特殊字符否则路径中包含引号、反斜杠等字符时生成的 SQL 会被错误解析。workflow: escape tenant id and column name in getTenantClause (#20413)getTenantClause用于构造按租户过滤的查询子句修复了租户 ID 与列名未转义可能导致的 SQL 注入/语法错误风险。vplayer 批量写入的正确性VReplication: Avoid sending mixed batch of row changes to bulk insert or bulk delete in vplayer batch mode (#20565)与VReplication: only build a bulk-delete plan for insertNormal table plans (#20889)共同完善了 vplayer 批处理路径批量模式下同一批次内不能同时混入批量插入与批量删除两类行变更否则生成的目标 SQL 语义会混乱bulk-delete 计划只允许为insertNormal类型的表计划构建避免在其它计划形态下误用批量删除导致数据被意外删除。这两项修复直接关系到高吞吐迁移/同步场景下的数据一致性属于对批处理执行器vplayer边界条件的收敛。节流时间不计入 vplayer 停滞期限VReplication: dont count throttled time in the vplayer stall deadline (#20925)vplayer 设有停滞stall截止时间以检测无进展的复制任务但节流throttled期间本身是有意放慢速度而非故障。修复前若把节流时间计入停滞期限长时间节流会被误判为停滞而中断复制。修复后停滞判定只统计非节流的时间保证节流机制与停滞检测互不干扰。工作流状态指标与持久化行对齐VReplication: reconcile in-memory workflow state metric from the persisted row (#20442)VReplication 工作流的内存态指标与持久化的状态行可能出现分歧例如进程重启后内存态未刷新修复后以持久化行为准进行对账reconcile确保workflow show等查询反映真实状态。VDiff 修复VDiff: stop pre-seeding a bogus category in TableDiffPhaseTimings (#20713)表 diff 各阶段计时指标TableDiffPhaseTimings不再预置一个无意义的类别避免监控面板上出现虚假的阶段数据Properly handle vstream filter predicates with multi-col PKs (#20858)当 vstream 的过滤谓词涉及多列主键时VDiff 的谓词计算与行匹配此前可能出错本次修复保证多列主键表在 VDiff 过滤场景下的正确比对。VTGate 与 evalengine表达式引擎行为对齐 MySQLevalengine 是 VTGate 内置的 MySQL 兼容表达式求值引擎位于 go/vt/vtgate/evalengine。v23.0.6 针对它做了大量抠细节的兼容性修复。TO_BASE64 在 57 字节整数倍处的多余 NUL 字节evalengine: dont append a NUL byte to TO_BASE64 output at exact 57 byte multiples (#20474)。MySQL 的TO_BASE64()每编码 76 个字符对应 57 字节输入插入一个换行符。在 fn_base64.go 中可见其实现约定// MySQL wraps every 76 characters with a newline. That maps // to a 57 byte input. So we encode here in blocks of 57 bytes // with then each a newline. var ( mysqlBase64OutLineLength 76 mysqlBase64InLineLength (mysqlBase64OutLineLength / 4) * 3 ) func mysqlBase64Encode(in []byte) []byte { // A newline is only written after a full 57 byte block that has more // input following it, so an input that is an exact multiple of 57 // bytes gets one newline less than len(in)/57. newlines : 0 if len(in) 0 { newlines (len(in) - 1) / mysqlBase64InLineLength } ... }修复点在于当输入长度恰好为 57 的整数倍时输出末尾不应再有额外的字节此前实现可能多写一个 NUL 字节导致编码结果与 MySQL 不一致。ROUND() 对 DOUBLE 的四舍六入五成双evalengine: round DOUBLE ties half to even in ROUND() like MySQL (#20476)MySQL 对浮点ROUND()采用舍入到最接近偶数round half to even即银行家舍入而此前 evalengine 对恰好处于中间值的 DOUBLE 结果可能按其它规则舍入。此修复保证ROUND(2.5)、ROUND(1.5)等边界值行为与 MySQL 完全一致避免因舍入差异引发的数据不一致。二进制协议中的零值日期mysql: encode zero DATE/DATETIME/TIMESTAMP values as zero-length in the binary protocol (#20460)在使用预处理语句binary protocol时零值日期如0000-00-00此前可能被编码为错误长度修复后按 MySQL 语义以零长度编码保证客户端收到的类型与长度正确。表达式求值的内存安全与 NULL 语义evalengine: stop RPAD growing its operand in place (#20697)RPAD在填充时不再原地扩展操作数避免因原地修改缓冲区影响共享的表达式结果evalengine: stop the binary bitwise operators writing over and marking their result (#20696)二进制按位运算、|、^等不再写覆盖并标记其操作数结果防止修改了可能被复用的中间值evalengine: collapse the VM stack when a later LOCATE or SUBSTRING operand is NULL (#20645)当LOCATE/SUBSTRING的靠后操作数为 NULL 时及时折叠collapse虚拟机栈避免栈上残留无效条目影响后续表达式求值。这三项都属于 evalengine 编译/执行栈的健壮性修复尤其影响复杂的嵌套表达式。ENUM 在数值上下文中的 1 起始序数evalengine: use MySQL 1-based ordinal for ENUM in numeric context (#20454)MySQL 中 ENUM 在数值上下文中返回从1开始的序数如SELECT b 0当 ENUM 定义为(a,b)时返回 2。此前 evalengine 可能按 0 起始计算本次修复使其与 MySQL 语义对齐。递归 CTE 的流式深度限制Enforce recursion-depth limit on the streaming recursive CTE path (#20432)递归 CTE 若缺少终止条件会无限迭代v23.0.6 将深度上限也施加到流式执行路径。在 recurse_cte.go 中// maxRecurseDepth caps the number of recursion iterations before we abort. // TODO: This should be controlled with the cte_max_recursion_depth system variable. const maxRecurseDepth 1000TryExecute与TryStreamExecute两条路径都在每次迭代时执行loops maxRecurseDepth检查超限则返回vterrors.VT09030()见 recurse_cte.go。此前仅缓冲路径受保护流式路径缺失该限制时可能被恶意/错误的递归查询拖垮。对应测试位于 recurse_cte_test.go。流式执行的多处状态隔离修复vtgate: copy bindVars per source in streaming Concatenate (#20436)流式Concatenate多个源结果串联中不同源的 bindVars 若共享同一 map前一源的改动会泄漏到后一源修复后每个源拷贝独立的 bindVarsvtgate: copy execute options per scatter call for FetchLastInsertId (#20439)FetchLastInsertId在跨分片散射scatter时每个分片调用需独立的执行选项execute options避免共享导致的状态污染vtgate: do not autocommit per-chunk in streaming insert-select (#20497)流式INSERT ... SELECT不再对每个数据块单独 autocommit避免中途失败时留下半提交的部分数据保证事务语义与批量路径一致。预处理语句与查询提示vtgate: support prepared statements with a leading WITH clause (#20665)预处理语句支持以WITH开头的语句即 CTE 形式的预处理语句扩展了协议兼容面Preserve query hints in field/impossible queries (#20366)在生成字段查询field query与不可能查询impossible query时保留查询提示hint避免 EXPLAIN 或元数据探测阶段丢失优化器提示。客户端连接与超时语义Fix ExecuteMulti timeout context reuse (#20445)ExecuteMulti不再复用已被取消/过期的超时 context防止后续请求继承上一个请求的截止时间而立即超时grpcvtgateconn: stop mutating shared dial options slice (#20580)gRPC 客户端不再修改共享的 dial options 切片消除并发初始化时的数据竞争。VTTablet事务节流、心跳与执行安全txthrottler 在 target_replication_lag_sec1 时不再 panictxthrottler: dont panic on target_replication_lag_sec of 1 (#20554)修复了一个由整数除法下取整为 0引发的崩溃。在 tx_throttler.go 中return ts.maxLag.Load() ts.config.TxThrottlerConfig.TargetReplicationLagSec ... ... ticker : time.NewTicker(time.Duration(ts.config.TxThrottlerConfig.TargetReplicationLagSec) * time.Second / 2)当TargetReplicationLagSec配置为 1 秒时1 * time.Second / 2取整为 0time.NewTicker(0)会立即 panic。对应测试见 tx_throttler_test.go明确注释旧代码把 TargetReplicationLagSec/2 向下取整为 0。修复后该配置值不再触发崩溃事务节流可安全使用 1 秒目标延迟。取消上下文下的 schema 重载回滚vttablet: roll back canceled schema reload on a non-cancelable context (#20385)当一次 schema 重载因 context 取消而失败时若后续使用不可取消的 context 继续执行需要回滚这次被取消的重载状态避免表结构信息处于半更新状态。畸形 RowChange 镜像不再引发 panicvreplication: prevent vttablet panic on malformed RowChange images (#20377)vstream 接收到的 binlogRowChange镜像若字段数量与表结构不匹配畸形数据此前可能导致 vttablet panic本次修复改为返回错误并跳过保证复制进程存活。流式 CALL 路径的存储过程安全检查Enforce stored-procedure safety checks on the streaming CALL path (#20372)vttablet 对存储过程CALL有安全检查例如禁止某些危险调用此前该检查只覆盖部分路径流式CALL可能绕过本次在流式路径上强制同样约束。心跳读取器初始读取vttablet: perform an initial heartbeat read when opening the heartbeat reader (#20868)心跳读取器heartbeat reader打开时立即执行一次初始读取避免启动后长时间无心跳数据导致主从延迟lag指标误报或延迟过高判断。reparent 候选排序与复制管理按 GTID 支配关系排序候选reparentutil: order reparent candidates by GTID dominance for a consistent sort (#20728)同时更新了文档与reparentutil: keep nil-alias tablets out of candidate ordering (#20762)共同改进了 reparent主从切换时候选 tablet 的排序逻辑。GTID 位置是偏序partially ordered关系两个候选可能互不支配如 UUID 集合不相交直接两两比较会导致排序结果不稳定。修复实现在 reparent_sorter.go 的comparePosition// comparePosition orders by replication position using the precomputed dominated // counts (how many other candidates strictly dominate each one). A lower count is // more advanced. Combined dominance takes precedence; at an equal count it falls // through to the Executed-dominated count ... // GTID positions are only partially ordered, so counts are not unique: incomparable // candidates (disjoint UUIDs) can share a count, in which case comparePosition // returns 0 and leaves the decision to the next tiebreaker. Counting dominators // keeps the sort transitive-safe where a naive pairwise comparison is not; // findMostAdvanced still re-checks the winner after sorting.核心思路预计算每个候选被多少其它候选严格支配dominated count支配数越少越先进同时以 Combined已接收支配数优先、Executed已执行支配数次之兼顾复制延迟。计数排序避免了朴素两两比较在偏序下的传递性问题findMostAdvanced在排序后仍会复核胜者。nil-aliastablet未设置 alias 的候选被排除在排序之外避免空指针/无效排序参与主从切换决策。备份恢复与 mysql 协议层时间点恢复强制 UTCmysqlctl: force TZUTC for mysqlbinlog during point-in-time restore (#20463)进行基于 binlog 的时间点恢复PITR时mysqlbinlog进程强制以TZUTC运行。binlog 事件中的时间戳与本地时区无关若宿主环境时区非 UTCmysqlbinlog的时间过滤可能错位导致恢复到错误的时间点。强制 UTC 消除了时区依赖使恢复结果可复现、可预期。流式错误不再表现为连接断开go/mysql: streaming errors no longer surface as connection loss (#20383)流式查询过程中 MySQL 服务端返回的错误此前可能被上层误解为连接丢失connection loss而触发重连/报错修复后错误按正常流式错误传播语义更清晰go/mysql: send ERR instead of teardown after an OK carrying SERVER_MORE_RESULTS_EXISTS (#20563)当响应以SERVER_MORE_RESULTS_EXISTS标志的 OK 包开始时多结果集场景若后续出现错误客户端应发送 ERR 包而非直接关闭连接teardown保证多结果集协议交互的正确性。MySQL JSON 编码修复mysql/json: fix MarshalTo discarding accumulated output for nested blob and bit values (#20625)MarshalTo在编码嵌套的 blob 与 bit 类型值时此前可能丢弃已累积的输出缓冲导致 JSON 文档编码不完整本次修复保证累加缓冲正确保留。构建、依赖与安全加固Go 版本升级Docker 构建镜像中 Golang 升级到go1.25.12#20519与go1.25.13#20835引入工具链的 bug 修复与安全补丁CI 可靠性修复 mysql57 CI 中已移除的libtinfo5固定版本问题并快速失败#20481修复query_serving_queries_2change-detection 过滤器的自引用#20482下载archive.ubuntu.com时逐个尝试已解析 IP#20539CI 安全加固GitHub context 通过环境变量而非模板展开传给脚本#20784收紧 workflow token 权限与 checkout 凭据#20785app token 作用域限定到单个 step 而非导出到GITHUB_ENV#20786文档与维护移除内部未公开的 VRLog 功能#20467更新维护者与 code owner 项目列表#20772v23.0.6 代码冻结#20992测试基建修复 topo-flavor e2e 分片静默执行零测试的问题#20556避免 CI 假绿。升级建议与验证要点从 v23.0.x 升级到 v23.0.6 时建议重点关注以下行为变化并安排验证VReplication/VDiff涉及 SET 列尤其达到 64 个成员上限的表升级后建议对在途的 MoveTables/Reshard 任务执行VDiff复核数据一致性使用多列主键 过滤谓词的 VDiff 场景需回归验证。VTGate 表达式TO_BASE64输出57 字节整数倍输入、ROUND()浮点边界、ENUM 数值上下文的结果可能与旧版本不同涉及这些表达式的应用可先做差异对比。递归 CTE流式递归 CTE 现在同样受 1000 层深度上限约束超限会返回VT09030错误应用侧需确保递归查询有合理终止条件。txthrottler若使用target_replication_lag_sec1旧版本会 panic升级后可安全启用该配置。时间点恢复PITR 现在强制 UTC 语义跨时区环境的恢复行为更一致但脚本若依赖本地时区时间过滤需同步调整。总体而言v23.0.6 是一次质量沉淀型补丁版本没有新特性的大规模引入而是把 VReplication 数据流、evalengine 兼容性、复制切换排序、协议错误语义等核心路径上的边界问题逐一收敛。对于生产环境用户建议结合自身使用的功能模块优先验证上表所列场景后完成升级。【免费下载链接】vitessVitess is a database clustering system for horizontal scaling of MySQL.项目地址: https://gitcode.com/gh_mirrors/vi/vitess创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表