0
0
1
0
博客/.../

TiDB 分布式事务深度解析

 菩提老祖  发表于  2026-06-29

基于 TiDB 官方 v8.x / v7.1.x


目录


一、什么是分布式事务

分布式事务是指在分布式数据库中,事务的参与者、资源管理器、事务管理器分布在不同的物理节点上,它们需要通过网络通信协同工作,共同保证事务的 ACID 特性。

核心挑战

挑战 说明
网络不可靠 节点间通信可能延迟、丢包、乱序
节点可能故障 任一参与节点可能在事务执行中宕机
时钟不一致 不同节点难以精确同步时钟
数据跨节点分布 一个事务涉及的数据可能分布在多个物理节点上

TiDB 的解决思路

"对用户完全透明"——开发者和使用单机 MySQL 一样写 BEGIN / COMMIT / ROLLBACK,底层自动处理跨节点的数据一致性。

-- 和单机 MySQL 完全相同的语法
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;  -- TiDB 自动保证跨 Region、跨 TiKV 节点的原子提交

二、核心架构

分布式事务的实现依赖于 TiDB 的三层架构协同工作。

┌──────────────────────────────────────────────────────────┐
│                     TiDB Server                          │
│                       (SQL 层)                            │
│  ┌────────────────────────────────────────────────────┐  │
│  │ • SQL 解析与执行计划生成                            │  │
│  │ • 作为 2PC 协调者(Coordinator)                     │  │
│  │ • 与 PD 交互获取 TSO 时间戳                          │  │
│  │ • 缓存写入,commit 时统一提交                        │  │
│  └────────────────────────────────────────────────────┘  │
└────────────────────────┬─────────────────────────────────┘
                         │ gRPC 通信
┌────────────────────────▼─────────────────────────────────┐
│             PD — Placement Driver                         │
│  ┌────────────────────────────────────────────────────┐  │
│  │ • 全局授时服务(TSO — Timestamp Oracle)            │  │
│  │ • 管理 Region 分布与元数据                           │  │
│  │ • 执行调度策略(Leader 均衡 / Region 均衡)          │  │
│  └────────────────────────────────────────────────────┘  │
└────────────────────────┬─────────────────────────────────┘
                         │
┌────────────────────────▼─────────────────────────────────┐
│                   TiKV (存储层)                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │ • 分布式 KV 存储,数据按 Range 切分为 Region         │  │
│  │ • 每个 Region 使用 Raft 维护 3 副本                  │  │
│  │ • 每个 Region 有一个 Leader 负责读写                  │  │
│  │ • 执行 prewrite / commit / pessimistic lock 等操作    │  │
│  │ • 使用 RocksDB 进行本地持久化                        │  │
│  └────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────┘

各层的事务职责

组件 事务中的角色
TiDB Server 2PC 协调者(Coordinator):获取 TSO、执行 prewrite 和 commit、处理冲突与重试
PD 全局授时服务:分配全局唯一单调递增的时间戳(TSO)
TiKV 事务参与者(Participant):执行具体的数据写入、锁管理、MVCC 版本控制

三、技术基石:Percolator 模型

TiDB 的事务模型源自 Google Percolator(Google 在 BigTable 之上实现的事务系统),并做了大量工程优化。

核心思想

已有的分布式 KV 存储之上增加事务层,提供跨行、跨表的事务能力。

四大机制

┌──────────────────────────────────────────────────────────┐
│                 Percolator 事务模型                        │
│                                                          │
│    TSO 全局时钟  ←───  为每个操作分配全局唯一时间戳      │
│         │                                                │
│         ▼                                                │
│    MVCC 多版本    ←───  每个 Key 保存多个版本历史         │
│         │                                                │
│         ▼                                                │
│  Primary Key 机制 ←───  事务状态以 Primary 为准           │
│         │                                                │
│         ▼                                                │
│  两阶段提交 2PC  ←───  Prewrite + Commit 两阶段           │
│                                                          │
└──────────────────────────────────────────────────────────┘

