首页/新闻资讯/正文详情

Vitess 原子分布式事务设计解析:基于 2PC 的跨分片强原子提交架构

发布时间:2026/9/21 2:00:43 来源:云帆数科 栏目:资讯中心
Vitess 原子分布式事务设计解析:基于 2PC 的跨分片强原子提交架构
数据库分布式数据库云原生后端数据存储【免费下载链接】vitessVitess is a database clustering system for horizontal scaling of MySQL.项目地址https://gitcode.com/gh_mirrors/vi/vitess点击查看免费下载本设计文档doc/design-docs/AtomicDistributedTransaction.md定义了 Vitess 如何为跨分片、跨 keyspace 的分布式事务提供原子提交能力。传统的最佳努力提交BEC在提交中途发生故障时会导致部分分片已提交、部分分片未提交的半提交状态本文介绍的 Two-Phase Commit2PC实现通过无状态 CoordinatorVTGate与由参与者兼任的 Metadata ManagerMMVTTablet在保留单库事务零额外开销的前提下让分布式事务要么全部成功、要么全部回滚。读完本文你将掌握 DTID 的生成规则、Prepare/Commit/Rollback 全流程、MM 与 RM 的状态机、五种典型故障场景下的组件交互以及 2PC 在 PRS/ERS、MySQL 重启、Online DDL、MoveTables 等生产扰动下的保障机制。1. 背景为什么需要原子分布式事务Vitess 长期以来的分布式事务实现是Best Effort CommitBEC。应用可以在一个事务内向不同分片或不同 keyspace 发送 DML提交时 VTGate 逐个尝试提交各参与分片VTTablet上已开启的数据库事务。问题在于如果提交进行到一半时某个数据库宕机这部分提交就会丢失——最终出现部分提交数据完整性被破坏。此外随着 lookup vindex 等功能的引入VTGate 甚至会因为应用发出的单条语句自动展开出跨分片分布式事务例如一次 INSERT 同时写主表和 lookup 表这使得原子提交不再只是高级特性而是正确性的基本要求。Two-Phase Commit2PC是业界事实标准的原子提交协议但它长期被认为不实用且屡遭失败主要原因包括2PC 提交中途宕机的数据库会扣留其他数据库中的事务直到恢复——好在这一点如今已被复制与快速故障转移解决关系型数据库对 ACID 的严格要求让纯实现难以实际扩展工业标准分布式事务协议XA过度追求灵活性、报文过于繁琐chatty历史上一些事务管理方案设计拙劣要么附加开销过大要么流于形式反而破坏 2PC 的可靠性。MySQL 虽然支持 XA 协议但因大量 bug 而不可用。8.0 上虽有多次修复仍有大量 open bug生产环境几乎没有使用先例详见下文探索性工作一节的核实数据。本设计正是针对上述痛点以一组实用权衡practical trade-offs给出了 Vitess 自己的 2PC 实现。2. 设计总览对传统 2PC 的四处改造Vitess 在传统 2PC 算法之上引入了以下变体事务开始时无需声明参与 2PC。传统 API 往往要求应用在事务开始时就选定协议但这不是必须的。Vitess 中分布式事务以普通的Begin开始只有应用请求 2PC 提交时才被转换为 2PC 事务。这为大量常见场景保留了优化空间。把 Transaction Manager 拆分为两个角色Coordinator协调者无状态负责编排整个流程。VTGate 天然契合这一角色Metadata ManagerMM元数据管理器由某个 VTTablet 担任负责存储事务元数据并执行状态迁移。由于 VTTablet 本身已经是高可用HA的事务系统无需另建一套元数据存储。MM 参与者可跳过 Prepare 阶段。假设有 N 个参与者传统做法是 1→N 依次 Prepare、再 1→N 依次 Commit。若改为 Prepare 按 1→N、Commit 按 N→1则第 N 个数据库原本要依次执行 Prepare→Decide-to-Commit→Commit 三步。Vitess 的做法是把元数据状态迁移到 Decide to Commit所需的 DML作为应用事务的一部分一并执行并提交提交失败视为 Prepare 失败提交成功则视为三步全部成功。Prepare 功能基于事务系统实现详见第 5 节 Prepare API。上述组合保证了最常见的用例保持高效只影响一个数据库的事务因 2PC 引入的额外成本为零。对于多库事务则选择语句数最多的参与者作为 MM该库无需承担 Prepare 阶段开销也省去了单独持久化提交决策的额外事务。在源码中这一单参与者退化为普通提交的逻辑清晰可见go/vt/vtgate/tx_conn.go 的commit2PC()首先判断len(session.ShardSessions) 1若是则直接调用commitNormal()走普通提交路径。2.1 ACID 权衡核心 2PC 算法只保证Atomicity原子性要么整个事务提交要么完全回滚。Consistency一致性是正交属性由数据库保证值不违反关系规则Durability持久性由各数据库自身保证整体持久性由 2PC 流程继承Isolation隔离性需要额外工作分布式提交进行中若客户端读到部分提交的数据就会看到中间状态。传统做法是数据库对 2PC 涉及的行加读锁任何试图读取的人都必须等待事务终结——但这种锁的争用极其激烈往往抵消了数据分布带来的收益。实际上这种强度的隔离保证对大多数应用代码路径而言是过度设计。因此 Vitess 的取舍是为可扩展性放松隔离性把需要更强隔离的场景交给应用显式加锁而原子性不可妥协——非原子事务会导致部分提交、实质性地破坏数据这正是 2PC 要保证的。3. 一次 2PC 事务的完整生命周期一个 2PC 事务的生命周期如下应用向 VTGate 发起Begin此时会话被标记为处于事务中应用发送 DMLVTGate 在各个 VTTablet 上开启事务每个 VTTablet 的事务 idVTID被记录在会话中应用请求 2PC 提交。在此之前 2PC 与 BEC 没有任何区别——BEC 下 VTGate 只是向所有参与 VTTablet 发送 Commit2PC 下 VTGate 启动下述工作流。直到此阶段普通事务与 2PC 事务路径完全一致这也是单库事务零额外成本的另一层保证。3.1 Prepare 阶段生成Distributed Transaction IdentifierDTID将会话事务列表中第一个位置的 VTTablet指定为 MM向它发送CreateTransaction携带 DTID。这条记录会被事务解析监视器Transaction Resolution Watcher关注向所有其他 VTTabletRM发送PrepareDTID 作为请求的一部分一并发送。3.2 Commit 阶段对 MM 执行3-in-1动作Prepare-Decide-Commit即StartCommit将元数据状态迁移为Commit使用 DTID 向所有已 Prepare 的 VTTablet 发送CommitPrepared通过ConcludeTransaction删除 MM 中的事务记录。3.3 Rollback 阶段在提交决策被持久化之前的任何形式的失败都会导致回滚决策将元数据状态迁移为Rollback使用 DTID 向已 Prepare 的事务发送RollbackPrepared若原 VTGate 仍在编排则用各 VTID 回滚未 Prepare 的事务否则未 Prepare 的事务由事务杀手transaction killer负责回滚通过ConcludeTransaction删除 MM 中的事务记录。3.4 事务解析监视器Transaction Resolution Watcher如果某个事务在 MM 中滞留过久仍未解决事务解析监视器会介入。此时事务必处于以下三种状态之一PrepareRollbackCommit对状态 1、2启动回滚工作流对状态 3恢复提交工作流。3.5 MM 与 RM 的状态机以下两幅 Mermaid 状态图刻画了事务记录在 MM 与 RM 中的状态迁移状态迁移语义归纳事务通常从单个数据库事务开始对单库事务执行 2PC 提交会被当作普通提交处理一旦涉及多个 VTTablet事务就变为分布式事务。若应用发出 rollback所有参与者一律回滚对分布式事务的 2PC 提交启动新的提交流程事务记录以Prepare状态存储并在向各 RM 发出 Prepare 期间保持该状态若 Prepare 全部成功状态迁移为Commit。在 Commit 状态下只允许提交根据 Prepare 契约的保证所有数据库最终都会接受提交Prepare 阶段任何失败都会使状态迁移为Rollback该状态下只允许回滚。4. DTID 的生成与防碰撞目前事务 id 由 VTTablet 签发VTID且被视为**局部local**id。为了协调分布式事务、并让监视进程watchdog能拾起孤儿事务并将其解决到终态需要一套新的全局标识体系。DTID 生成规则取 MM 的 VTID并以 keyspace 和 shard 信息作为前缀防止碰撞。例如 MM 的 VTID 为1234、keyspace 为order、shard 为40-80则 DTID 为order:40-80:1234。源码实现在 go/vt/dtids/dtids.go 中完全对应// New generates a dtid based on Session_ShardSession. func New(mmShard *vtgatepb.Session_ShardSession) string { return fmt.Sprintf(%s:%s:%d, mmShard.Target.Keyspace, mmShard.Target.Shard, mmShard.TransactionId) }同一文件中的ShardSession(dtid)负责把 DTID 反解回Session_ShardSession含PRIMARYtablet 类型目标TransactionID(dtid)提取原始事务 id——它们是恢复、监视、工具等流程的公共基础。仍然存在的碰撞场景与对策若发生故障转移新 VTTablet 的起始 VTID 可能与旧实例用过 id 有重叠则仍可能碰撞。为此VTTablet 的起始 VTID 会被调整为一个高于任何已用 Prepared DTID 的值。5. Prepare APIVTTablet 侧Prepare API 由 VTTablet 提供本质上是三个函数Prepare、CommitPrepared、RollbackPrepared。其核心思想是在一个不原生支持 Prepare 的事务系统之上实现 Prepare即把需要预备提交的语句作为 redo 日志持久化下来事务连接则移入专门的 prepared 池等待最终决策。5.1 语句列表与状态每个事务必须记住自己的 DML 语句列表。VTTablet 已在按事务记录查询RecordQuery但当前记录的是请求的原始查询需要改为实际发给数据库的 DML。由于RecordQuery目前的用途主要是排障与诊断改成记录真实 DML 并不会损失价值反而更有用。5.2 Schemaredo 表以下两张表位于sidecar 数据库中所有时间戳以 unix 纳秒表示。redo_state表需支持以下用例Prepare创建行恢复与修复工具全表连接扫描拉取所有事务Resolve对指定 DTID 做状态迁移update where dtid :dtid and state :preparedWatchdog统计早于 X 的未解决事务select where time_created X删除已解决事务delete where dtid :dtid。create table redo_state( dtid varbinary(512), state bigint, // state can be 0: Failed, 1: Prepared. time_created bigint, message text, // record any error message. primary key(dtid) )redo_statement表是 redo 事务表的明细表需要能按正确顺序按 id读取某 dtid 的全部语句并能删除某 dtid 的所有语句create table redo_statement( dtid varbinary(512), id bigint, statement mediumblob, primary key(dtid, id) )5.3 Prepare该函数以 DTID 和 VTID 为输入执行取出活动事务连接移入prepared 池。若池已满事务被回滚并返回错误将元数据保存到 redo 日志作为一个独立事务。此步失败则主事务一并回滚并返回错误。关闭与降级语义VTTablet 被关闭或转为非 primary 时事务池处理器内部会回滚 prepared 事务并将其归还事务池。prepared 事务的回滚必须发生在所有打开事务被解决回滚或提交之后——因为回滚 prepared 事务会释放其持有的锁若此时仍有其他未杀掉的写事务在等待这些锁就可能趁虚而入导致数据损坏。若某个待处理事务正等待一个由 prepared 事务持有的锁它最终会超时并被回滚。故障转移后的恢复之后另一个 VTTablet 会被提升为 primary此时它会从 redo 日志重建未解决事务对应源码中的prepareFromRedo()。如果重放失败会发出告警但仍启动查询服务。正常情况下重放不应失败因为 VTTablet 在重放完成前不允许对数据库写入且任何外部代理都不应直接向 MySQL 写数据这是 Vitess 的一条宽约束。事务边界纪律VTTablet 总是以BEGIN-COMMIT包裹执行 DML确保连接被意外关闭时不会有 autocommit 语句漏网。5.4 CommitPrepared提交给定 DTID 的 prepared 事务从 Prepare 池取出事务若事务在failed 池中返回错误若事务未找到返回成功说明已被解决作为当前事务的一部分将 redo_log 中的状态迁移为 Committed 并提交事务失败时把错误信息记入redo_state并将事务移入 failed 池针对不可重试错误后续提交将永久失败把连接归还事务池。5.5 RollbackPrepared回滚给定 DTID 和 VTID 的 prepared/un-prepared 事务在独立事务中删除该 dtid 的 redo 日志条目从 Prepare 池取出事务若存在回滚并把连接归还事务池若提供了 VTID回滚原始事务。6. Metadata Manager APIMM 侧MM 功能同样由 VTTablet 提供。虽然可以做成独立服务但指定某个参与者兼任管理器能带来优化机会跳过 Prepare、合并决策事务。MM 支持的函数为CreateTransaction、StartCommit、SetRollback、ConcludeTransaction另有只读查询函数ReadTransaction、UnresolvedTransactions、ReadTwopcInflight。6.1 Schema事务元数据元数据由两张表组成需满足的用例CreateTransaction存储事务记录元数据状态迁移update where dtid :dtid and state :prepare解析流程select dt_state dt_participant where dtid :dtid事务解析监视器full table scan where time_created X删除已解决事务delete where dtid :dtid。create table dt_state( dtid varbinary(512), state bigint, // state PREPARE, COMMIT, ROLLBACK time_created bigint, primary key(dtid), key (time_created) )create table dt_participant( dtid varbinary(512), id bigint, keyspace varchar(256), shard varchar(256), primary key (dtid, id) )dt_participant记录了该分布式事务涉及的所有参与者keyspace shard是恢复与解析流程定位各 RM 的依据。6.2 CreateTransaction存储事务元数据记录初始状态为PREPARE。创建成功即启动 2PC 流程随后 VTGate 向其余参与者发出 Prepare。6.3 StartCommit当协调者已作出COMMIT决策时调用。恢复过程中的事务解析不会发起StartCommit调用因此可以假设该 VTTablet 的原始事务 VTID 仍然活跃取出给定 VTID 对应的连接在参与者事务VTID内部把事务状态从 PREPARE 迁移到 COMMIT发起提交并把事务归还事务池。成功则 VTGate 在其余参与者上执行提交决策失败则 VTGate 此时把事务解析交给监视器。6.4 SetRollback使用一个独立事务把状态从 PREPARE 迁移到 ROLLBACK。调用时 MM 的事务VTID可能仍然存活因此它会从 dtid 反推事务 id 并执行尽力而为best effort的回滚若事务未找到则视为 no-op。6.5 ConcludeTransaction删除给定 DTID 的事务元数据记录清理收尾。6.6 ReadTransaction / UnresolvedTransactions / ReadTwopcInflightReadTransaction返回给定 DTID 的事务元数据UnresolvedTransactions返回早于某个年龄阈值请求中指定或取 VTTablet 默认配置的所有未解决事务元数据ReadTwopcInflight返回全部事务元数据及 redo 语句日志。在 VTTablet 配置中未解决事务的默认年龄阈值由twopc-abandon-age控制默认值为 15 分钟见 go/vt/vttablet/tabletserver/tabletenv/config.go其TwoPCAbandonAge默认15 * time.Minutetwopc-enable旗标已废弃当前实现中 2PC 始终启用。7. Transaction CoordinatorVTGate 侧VTGate 本就负责 Best Effort Commit即transaction_modeMULTI自然可以扩展为 2PC 协调者只需支持transaction_modetwopc的提交。此外 VTGate 还需监听 VTTablet 的健康流health stream接收未解决事务信号并采取行动。7.1 Committransaction_modetwopc对一个活跃事务会话信息已知执行如下工作流指定一个 VTTablet 为 MM并基于 MM 的身份生成 DTID在 MM 上CreateTransaction在其余所有参与者上Prepare在 MM 上StartCommit在其余所有参与者上CommitPrepared在 MM 上ResolveTransaction即 Conclude。StartCommit 之前的任何失败都会触发回滚工作流在 MM 上SetRollback对所有已发出 Prepare 的参与者执行RollbackPrepared回滚其余所有参与者在 MM 上ResolveTransaction。上述编排在 go/vt/vtgate/tx_conn.go 的commit2PC()中按commitPhase枚举依次推进Commit2pcCreateTransaction→Commit2pcPrepare→Commit2pcStartCommit→Commit2pcPrepareCommit→Commit2pcConclude各阶段间的 Prepare 与 CommitPrepared 通过runSessions并发下发。失败时errActionAndLogWarn()依据所处阶段选择普通回滚 / 按 DTID 回滚 / 留待监视器解决并向会话记录包含 DTID 的警告ERInAtomicRecovery。7.2 Unresolved Transaction Signal未解决事务信号该信号由 MM 在存在未解决事务时经健康流发给 VTGate。处理函数首先在 VTTablet 上调用UnresolvedTransactions读取事务元数据再依据状态执行PrepareSetRollback并启动回滚工作流Rollback启动回滚工作流Commit启动提交工作流。提交工作流对所有参与者CommitPrepared然后在 MM 上ResolveTransaction。 回滚工作流对所有参与者RollbackPrepared然后在 MM 上ResolveTransaction。8. 组件交互五种典型场景以下序列图展示 2PC 提交在不同成败组合下的组件交互。图中G为 VTGate、MM为兼任元数据管理器的 VTTablet、RM1/RM2为其余参与 VTTablet。通用机制提交阶段任何错误都会以**警告标志warning flag**告知应用。应用事务收到警告后可执行show warnings查看该事务的分布式事务 ID再用show transaction status for dtid观察事务状态——这把失败兜底的主动权交还给了应用。Case 1所有组件都成功注意最后一步Delete Transaction Record被放在opt块中此时事务已提交删除元数据记录的失败不再影响返回给应用的响应。Case 2某个 RM 的 CommitPrepared 报错此时 watcher 服务需要解析该事务并提交遗留的 prepared 事务Case 3MM 上存储提交决策StartCommit报错此时无法确定提交决策是否已持久化必须交由 watcher 服务解析Case 4某个 Prepare 失败TM 决定回滚整个事务。若任一回滚失败则由 watcher 服务接管解决Case 5Create Transaction Record 失败事务尚未进入 2PC 状态TM 直接回滚全部参与者8.1 Transaction Resolution Watcher 的解决流程每个 primary VTTablet 会轮询自己的dt_state表查找滞留的分布式事务并通过健康流把存在未解决事务的信号发给 VTGate无状态的 VTGate 被视为短暂组件、随时可能失效这正是需要 watcher 的原因任何 VTGate 崩溃导致分布式提交进行到一半被遗弃时MM 的轮询 健康流信号 任意一个存活的 VTGate 接手就能把事务解决到终态。这与 go/vt/vttablet/tabletserver/tx_engine.go 中transition()到AcceptingReadAndWrite状态时调用startTransactionWatcher()的实现一一对应。9. 生产环境支持各类扰动下的原子性保障除功能本身外让 2PC 可投产还需要处理**扰动disruptions、监控monitoring、工具tooling与配置configuration**四大领域。本节梳理各扰动场景及其工程对策。9.1 PlannedReparentShard 与 EmergencyReparentShardPRS / ERS对于计划内与紧急重父reparent都会对主分片调用DemotePrimary。计划内重父要求该调用必须成功紧急重父时若主分片不可达该调用可以失败并继续推进。DemotePrimary流程中分片转入非服务状态时会等待所有事务完成对应TxEngine.shutdownLocked()中的te.txPool.WaitForEmpty()。若配置了关闭宽限期shutdown grace-period宽限期到后才会强制杀死所有运行中的查询然后回滚 prepared 事务。必须强调prepared 事务的回滚只能在其他所有写入都被杀掉之后进行——因为回滚 prepared 事务会释放其持有的锁若仍有冲突写入未杀干净它可能趁虚而入导致数据损坏该事务将无法再次 Prepare。相关代码见stateManager.terminateAllQueries()。新主分片通过PromoteReplica提升时会在允许任何新写入之前重做redo所有 prepared 事务TxEngine.RedoPreparedTransactions()见 go/vt/vttablet/tabletserver/tx_engine.go确保新主分片与旧主分片状态一致。若上述流程正常重做 prepared 事务没有理由失败。但若意外导致 Prepare 失败VTTablet 仍会接受新写入——决策是分片的可用性优先于个别的 2PC 事务同时会建设工具与指标通知用户处理这些失败。紧急重父还有个必须靠semi-sync半同步复制才能规避的坑由于DemotePrimary与StopReplicationAndBuildStatusMap并行执行可能出现主分片在所有副本停止复制之后才向 binlog 写入的情况。若无 semi-sync主分片可能提交一个 prepared 事务并向 VTGate 返回成功VTGate 据此判定事务安全并删除全部元数据但新主分片并未复制到该提交会重新 Prepare 该事务并永远等待一个不会到来的决策——事务将无限期卡在 prepared 状态。semi-sync 保证向调用方确认成功的写入必然已复制到至少一个副本从而保证事务在新主分片上必然已提交。9.2 MySQL 重启MySQL 重启会丢失所有进行中的事务包括全部 prepared 事务——因为事务日志在重启间不持久化这是 MySQL 的限制、无法绕开。但 Vitess 层必须保证即使 MySQL 重启prepared 事务也能被成功提交。VTTablet 有检测 MySQL 故障的代码stateManager.checkMySQL()会把分片转为NotConnected状态阻止任何写入直到恢复服务。但不能依赖 checkMySQL 挡住冲突写入从 MySQL 重启到 VTTablet 转为 NotConnected 之间存在时间窗期间 VTTablet 仍接受写入其中某些可能与 prepared 事务冲突。对策依赖这样一个事实MySQL 重启后以 super-read-only 启动因此不会有写入发生。由 VTOrc 将此登记为问题并通过UndoDemotePrimary修复在把 MySQL 置为 read-write 之前先在 read_only 状态下重做全部 prepared 事务使用具有管理权限的dba 池。这是安全的因为在置为 read-write 前不会有冲突写入。相关代码见TabletManager.redoPreparedTransactionsAndSetReadWrite()。为什么选择在super-read-only → read-write迁移时总是检查并重做处理 MySQL 重启是引入该逻辑的唯一理由。虽然严格来说只需在UndoDemotePrimary中做但把 MySQL 置为 read-write 的不一定是 VTOrc——用户可能手动调用SetReadWrite。因此最稳妥的做法就是每当 MySQL 从 super-read-only 迁移到 read-write 状态时都检查是否需要重做 prepared 事务。9.3 VTTablet 重启VTTablet 重启后所有既有连接丢失先以非服务状态启动读取 topo 中的 shard 与 tablet 记录后才转为服务状态。作为该转换的一部分必须在接受任何写入之前重做 prepared 事务——这发生在TxEngine.transition函数迁移到AcceptingReadWrite状态时复用与 MySQL 重启、PRS、ERS 相同的重做代码见 go/vt/vttablet/tabletserver/tx_engine.go 中transition()的te.redoPreparedTransactionsLocked()分支注释明确说明这是为了处理 vttablet 重启场景。9.4 VTGate 重启无需额外工作。原子事务会基于 MM 中记录的最后已知状态自动恢复并触发未解决事务工作流。9.5 Online DDLOnline DDL 切换cutover前必须保证在线 DDL 表上的所有 prepared 事务已完成——因为切换涉及 schema 变更不能存在依赖旧 schema 的 prepared 事务。切换过程中Online DDL 会添加查询规则query rules缓冲buffer针对该表的新查询检查表上是否存在打开的 prepared 事务若有则等待最多 100ms 后再次检查若无该表的 prepared 事务则继续切换否则失败由 Online DDL 机制稍后重试。Prepare 代码中则双向设防在把事务加入 prepared 列表前检查查询规则在把事务日志写入 redo 表前再次检查规则。通过第一次检查的事务若切换已推进会在第二次检查失败。两侧的检查保证要么切换不进行要么事务不被 Prepare。9.6 MoveTablesMoveTables工作流中唯一需要与原子事务同步的步骤是写入的SwitchTraffic。目标是对涉及的表禁用写入使用ShardInfo中的DeniedTables实现。更新 topo 中的DeniedTables后使所有 VTTablet 刷新 topo 以确保已登记变更。VTTablet 侧用DeniedTables添加查询规则与 Online DDL 类似区别在于Online DDL 是缓冲查询SwitchTraffic则直接拒绝。新增的查询规则阻止任何新的原子事务被 Prepare。随后尝试锁定表以确保没有进行中的写入——此步骤会阻塞直到所有打开的 prepared 事务完成。此后SwitchTraffic即可安全推进在DeniedTables复位前新原子事务必然被拒且已获取表锁说明当前无写入进行。10. 监控与工具10.1 VTTablet 侧指标Transactions层次扩展报告CommitPrepared与RollbackPrepared统计含直方图Prepare 是中间步骤不并入该变量新增两个 Prepare 相关变量Prepare直方图报告 prepare 耗时PrepareStatements直方图报告每次 Prepare 的语句条数UnresolvedTransactiongauge报告ResourceManager或MetadataManager中当前未解决的打开事务数任何CommitPrepared或RedoPrepared失败都会使对应的CommitPreparedFail/RedoPreparedFail计数器区分可重试/不可重试错误递增不可重试错误应触发告警2PC 过程中的任何意外错误都会递增InternalErrors计数器该计数器已配置为触发告警。10.2 VTGate 侧指标Transactions报告提交模式耗时直方图Single单分片、Multibest-effort 多分片、TwoPC2PC 多分片2PC 事务额外报告CommitUnresolved所有 RM 上 Prepare 完成后的失败次数Participant用于统计多分片事务的平均分片数。在源码中提交模式的直方图记录位于 go/vt/vtgate/tx_conn.go 的recordCommitTime()len(ShardSessions) 1记Singletwopc 记TwoPC其余记Multi。10.3 工具VTAdmin Transactions 页VTAdmin 的Transactions页签会列出所有未解决的 2PC 事务并提供修改 abandon 年龄abandon age的选项以限定早于指定时间的未解决事务。目前可对这些事务执行的动作是Conclude——它会清除所选事务在所有分片上的状态记录。当前长时间滞留且事务解析器无法完成的事务仍需用户采取人工纠正措施相关后端实现可参考 go/vt/vtadmin/http/transactions.go。此外VTTablet 提供/twopcz调试页面见 go/vt/vttablet/tabletserver/twopcz.go分别展示 Failed Transactions、Prepared Transactions、Distributed Transactions 三类事务并支持 Discard、Rollback、Commit 等人工操作可作为生产排障的补充手段。11. 数据保证无法避免的极端风险上述工作流总体可靠但仍依赖底层系统的数据保证以及prepared 事务只会随 VTTablet 一起被杀这一前提。以下场景存在不可恢复的数据丢失的可能——系统必须正确告警并尽力恢复后继续前进。目前这些场景需要运维介入随着系统获得信心未来可自动化。11.1 prepared 事务被外部杀掉外部代理可能杀掉 prepared 事务的连接MySQL 将回滚它。若系统正承载实时流量可能向前推进到该事务无法重放或以不同结果重放的状态。这非常罕见但一旦发生协调者发现事务缺失时会告警该事务被标记为Failed直到运维解决。但若在标记 Failed 之前发生故障转移它会在后续事务中被复活且可能携带错误变更——这种失败无法被检测。11.2 事务恢复重放的可靠性当前实现把事务恢复日志存为DML 语句。恢复时应用这些语句不应失败因为既有的关闭/启动流程保证没有其他 DML 泄漏进数据库。但仍存在重放期间语句失败的风险可能导致修改丢失且无法追踪具体哪些行被改。若发生此类情况会告警需运维介入排查。12. 测试计划2PC 主流程本身简单易测复杂的是各类故障模式。测试分为以下层级基础测试Basic Tests事务的提交或回滚以及 Prepare 失败引发事务回滚的处理可靠性测试Reliability Tests持续数天至一周的长时运行经历各种场景不同组件故障VTGate、VTTablet、MySQL、重父PRS 与 ERS、重新分片Resharding、Online DDL 操作模糊测试Fuzzy Tests持续运行多分片事务流在终止长时测试时断言事件必须处于特定序列压测Stress Tests持续执行单分片与分布式事务流记录所有成功提交及其预期行持续流式读取 binlog 事件对照变更流顺序与成功事务进行校验。13. 创新点总结本设计包含一系列创新想法其中部分可能在其他场景或 2PC 本身已被用过要点如下抛弃重量级的 XA 标准在不原生支持 Prepare 的系统之上实现 Prepare 功能把元数据存放在事务引擎中使协调者保持无状态把元数据存放在某个参与者上省去该参与者的 Prepare 开销在保持原子性的前提下放宽隔离性保证。14. 未来增强方向读隔离保证Read Isolation Guarantee当前系统缺乏隔离保证负担在应用侧。实现读隔离将带来真正的跨分片 ACID 事务分布式死锁避免Distributed Deadlock Avoidance当前系统可能遇到跨分片死锁只能靠某个事务超时回滚来解决。实现分布式死锁避免可更高效地处理这一问题。15. 附录15.1 术语表Distributed Transaction分布式事务任何跨多个数据库的事务。该词不暗示任何提交协议Best Effort CommitBEC最佳努力提交Vitess 目前支持的协议向所有参与者发送提交过程中若失败可能出现部分提交Two-Phase Commit2PC两阶段提交保证原子分布式提交的协议Coordinator协调者负责发起、恢复并完成 2PC 事务的无状态进程由 VTGate 担任Resource ManagerRMaka Participant参与者参与分布式事务的任何数据库只有 VTTablet 能作为参与者Metadata ManagerMM元数据管理器负责存储元数据并执行状态迁移的数据库Vitess 中由某个参与者兼任Watchdog监视器寻找被遗弃的事务并发起解决流程的组件Distributed Transaction IDDTID2PC 事务的唯一标识符VTTablet transaction idVTID每个 VTTablet 参与者上、包含应用待提交/回滚语句的独立事务 idDecision决策提交或回滚的不可逆决定。虽然容易混淆但也被称为Commit Decision文中也会间接称为Metadata state transition——因为事务经历多次状态变化而 Decision 是关键迁移值得单独命名。15.2 探索性工作为什么不直接用 MySQL XAMySQL XA 曾被考虑作为由 RM 管理事务恢复日志并持有行锁直到提交或回滚的替代方案。但 XA 目前有超过 20 个 open bug在 MySQL 8.0.33 上按复现步骤逐一验证后仍有 8 个可以复现其中 4 个有补丁可解决其余 4 个需要改代码或工作流才能解决。XA 的 chatty API 以及没有已知的大规模生产部署是 Vitess 最终未采用它的原因。若未来自研方案遇到 XA 能解决的问题MySQL XA 仍是一个候选。赞分享数据库分布式数据库云原生后端数据存储【免费下载链接】vitessVitess is a database clustering system for horizontal scaling of MySQL.项目地址https://gitcode.com/gh_mirrors/vi/vitess点击查看免费下载相关推荐JPEGView图像查看器完整指南轻松掌握Windows平台高效看图技巧JPEGView图像查看器完整指南轻松掌握Windows平台高效看图技巧 JPEGView是一款专为Windows系统设计的高性能图像查看和编辑工具以其轻量桌面应用图像处理Komodo分布式事务确保跨服务器操作的原子性Komodo分布式事务确保跨服务器操作的原子性 在分布式系统中跨服务器操作的一致性一直是技术团队面临的核心挑战。当业务流程需要同时修改多台服务器上的数据时DevOps容器编排CI/CD运维Vitess v22.0.0 发布说明深度解读MySQL 8.0.40、原子分布式事务与 VReplication 全面进化Vitess v22.0.0 发布说明深度解读MySQL 8.0.40、原子分布式事务与 VReplication 全面进化 本篇文章基于仓库 changel数据库分布式数据库云原生后端数据存储上一篇终极指南3步解锁Angular Material图标自定义从基础到高级扩展下一篇CVAT部署从零到交付标注数据的完整流水线五步走创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