TSO(Timestamp Oracle)全局时间戳

PD 提供一个全局唯一、单调递增的时间戳服务。

-- 查看当前事务的 start_ts
BEGIN;
SET @ts := @@tidb_current_ts;
SELECT @ts;
-- 返回示例:443852055297916932
ROLLBACK;

TSO 的组成:

TSO = 物理时间(毫秒) + 逻辑时间(同毫秒内计数器)
      └───── 高 46 位 ────┘ └───── 低 18 位 ─────┘
  • 开启事务时,TiDB 从 PD 获取 TSO 作为 start_ts
  • 提交时获取 commit_ts
  • 所有读写基于这些时间戳,实现快照隔离

解码 TSO:

-- TiDB 内置函数
SELECT TIDB_PARSE_TSO(443852055297916932);
-- 返回物理时间
SELECT TIDB_PARSE_TSO_LOGICAL(443852055297916932);
-- 返回逻辑计数器

MVCC 多版本并发控制

每个 Key 在 TiKV 中存储多个版本,通过时间戳区分:

Key "A" 在 TiKV 中的存储(逻辑视图):

Key_A @ ts=50  → Value "v3"  ← 当前最新版本
Key_A @ ts=30  → Value "v2"
Key_A @ ts=10  → Value "v1"
  • 事务读取时以 start_ts 为快照点,读取 <= start_ts 的最新版本
  • 写入时创建新版本,不覆盖旧数据
  • 旧版本由 GC 定期清理

Primary Key 机制

每个分布式事务选择一个 Key 作为 Primary Key,它是事务状态的权威标志

Primary Key 状态 事务整体状态
已提交(存在 commit 记录) 已提交
未提交(只有 prewrite 锁) 未完成

为什么需要 Primary Key?

当 TiDB Coordinator 在 2PC 过程中崩溃,或者某个 TiKV 节点出现锁残留时,其他节点通过检查 Primary Key 的状态就能唯一确定该事务应该提交还是回滚。这就是 Resolve Locks 机制的基础。


四、两阶段提交(2PC)详解

这是 TiDB 分布式事务的核心流程。下面以乐观事务为例,逐步拆解。

整体流程概览

┌─────────────────────────────────────────────────────────────────────┐
│                        事务执行全流程                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐        │
│  │ BEGIN  │───▶│  执行 SQL │───▶│ 2PC Phase1│───▶│ 2PC Phase2│       │
│  │获取TSO  │    │  缓存写入 │    │ Prewrite │    │  Commit   │       │
│  └────────┘    └──────────┘    └──────────┘    └──────────┘        │
│                                       │              │              │
│                         ┌─────────────┘              │              │
│                         ▼                            ▼              │
│                    start_ts 写入数据           commit_ts 确认提交     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

阶段一:Prewrite(预写)

TiDB (Coordinator)                     TiKV (Participants)
      │                                      │
      │  ① 选择一个 Key 作为 Primary Key      │
      │  ② 按 Region 分组所有待写入 Key       │
      │                                      │
      │  ③ prewrite(primary_key, start_ts)   │
      ├─────────────────────────────────────►│ 先写入 Primary
      │◄─────────────────────────────────────│ 成功
      │                                      │
      │  ④ prewrite(keys, primary, start_ts) │
      ├─────────────────────────────────────►│ 并发写入所有 Secondary
      ├─────────────────────────────────────►│
      ├─────────────────────────────────────►│
      │◄─────────────────────────────────────│ 全部成功
      │                                      │
      │  ✓ 所有 prewrite 成功,进入阶段二     │

Prewrite 检查什么?

TiKV 在 prewrite 时会检查目标 Key:

  1. 是否存在其他事务的锁(Lock)—— 有则等待或冲突
  2. 是否有更新的已提交数据(data.commit_ts > txn.start_ts)—— 有则返回 Write Conflict
  3. 验证 Schema 版本是否一致