LibreChat:开源多模型聊天中控台与MCP Agent实战指南
LibreChat:开源多模型聊天中控台与MCP Agent实战指南

1. LibreChat 是什么?一个真正能落地的开源聊天界面,不是玩具LibreChat 是一个开源、自托管、高度可定制的聊天界面项目,它的核心定位非常清晰:做 OpenAI、Gemini、Claude 等主流大模型 API 的“统一操作台”。它不训练模型&#… · 2026/9/21 1:59:43

nRF52832+RFX2401C实现蓝牙远距离通信的射频链路设计
nRF52832+RFX2401C实现蓝牙远距离通信的射频链路设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 1:59:43

react-admin 表单 Mutation Middleware 深度解析:用 `useRegisterMutationMiddleware` 拦截 create/update 保存流程
react-admin 表单 Mutation Middleware 深度解析:用 `useRegisterMutationMiddleware` 拦截 create/update 保存流程

前端UI组件 【免费下载链接】react-admin A frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design 项目地址: https://gitcode.com/gh_mirrors/re/react-admin 点击查看 免费下载 react-ad… · 2026/9/21 1:59:43

AFSIM源码编译实战:从环境配置到二次开发全流程解析
AFSIM源码编译实战:从环境配置到二次开发全流程解析

我最早接触AFSIM的时候,和大多数人一样,直接下载官方预编译工具包,装上就能跑通示例,感觉门槛并不高。真正让我决定从头编译一遍的,是一次二次开发需求:我需要在仿真框架内部挂一个自定义消息处理逻辑&… · 2026/9/21 2:45:51