阶段二:Commit(提交)

      │                                      │
      │  ⑤ 从 PD 获取 commit_ts              │
      │  ──── PD ──────────────────────────►  │
      │                                      │
      │  ⑥ commit(primary_key, commit_ts)    │
      ├─────────────────────────────────────►│ 先提交 Primary
      │◄─────────────────────────────────────│ 成功!
      │                                      │
      │  ⭐ 返回客户端 "SUCCESS"              │
      │  ──── 外部可见 ────────────────────►  │
      │                                      │
      │  ⑦ commit(secondary_keys, commit_ts) │
      ├─────────────────────────────────────►│ 异步并发 Secondary
      ├─────────────────────────────────────►│
      ├─────────────────────────────────────►│

关键设计要点:

要点 说明
先提交 Primary Primary Key 的成功提交即代表整个事务提交。这是事务原子性的核心保证
先返回成功,再提交 Secondary 一旦 Primary 提交成功,立即返回客户端成功,Secondary 异步提交
异步容错 Secondary 即使提交失败,后续 GC 或 Resolve Locks 也会根据 Primary 的状态补全
并发执行 Prewrite 和 Commit 阶段都按 Region 分组后并发执行

为什么先提交 Primary Key?

这是 Percolator 模型的精妙设计:

场景:Coordinator 在提交 Primary 成功、但 Secondary 还未全部提交时崩溃

恢复后:
  TiKV-1(Primary已提交) → "事务已提交,继续提交 Secondary"
  TiKV-2(Secondary尚在prewrite) → "检查 Primary 状态 → 已提交 → 补提交"
  TiKV-3(Secondary未响应) → "检查 Primary 状态 → 已提交 → 补提交"

最终:所有 Secondary 都被补全提交,原子性得到保证。

相反,如果 Secondary 都提交了但 Primary 未提交,其他节点通过检查 Primary 会判定事务未完成,从而回滚所有 Secondary —— Primary 永远是正确的答案

完整时序图

 ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
 │ Client  │     │  TiDB   │     │   PD    │     │  TiKV   │
 └────┬────┘     └────┬────┘     └────┬────┘     └────┬────┘
      │               │               │               │
      │  BEGIN        │               │               │
      ├──────────────►│  get start_ts  │               │
      │               ├──────────────►│               │
      │               │◄──────────────┤               │
      │               │               │               │
      │  SQL 执行阶段  │               │               │
      ├──────────────►│               │               │
      │  (读写操作)    │    get/lock   │               │
      │               ├──────────────────────────────►│
      │               │◄──────────────────────────────┤
      │◄──────────────┤               │               │
      │               │               │               │
      │  COMMIT       │               │               │
      ├──────────────►│               │               │
      │               │               │               │
      │    ── 2PC 开始 ──             │               │
      │               │  选择 Primary  │               │
      │               │  按Region分组  │               │
      │               │               │               │
      │  ── Phase 1: Prewrite ──      │               │
      │               │ prewrite(PK)   │               │
      │               ├──────────────────────────────►│
      │               │◄──────────────────────────────┤
      │               │ prewrite(SKs)  │               │
      │               ├──────────────────────────────►│
      │               ├──────────────────────────────►│(并发)
      │               │◄──────────────────────────────┤
      │               │               │               │
      │  ── Phase 2: Commit ──        │               │
      │               │ get commit_ts  │               │
      │               ├──────────────►│               │
      │               │◄──────────────┤               │
      │               │               │               │
      │               │ commit(PK)    │               │
      │               ├──────────────────────────────►│
      │◄══════════════┤════ 成功 ════ │               │  ← 此时返回
      │               │               │               │
      │               │ commit(SKs)   │               │  ← 异步提交
      │               ├──────────────────────────────►│
      │               ├──────────────────────────────►│(并发)
      │               │               │               │