Apex One 远程代码执行漏洞应急处理与加固实战指南
Apex One 远程代码执行漏洞应急处理与加固实战指南

上周看到趋势科技发布的 Apex One 安全公告时,我正坐在客户那边做季度巡检。说实话,终端安全产品的“代码执行漏洞”和普通业务系统的远程代码执行,处理起来的压力完全不在一个量级。Apex One 是很多企业的主力端点防护平台,管理界… · 2026/9/21 2:45:51

clap Builder API 教程:用 Command 配置命令行解析器(名称、版本与 Cargo.toml 元数据)
clap Builder API 教程:用 Command 配置命令行解析器(名称、版本与 Cargo.toml 元数据)

CLI开发工具 【免费下载链接】clap A full featured, fast Command Line Argument Parser for Rust 项目地址: https://gitcode.com/gh_mirrors/cl/clap 点击查看 免费下载 本文是 clap 官方 Builder API 教程系列中“Configuring the Parser(配置解析器… · 2026/9/21 2:45:51

STM32+WiFi+云平台的光感智能台灯闭环控制系统
STM32+WiFi+云平台的光感智能台灯闭环控制系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 2:45:51

STM32F103工业级水质检测系统:从原理图到现场排故的完整工程包
STM32F103工业级水质检测系统:从原理图到现场排故的完整工程包

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 2:45:51

STM32智能家居控制系统设计:从硬件选型到软件实现全解析
STM32智能家居控制系统设计:从硬件选型到软件实现全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 2:44:51

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39

Word表格编号全攻略:从列表编号到题注交叉引用
Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39

从第一个站到第二个站:独立开发者的静态网站选型与落地实践
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41

Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行
Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 0:00:18

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码