1PC / Async Commit 优化

v4.0+ 引入了 1PC 和 Async Commit 优化:

模式 说明 适用场景
2PC 标准的两阶段提交(prewrite + commit) 跨 Region 的通用写入
1PC 只需一次 RPC,跳过 prewrite 阶段直接提交 单 Region 事务
Async Commit Prewrite 后不等待所有 Secondary 确认就返回 延迟敏感的业务

TiDB 会根据事务涉及的 Region 数量自动选择合适的提交路径。


五、乐观事务 vs 悲观事务

TiDB 从 v3.0.8 起同时支持两种事务模式,这是 TiDB 事务体系的重要演进。

对比总览

对比维度 乐观事务(Optimistic) 悲观事务(Pessimistic)
加锁时机 仅在 commit 时的 prewrite 阶段检查冲突 DML 执行时就对目标行加悲观锁
冲突处理 提交时检测到冲突 → Write Conflict 错误 → 整个事务重试 写入即阻塞等待,类似 MySQL InnoDB
重试成本 高(事务整体重试,需要清理旧锁) 低(只需等待锁释放)
适用场景 低冲突、批量写入、分析型负载 高并发 OLTP、秒杀、热点更新
锁开销 几乎为零(无锁) 有锁维护成本
死锁检测 不存在死锁 支持死锁检测(Error 1213)
默认模式 v3.0.8 之前默认 v3.0.8 起推荐默认

乐观事务流程

BEGIN (获取 start_ts)
  │
  ▼
SQL 执行(全部缓存到内存,不与 TiKV 交互)
  │
  ▼
COMMIT(触发 2PC)
  ├─ Prewrite → 检查冲突
  │               ├─ 无冲突 → Commit → 成功
  │               └─ 有冲突 → Write Conflict Error
  │                           → 自动获取新 start_ts 重试(如果开启)
  └─ 重试限制:tidb_retry_limit(默认 10 次)

Write Conflict 日志示例:

[WARN] [session.go:446] ["commit failed"]
[error="[kv:9007]Write conflict,
 txnStartTS=416617006551793665,
 conflictStartTS=416617018650001409,
 conflictCommitTS=416617023093080065,
 key={tableID=47, indexID=1, indexValues={string, }}
 primary={tableID=47, indexID=1, indexValues={string, }}
 [try again later]"]

悲观事务流程

BEGIN (获取 start_ts)
  │
  ▼
DML 执行
  ├─ 对目标行加悲观锁
  │     ├─ 无冲突 → 锁定成功,在内存中缓存修改
  │     └─ 有冲突 → 等待锁释放(超时阈值:innodb_lock_wait_timeout)
  └─ 加锁成功后继续执行
  │
  ▼
COMMIT
  ├─ 触发 2PC(Prewrite + Commit)
  └─ 释放所有锁

配置方式:

-- 全局切换为悲观事务
SET GLOBAL tidb_txn_mode = 'pessimistic';

-- 单事务指定
BEGIN PESSIMISTIC;
-- 或
BEGIN /*T! PESSIMISTIC */;

-- 查询当前模式
SELECT @@tidb_txn_mode;

Pipelined 悲观锁(v4.0.9+)

TiDB         TiKV Leader        TiKV Follower
 │               │                    │
 │  Lock(key)    │                    │
 ├──────────────►│  异步 Raft 复制    │
 │◄══════════════│══════ 立即返回 ═══►│  ← 不等 Raft 落盘就返回
 │               ├───────────────────►│  异步复制日志
 │               ├───────────────────►│
  • 效果:获取悲观锁的延迟从 Raft 持久化延迟降低到内存级延迟
  • 配置:TiKV 的 [pessimistic-txn] pipelined = true(v4.0.9+ 默认开启)

In-Memory 悲观锁(v6.0.0+)

更进一步,悲观锁直接在 Region Leader 内存中完成,完全不写盘:

  • Region Leader 内存中维护锁表
  • 只有当内存锁表满时才 fallback 到磁盘模式
  • 大幅降低悲观锁的 P99 延迟

如何选择

工作负载 推荐模式 原因
OLTP 高并发短事务 悲观事务  避免 Write Conflict 重试,延迟稳定
秒杀/热点更新 悲观事务  保证更新顺序,不会反复重试
批量 ETL/导入 乐观事务  减少加锁开销,冲突概率低
纯分析查询 两者均可 只读事务无冲突
不确定的场景 悲观事务  行为与 MySQL 一致,兼容性最好

六、事务隔离级别

默认隔离级别:可重复读(Repeatable Read)

TiDB 的 REPEATABLE READ 基于 Snapshot Isolation(快照隔离) 实现,实际上比 ANSI SQL 标准更强:

异常现象 ANSI RR MySQL RR TiDB RR
脏读(Dirty Read)
不可重复读(Fuzzy Read)
幻读(Phantom) 可能 ✓ 可能 ✓ ✗ 不会发生 

为什么 TiDB 不会幻读?

因为所有读取都基于事务开始时的 start_ts 快照。无论其他事务何时插入新行,当前事务的快照中"看不到"它们。

读已提交(Read Committed)

-- 设置当前会话
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • v4.0.0-beta 开始支持
  • 每个语句能看到最新的已提交数据
  • 行为类似 Oracle / PostgreSQL 的 Read Committed

优化手段:

系统变量 作用 引入版本
tidb_rc_read_check_ts SELECT 语句避免每次请求最新 TSO v6.0.0
tidb_rc_write_check_ts 减少 DML 写冲突检查次数 v6.3.0

隔离级别矩阵

-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

注意: TiDB 不支持 READ UNCOMMITTED 和 SERIALIZABLE 级别,设置时会降级为 REPEATABLE READ 或 READ COMMITTED

MySQL 兼容性差异

特性 MySQL InnoDB TiDB
Gap Locking(间隙锁) 支持 不支持
SELECT LOCK IN SHARE MODE 支持 需开启 tidb_enable_noop_functions
START TRANSACTION WITH CONSISTENT SNAPSHOT 支持 无实际效果
FOR UPDATE NOWAIT MySQL 8.0+ 支持(Error 3572)
死锁检测(Error 1213) (悲观模式)

七、ACID 保证

原子性(Atomicity)

保证机制:2PC + Primary Key + Resolve Locks

                ┌─ Primary Key 已提交 ──▶ 补全提交所有 Secondary
                │
  残留锁发现 ───┤
                │
                └─ Primary Key 未提交 ──▶ 回滚所有 Secondary
  • Partition 1:2PC 确保所有参与者要么全部 prewrite 成功,要么全部回滚
  • Partition 2:Coordinator 崩溃后,其他节点通过 Primary Key 决议
  • Partition 3:GC 过程中的 Resolve Locks 阶段自动清理残留事务

一致性(Consistency)

保证机制:SQL 层约束 + KV 层一致性

层面 保证内容
TiDB SQL 层 唯一键约束、外键约束、CHECK 约束检查
TiDB DDL 层 Online Schema Change,DML 与 DDL 不会冲突导致数据损坏
TiKV 层 Raft 协议保证所有副本数据最终一致

隔离性(Isolation)

保证机制:MVCC + TSO 时间戳

  • 每个事务读取自己 start_ts 时刻的一致性快照
  • 写入通过 2PC 的 prewrite 阶段进行冲突检测
  • 悲观模式下通过锁机制保证写写隔离

持久性(Durability)

保证机制:Raft 共识协议

Client → TiKV Leader → 写入 Raft Log
                     → 同步到多数派 Follower(至少 2/3)
                     → 返回成功给 Client
                     → 异步应用到 RocksDB
  • 数据写入 必须同步到多数派副本才算成功
  • 即使部分 TiKV 节点宕机,数据不丢失
  • Raft Log 和实际数据都持久化在 RocksDB 文件中

八、垃圾回收(GC)

GC 是分布式事务的"保洁员",负责清理 MVCC 产生的历史版本。

GC 流程

TiDB GC Leader 驱动(10 分钟一次,默认)

  ┌─ 1. Resolve Locks(解决残留锁)
  │    扫描 safe point 之前的残留锁
  │    通过检查 Primary Key 状态,提交或回滚过期事务
  │
  ├─ 2. Delete Ranges(删除废弃数据范围)
  │    清理 DROP TABLE / DROP INDEX / TRUNCATE 产生的数据
  │
  └─ 3. Do GC(清理旧版本)
      删除每个 Key 在 safe point 之前的所有历史版本

GC 关键配置

系统变量 默认值 说明
tidb_gc_enable ON 是否启用 GC
tidb_gc_run_interval 10m GC 运行间隔
tidb_gc_life_time 10m 历史版本保留时间(安全窗口)
tidb_gc_concurrency 自动 GC 并发度
tidb_gc_max_wait_time 0 GC 等待 safe point 推进的最长时间
-- 查看 GC 配置
SELECT * FROM mysql.tidb WHERE variable_name LIKE 'tikv_gc%';

GC 模式演进

版本 模式 说明
v3.0 之前 CENTRAL GC TiDB 逐个扫描所有 Region 执行 GC,效率低
v3.0+ DISTRIBUTED GC TiKV 每个 Region Leader 自行执行 GC
v5.0+ Compaction Filter GC RocksDB Compaction 时直接过滤过期数据,零 GC 开销

Compaction Filter GC 是最优模式(v5.0+ 默认):

  • GC 在 RocksDB 后台 Compaction 过程中顺带完成
  • 不需要单独的 GC Worker 扫描和删除
  • 对业务几乎零影响
-- 查看当前 TiKV 是否启用 Compaction Filter GC
SHOW CONFIG WHERE type = 'tikv' AND name LIKE '%enable-compaction-filter%';

-- 在线修改
SET CONFIG tikv gc.enable-compaction-filter = true;

九、XA 事务兼容性

TiDB 兼容 MySQL XA 协议,允许作为资源管理器(RM)参与外部分布式事务协调。

适用场景

               ┌──────────────────┐
               │  Atomikos /      │
               │  Seata / Narayana │  ← 分布式事务协调器(TM)
               └────────┬─────────┘
                        │ XA 协议
          ┌─────────────┼─────────────┐
          │             │             │
          ▼             ▼             ▼
    ┌──────────┐ ┌──────────┐ ┌──────────┐
    │  TiDB    │ │ MySQL    │ │ Oracle   │  ← 多个资源管理器(RM)
    └──────────┘ └──────────┘ └──────────┘

配置示例

<!-- Spring + Atomikos 配置 -->
<bean id="xaDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean">
    <property name="uniqueResourceName" value="tidb_ds" />
    <property name="xaDataSourceClassName"
              value="com.mysql.cj.jdbc.MysqlXADataSource" />
    <property name="xaProperties">
        <props>
            <prop key="URL">jdbc:mysql://tidb:4000/test</prop>
            <prop key="user">root</prop>
        </props>
    </property>
    <property name="maxPoolSize" value="10" />
</bean>

重要说明

注意点 说明
不同层级 TiDB 内部的 Percolator 事务与 XA 协议处于不同抽象层
适用范围 Percolator 保证跨 Region/跨 TiKV 的一致性;XA 保证跨多个异构数据库
性能开销 XA 事务需要额外的协调器交互,延迟高于原生事务

十、最佳实践与常见问题

10.1 大事务处理

TiDB 限制:

限制项 默认上限 说明
单事务 KV 条目数 3000 行/批(推荐) 超过可能触发 transaction is too large
单条 KV Entry 6 MB 单行数据推荐不超过此值
事务总大小 120 MB(v8.x) 超过可能被 PD 拒绝

分批提交方案:

// 错误示例:一次性提交大量数据
for _, row := range rows {
    db.Exec("INSERT INTO t VALUES (?)", row)
}
tx.Commit()  // ❌ 可能触发 transaction is too large

// 正确示例:分批提交(推荐每批 3000 行)
const batchSize = 3000
for i := 0; i < len(rows); i += batchSize {
    tx, _ := db.Begin()
    end := i + batchSize
    if end > len(rows) {
        end = len(rows)
    }
    for _, row := range rows[i:end] {
        tx.Exec("INSERT INTO t VALUES (?)", row)
    }
    tx.Commit()  //  每批单独提交
}

10.2 监控事务性能

Grafana → TiDB Dashboard

关键面板:
  ⚡ KV Errors → KV Backoff OPS     ← 事务冲突/重试频率
  ⚡ KV Errors → Lock Resolve OPS   ← 锁解析频率(正常应为低值)
  ⚡ KV Errors → KV Retry Duration  ← 事务重试耗时
  ⚡ Transaction → Transaction OPS    ← 事务吞吐
  ⚡ Transaction → Duration           ← 事务延迟

常用 PromQL:

# 事务冲突率
sum(rate(tidb_tikvclient_txn_regions_num_sum{type="2pc_prewrite"}[1m]))
/
sum(rate(tidb_tikvclient_txn_regions_num_count{type="2pc_prewrite"}[1m]))

# Write Conflict 次数
sum(rate(tidb_session_retry_error_total[1m]))

10.3 常见问题 FAQ

Q:出现 Write Conflict 怎么办?

A:通常两种策略:

  • 切换到悲观事务模式,让冲突提前暴露在 DML 阶段而非 commit 阶段
  • 减少冲突概率:缩短事务执行时间、降低并发度、减小事务粒度

Q:transaction is too large 如何解决?

A:大事务拆分。参考上方"分批提交方案",将一次大批量写入拆分为多个小事务(推荐 3000 行/批)。大规模数据导入建议使用 TiDB Lightning 工具。

Q:TiDB 的 REPEATABLE READ 和 MySQL 有什么区别?

A:TiDB 基于 MVCC 快照实现,不会出现幻读;MySQL InnoDB 需要 Gap Locking 来防止幻读。TiDB 不支持 Gap Locking,但也不需要——因为快照隔离天然阻止幻读。

Q:TiDB 事务和 MySQL 一致吗?

A:95% 一致。主要差异:

  • TiDB 不支持 READ UNCOMMITTED 和 SERIALIZABLE
  • TiDB 无 Gap Locking
  • TiDB 的 SELECT LOCK IN SHARE MODE 需要特殊配置
  • TiDB 支持乐观模式的自动重试(MySQL 不支持)

十一、演进时间线

v1.0  ── 乐观事务模型(Percolator 2PC)
 │
v3.0.8 ── 悲观事务支持 + 事务自动重试
 │
v4.0  ── 1PC / Async Commit / Pipelined Pessimistic Lock
 │
v5.0  ── Compaction Filter GC + Distributed GC
 │
v6.0.0 ── In-Memory Pessimistic Lock
 │         tidb_rc_read_check_ts(Read Committed 优化)
 │
v6.3.0 ── tidb_rc_write_check_ts(RC 写入优化)
 │
v7.x  ── GC 持续优化(Compaction Filter 增强)
 │
v8.x  ── 事务性能持续优化,大对象存储支持(LOB)

参考文档


一句话总结:TiDB 基于 Google Percolator 模型,通过 TSO 全局时间戳 + MVCC + 两阶段提交(2PC)+ Primary Key 机制,在分布式 KV 存储 TiKV 之上实现了完全透明、强一致、水平扩展的 ACID 分布式事务。

0
0
1
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论