一、TiDB 是什么
TiDB 是平凯星辰(PingCAP) 公司自开源的分布式 NewSQL 数据库,兼容 MySQL 协议 ,支持水平弹性扩展、分布式事务和强一致性, 它的核心定位是解决传统单机数据库在海量数据存储 和高并发访问 上的瓶颈,同时提供HTAP(混合事务与分析处理) 能力,让 OLTP(在线事务处理) 和 OLAP(在线分析处理) 在同一系统中运行,免去数据同步的烦恼
TiDB 的核心优势可以概括为:
-
水平扩展 :计算层无状态,可以无限加 TiDB Server;存储层按Region 分片,可以动态加 TiKV 节点
-
高可用 :数据多副本存储 ,Raft 协议保证一致性,少数节点故障不影响服务
-
分布式事务 :基于 Google Percolator 模型 + MVCC,对外提供 MySQL 兼容的隔离级别
-
HTAP 一体化 :TiKV 行存 + TiFlash 列存,同一 SQL 层自动路由
| 主线 | 解决的问题 | 关键机制 |
|---|---|---|
| 拆得开 | 容量与写吞吐线性扩展 | Range 分片(Region)+ 计算存储分离,无需预先设计分库分表规则 |
| 不丢不错 | 强一致与高可用 | Multi-Raft 多数派提交(RPO=0,少数副本故障自动转移) |
| 跨片事务 | 分布式 ACID | PD 全局时间戳 TSO + Percolator 两阶段提交 + Async Commit / 1PC 优化 |
| 一份数据两用 | OLTP 与实时分析不打架 | TiKV 行存 + TiFlash 列存(Raft Learner 异步复制),CBO 自动路由 |
二、核心架构与关键原理
核心技术特性
- 一键水平弹性扩缩容:得益于存算分离架构,企业可以根据业务需求,在线对计算或存储资源分别进行扩容或缩容,整个过程对应用和运维人员完全透明
- 金融级高可用与强一致性 :数据采用多副本存储,通过 Multi-Raft协议同步事务日志,确保只有多数派写入成功事务才能提交, 当少数副本或节点发生故障时,系统可自动进行故障转移,确保 RPO=0(数据零丢失)且 RTO ≤ 30s(恢复时间极短)
- 高度兼容 MySQL 协议与生态:TiDB 兼容 MySQL 5.7 协议及常用功能,支持绝大部分 MySQL 8.0 语法, 应用从 MySQL 迁移到 TiDB 时,通常无需修改代码或仅需极少修改,且支持使用现有的 MySQL 客户端工具直接接入
- 云原生设计:专为云环境打造,通过 TiDB Operator 等工具,可以在公有云、私有云及混合云中实现数据库部署的自动化与工具化,降低运维门槛
1. 整体架构:计算与存储分离
TiDB 采用计算与存储分离架构,由下面核心组件构成,各组件可独立进行水平扩缩容:
TiDB Server(计算层) :无状态 SQL 层,对外暴露 MySQL 协议连接端点,纯计算节点,不存储数据,仅负责 SQL 接收、解析、优化,并生成分布式执行计划,将实际数据读写请求转发给底层存储节点, 由于无状态,大促时可直接将节点数从 4 台扩展到 12 台承接连接洪峰,结束后再缩容
PD Server(调度层):集群的"大脑",负责三项关键任务
① 通过 etcd 存储 Region→Store 映射等元信息
② 分配全局单调递增时间戳 TSO
③ 根据心跳下发 AddReplica / RemoveReplica / TransferLeader 等调度指令, PD 是整个集群唯一的中心化部件,但其瓶颈已被批量化 TSO 和 Local TSO(5.x+)化解,通常不会成为性能瓶颈
TiKV Server(存储层) :分布式事务型 Key-Value 存储引擎 ,负责底层数据持久化, 数据按范围(Region)分片,并通过 Multi-Raft 协议在多个副本之间同步,保证强一致性与高可用, 底层采用 RocksDB(LSM-Tree),每个节点运行两个独立的 RocksDB 实例:raftdb 存日志,kvdb 存数据,kvdb 包含 raft / lock / write / default 四个 CF, 这种分离日志与数据 IO 路径的设计,使其在高写入场景下依然稳定
TiFlash Server(列存引擎) :一种特殊的存储服务器,以列存方式存储数据,代码源自 ClickHouse,但放弃了 MergeTree 而改用DeltaTree 列存引擎, 这是因为 TiDB 的 MVCC 会带来大量更新 ,LSM 在 Scan 时需要堆排序合并多层文件,导致 CPU 分支预测失效且写放大严重**, TiFlash作为 Raft Learner 异步复制 TiKV 数据 ,即使宕机也不会影响 TiKV 的写入,主要用于加速分析型处理(OLAP)**,与 TiKV 结合实现真正的实时 HTAP 架构
**演进方向:**TiDB X 架构正从 shared-nothing 转向 shared-storage,以对象存储为单一可信源,上层用共享缓存加速, 其目标是让扩缩容不再依赖物理数据迁移(官方称最高提升 10 倍),并彻底隔离 compaction 等后台任务与在线流量, 目前主要在云托管形态提供,自建生产仍以经典架构为主
2.TiDB/TiKV 核心机制整合:Region、Raft 与分布式事务
(1).Region 与 Raft:数据分片与一致性
TiKV 将数据划分为 Region ,每个 Region 负责一个 Key Range, 每个 Region 有多个副本,分布在不同 TiKV 节点上,构成一个 Raft Group, 任何写请求都只能在 Leader 上写入,并且需要写入多数副本后,才会返回客户端写入成功
举例说明:假设集群有 3 个 TiKV 节点,Region 100 的三个副本分别位于:
-
node-1:Leader
-
node-2:Follower
-
node-3:Follower
写入一条数据时:
-
(1).请求到达 node-1 的 Leader
-
(2).Leader 将写操作并行发送到 node-2 和 node-3
-
(3).只要 node-2 或 node-3 中有一个确认成功,加上 Leader 自身,就达到多数派,写入即算成功
-
(4).若某个 Follower 宕机,只要 Leader 和另一个 Follower 存活,仍可继续提交;若 Leader 宕机,剩余多数派副本会重新选举 Leader,服务不中断
PD Server (调度层) 以 Region 为单位进行调度, 当某个 TiKV 节点负载过高时,PD 会将部分 Region 迁移到空闲节点,实现负载均衡, Region 也会自动分裂和合并:当 Region 数据量增大到阈值时自动分裂成两个,数据量减少时合并,保持每个 Region 大小适中
(2).Region 如何自动生长
Key 编码方式为:
table_id + handle(主键) → 全局有序键空间
Region 表示为:
Region = [StartKey, EndKey) 左闭右开
默认约 96MB 触发 split, 一张 10 亿行的订单表,在 TiKV 中会被切成几千个 Region,均匀散落在几十台 Store 上, 应用完全感知不到分片的存在,这也是TiDB 与"手动分库分表"最大的差异
由此带来两个直接后果:
1). 全局有序主键 = 写入热点
如果使用:
sqlid bigint auto_increment
所有新写入都会集中在最后一个 Region,导致单点被打满, 此时增加再多节点也无济于事,
常见解法是打散主键 ,例如使用
AUTO_RANDOM、随机主键、随机前缀或业务散列键,避免连续自增造成尾部热点
2). 跨 Region 操作成本更高
一次事务涉及 N 个 Region,就需要 N 次 Raft 提案与网络往返, 因此,表设计应尽量让"常一起访问的行落在相邻 Key",例如使用用户 ID 作为主键前缀
(3).分布式事务:TSO + Percolator 2PC
TiDB 的事务模型基于 Google Percolator,本质上是一个优化过的**两阶段提交协议**,配合 MVCC 实现多版本并发控制
两阶段提交流程:
Prewrite 阶段:TiDB 作为事务协调者,将所有写操作发送到对应的 TiKV 节点,写入数据和锁,但数据对其它事务不可见
Commit 阶段:如果所有 Prewrite 成功,协调者向 PD 获取 commitTs,然后向所有 TiKV 发送提交指令,将锁替换为提交记录
TiDB 支持两种事务模式:
乐观事务:直接提交,提交时才检测写写冲突, 适合冲突率低的场景,冲突时回滚代价较大
悲观事务:提交前先对需要修改的资源上锁,确保事务能成功后才提交, 适合冲突率高的场景,提前上锁的代价小于事后回滚
时间轴
sql
T1 begin
→ TiDB 向 PD 拿 start_ts(全局递增时间戳,批量分配)
T2 执行 SQL
→ 读走 MVCC 快照(≤ start_ts 的最新版本)
→ 写先攒在内存 buffer
T3 commit
→ 两阶段提交:
Prewrite:
选一个 primary key,并行向所有涉及 Region 写 Lock + 数据
检查冲突:已有 Lock 或存在 > start_ts 的已提交版本 → 冲突回滚
Commit:
先 commit primary(写 Write CF,记录 start_ts)
再异步 commit secondaries
T4 清理 Lock
→ 异步执行,失败也不影响正确性:primary 已提交即视为成功
三个关键优化
| 优化 | 作用 | 适用 |
|---|---|---|
| Async Commit | 跳过同步等待 CommitTS,二次 RPC 合并 | 小事务,显著降低尾延迟 |
| 1PC(一阶段提交) | 单 Region 事务直接绕过 Prewrite | 单行插入/更新,接近单机数据库开销 |
| 悲观锁 + 增量锁检测 | SELECT ... FOR UPDATE 真正阻塞而非直接报错,死锁检测响应更快 |
冲突率高的扣库存、转账场景 |
隔离级别
TiDB 默认隔离级别为 Snapshot Isolation ,也就是可重复读, 它不提供 Serializable,但可以通过
SELECT ... FOR UPDATE模拟
这意味着:
-
同一事务内不会出现不可重复读
-
但可能出现写偏斜(write skew)
-
若业务逻辑强依赖串行化语义,必须在代码层面通过显式加锁来兜底
总结: TiDB 用 Region 做透明分片,用 Raft Group 保证多副本一致性,用 PD 做 Region 调度、分裂合并和负载均衡,再用 TSO + Percolator 2PC 提供分布式事务
应用通常感知不到分片存在,但表设计和事务设计仍需重点关注两件事:
避免全局有序主键造成的写入热点
尽量减少跨 Region 事务,让常一起访问的数据落在相邻 Key
3. MVCC 与 GC
TiKV 的 write CF 保留多个版本,读取时按时间戳过滤, 后台 GC 会定期清理早于
gc_safe_point的版本致命陷阱:一个长事务(或未提交的事务)会阻塞整个集群的 GC 推进,导致所有旧版本无法清理,磁盘空间持续上涨直至打满,同时查询性能急剧下降
原因是:
gc_safe_point不能超过最老的活跃事务的start_ts,否则可能删掉该事务仍然需要读取的历史版本
长事务 / 未提交事务 → 阻止 gc_safe_point 推进 → 所有旧版本无法清理 → 磁盘空间持续上涨直至打满 → 查询性能急剧下降这就是所谓"静默爆炸":业务可能没有明显报错,但磁盘和查询延迟已经在恶化
排查:GC 是否被堵住
-- 必查:GC 是否被堵住
SELECT * FROM mysql.tidb WHERE variable_name='tikv_gc_safe_point';
SHOW VARIABLES LIKE 'tidb_gc_life_time'; -- 默认 10m0s
-- 查长事务
SELECT * FROM information_schema.cluster_tidb_trx WHERE duration > '00:10:00';
重点关注:
tikv_gc_safe_point是否长时间不推进;
tidb_gc_life_time是否过短;是否存在超过业务预期的长事务;
是否存在长期未提交事务或悬挂锁
对策:
设置合理的 GC 生命周期
tidb_gc_life_time应略大于最长业务窗口,避免正常业务快照被过早清理长查询改用 TiFlash 或从库
报表类长查询不要长期占用 TiDB 事务快照,否则容易拖住 GC
配置磁盘使用率告警
建议阈值
< 80%,并联动 GC 生命周期参数做自动收缩或人工干预监控长事务与未提交事务
对
information_schema.cluster_tidb_trx做持续监控,发现超长事务及时 kill 或优化避免业务侧大事务
大事务不仅提交慢,还会长时间持有
start_ts,是阻塞 GC 的常见根因
4.HTAP:TiKV 行存 + TiFlash 列存
TiDB 在 4.0 版本引入列存储引擎 TiFlash,与行存储引擎 TiKV 共同构建真正的 **HTAP 数据库,**TiFlash 通过 Multi-Raft Learner 协议实时从 TiKV 复制数据,确保行存和列存之间的数据强一致
查询路由逻辑:
-
点查和小范围扫描 → TiKV(行存,适合按行读取)
-
大聚合和全表扫描 → TiFlash(列存,按列读取数据量更少)
-
应用层 SQL 不变,优化器自动选择引擎
举例:
sql
-- 点查,走 TiKV
EXPLAIN SELECT * FROM orders WHERE order_id = 84213;
-- 输出:Point_Get,TiFlash 不出现在计划中
-- 全表聚合,走 TiFlash
EXPLAIN SELECT region, COUNT(*) FROM orders GROUP BY region;
-- 输出:TableFullScan → mpp[tiflash],使用 MPP 模式并行计算
TiFlash 的 MPP 模式允许各 TiFlash 节点并行计算后汇总,大幅提升分析查询性能
5.SQL 层:为什么同一条 SQL 有时快有时慢
- CBO 优化器 :依赖统计信息(行数、NDV、直方图)进行代价估算, 默认采用自动 analyze,但在大批量导入后会短暂出现统计信息滞后的情况,从而导致执行计划选错
- 执行计划缓存(Plan Cache) :仅对简单点查类 prepare 语句生效,复杂查询每次都会重新硬解析, 因此,大促期间 QPS 暴涨时,TiDB 层的 CPU 往往消耗在解析阶段,而非存储层
- 下推机制 :过滤、聚合及部分 Join 会下推到 TiKV Coprocessor(协同处理器 ) 或 TiFlash MPP 执行, 可以通过
EXPLAIN查看是否命中cop[tikv]或BatchCop/MPP- 在线 DDL:采用 fully online 策略,加字段不阻塞读写(仅 reorg 类操作会产生额外流量), 这解决了 MySQL 在大表上执行 DDL 容易拖垮业务的痛点
三、 典型应用场景
- 金融行业核心系统:适用于对数据一致性、高可靠性、容灾能力要求极高的场景(如银行转账、核心交易), TiDB 的多副本与 Multi-Raft 机制能够有效替代传统的同城双活或异地灾备方案,降低维护成本
- 海量数据与高并发 OLTP 场景:当业务数据呈爆炸性增长,传统单机数据库或分库分表中间件无法满足容量和高并发需求时,TiDB 能够提供 PB 级别的存储容量和高达 512 个计算节点的扩展能力,轻松应对海量并发
- 实时 HTAP 混合负载场景:在物联网、人工智能等产生海量数据的场景中,TiDB 允许在同一个系统中同时进行联机交易处理与实时数据分析, 这避免了传统架构中通过 ETL 工具将数据同步到 OLAP 库带来的高存储成本和严重的数据延迟
- 数据汇聚与二次加工处理:适用于将企业分散在各个业务系统中的数据统一汇聚到 TiDB 中,并通过 SQL 直接进行二次加工,快速生成 T+0 或 T+1 的业务报表,大幅简化了传统大数据架构的复杂性
Flipkart:超过 100 万 QPS,P99 延迟 7.4msFlipkart 是印度最大的电商平台,服务数百万用户, 其原有架构使用 900 个独立 MySQL 集群加 Vitess 分片,面临严重问题:
故障切换:主节点故障导致短暂但不可避免的服务中断
数据丢失风险:MySQL 异步复制,主节点故障时在途数据可能丢失
垂直扩展上限:虚拟机最多支持约 3-3.5TB 存储,需要频繁分库分表
运维复杂度高:分片增加了应用逻辑、监控、备份恢复的复杂度
Flipkart 迁移到 TiDB 后,压测结果显示 TiDB 能够处理超过 100 万 QPS,P99 延迟 7.4ms,写入吞吐达到每秒 12 万次,延迟 13ms
关键优化实践:
热点打散 :使用
AUTO_RANDOM替代自增主键,将写入分散到多个 Region预分片 :建表时使用
PRE_SPLIT_REGIONS预先切分 Region,避免初期写入集中在单个 Region批量写入:每批 1000-5000 条记录,通过 gRPC 连接池控制并发数(建议 <50)
内存悲观锁:TiDB v6.0.0 及以上版本默认开启,通过内存中加锁避免落盘,可将 TPS 提升约 30%
某游戏:100+ 套集群,数据规模超 1PB
某游戏当前 TiDB 集群数量超过 100 套,最大单集群节点数达到 60 个以上,数据总规模超过 1PB
针对高并发请求的优化措施:
某游戏为高并发 OLTP 场景(如游戏服务)推出了高性能套餐,配置 18 核 CPU 和 180GB 内存,专为满足高并发业务需求而设, 在资源隔离方面,采用轻量级 LXC 虚拟化技术实现 CPU 和内存隔离,对 TiKV 等 IO 密集型节点在 SSD 盘上创建不同的 LVM 并挂载至不同虚拟机,确保磁盘响应的独立性
TiDB 在 某****游戏的使用场景包括:基础架构服务、云存储、内部管理等 OLTP 场景;上游 MySQL 下游TiDB 作为读扩展;重OLAP 场景下使用 TiSpark 直接请求 PD 进行报表统计计算;以及利用 TiDB 的横向扩展能力进行数据归档
电商大促:峰值 QPS 4.2 万,库存扣减零超卖
一个 DTC 电商公司在双十一彩排压测中的实战数据:
TiDB 弹性扩容从 1 个 TiKV 到 3 个 TiKV 只需 23 分钟
峰值 QPS 4.2 万,P99 延迟 22ms
库存扣减使用
SELECT ... FOR UPDATE加悲观事务,实现零超卖库存扣减的分布式事务示例:
sqlBEGIN PESSIMISTIC; -- 扣减库存,悲观锁防止并发超卖 UPDATE products SET stock = stock - 1 WHERE product_id = 1001 AND stock > 0; -- 创建订单 INSERT INTO orders (order_id, product_id, user_id, status) VALUES (20260921001, 1001, 88888, 'created'); COMMIT;这个事务涉及库存表和订单表,可能分布在不同的 TiKV 节点上, TiDB 通过 Percolator 两阶段提交保证跨节点的原子性:要么库存扣减和订单创建都成功,要么都回滚,不会出现"库存扣了但订单没创建"的情况
汽车之家:业务增长 20+ 倍,HTAP 一体化
汽车之家的用户访问、内容互动和交易请求呈指数级增长,数据库需要同时满足高 TPS/QPS 与低延迟响应的严苛要求, 汽车之家采用 TiDB 构建了一套 HTAP 数据库,同时支撑在线交易和实时分析,避免了传统方案中 OLTP 与 OLAP 分离带来的数据同步延迟和运维复杂度
四、 在线峰值高并发项目落地案例
1. 容量规划
假设目标:峰值写入 8 万 TPS,数据日增 300GB,保留 180 天,读 QPS 15 万
- 存储总量 ≈ 300GB × 180 × 3 副本 ≈ 162 TB 原始,考虑 LSM 写放大(约 1.5~2 倍)→ 约 250~320 TB
- TiKV 节点:采用 NVMe SSD,单节点建议承载 8~15 TB 有效数据 → 约 20~30 台(16C64G + 4TB NVMe × 4)
- TiDB Server:按单节点 3000~5000 并发连接、峰值 QPS 能力估算 → 8~12 台(16C32G),前方挂载 TiProxy/LVS
- PD:3 台(8C16G SSD),跨可用区部署
- TiFlash:3~6 台(32C128G,需 CPU 支持 AVX2),与 TiKV 物理隔离
注意:上述为量级估算,实际应以业务压测为准, TiDB 官方标称可支持计算节点数百个、PB 级容量,但单集群性价比最优区间通常在 10~50 台 TiKV, 规模过大时应考虑按业务域拆分集群
2. 热点写入打散
- 现象 :订单表
id auto_increment,促销零点流量涌入,某一台 TiKV 的 CPU 飙升至 95%,其余节点仅为 20%,TPS 上不去- 原因:全局有序主键导致所有新写入落入同一个 Region,形成单点热点, Raft 多数派提交的机制在此刻反而放大了单点压力
- 修复(三重组合拳):
-- ① 首选:AUTO_RANDOM(把自增换成随机分布的主键)
CREATE TABLE orders (
order_id BIGINT PRIMARY KEY /*T![auto_rand] AUTO_RANDOM(5) */,
user_id BIGINT NOT NULL,
amount DECIMAL(12,2),
status TINYINT,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_time (user_id, create_time)
) SHARD_ROW_ID_BITS=4 PRE_SPLIT_REGIONS=4;
-- ② 预分裂 Region:建表时就切成 2^4=16 个 Region,避免运行时自动 split 带来的抖动
-- ③ 查询侧兜底:按 user_id 前缀聚簇,保证「查我的订单」是局部扫描
效果参考:在同等硬件条件下,打散热点后写入TPS通常能提升 3~8 倍,且各节点负载趋于均衡
代价与补偿 :主键不再有序,分页不能使用ORDER BY id DESC的单调游标(应改为 **create_time + id**组合), 自增 ID 的"连续"与"可推测业务量"特性消失(后者反而是安全收益)
3. 事务与 SQL 设计红线
| 做法 | 说明 |
|---|---|
| 事务尽量短小 | 单事务操作数据建议 < 100MB、行数万级以内;大事务会占用更多锁并放大 2PC 开销 |
| 扣库存用悲观锁 + 精确条件 | UPDATE stock SET qty=qty-1 WHERE sku_id=? AND qty>0,利用索引确保只锁一行;切忌无索引的全表 FOR UPDATE |
避免 SELECT * 与大范围扫描 |
跨 Region 拉取大量无关数据会成倍放大网络与 TiDB 层内存消耗 |
| JOIN 控制在 3~5 张表内 | 大表多路 JOIN 建议在 TiFlash/MPP 或数仓中处理 |
批量写入走 INSERT INTO ... VALUES(...),(...) 或 batch DML |
减少网络往返与解析开销,单批次控制在数千行 |
| 开启 prepared plan cache | 针对高频点查模板,降低 TiDB 层 CPU 消耗 |
| 连接池复用 | 应用侧使用 HikariCP 等池化,TiDB 侧 max_connections 按需调大(默认值较小) |
4. 资源隔离:别让一条报表 SQL 拖垮下单链路
这是峰值保障中最具性价比的一项措施(TiDB 6.0+ 引入 Resource Control):
-- 给 OLAP / 报表 / 内部工具限定 RU 配额,超配额排队而非抢资源
CREATE RESOURCE GROUP rg_report RU_PER_SEC = 2000 PRIORITY = LOW BURSTABLE;
CREATE USER 'report'@'%' IDENTIFIED BY 'xxx';
ALTER USER 'report'@'%' RESOURCE GROUP rg_report;
-- 在线查询走高优先级
CREATE RESOURCE GROUP rg_online RU_PER_SEC = 20000 PRIORITY = HIGH;
配合
tidb_mem_quota_query(单查询内存上限,建议 1~2GB)与tidb_distsql_scan_concurrency调优,可有效防止单个大查询引发 OOM。
5. 大促前 72 小时 Checklist
sql
D-72 全链路压测(用 go-ycsb / sysbench + 真实流量回放),拿到 TPS/QPS/尾延迟基线
D-48 全表 ANALYZE TABLE,确认统计信息新鲜;检查慢查询 TOP50 逐一优化
D-24 关闭非必要的自动 analyze / 导入任务; TiFlash 副本提前预热(select count(*) 扫一遍)
D-12 扩容 TiDB 层(无状态,分钟级生效); 确认 TiKV 磁盘 < 70%,PD 调度正常
D-2 冻结 DDL 与 schema 变更; 确认备份(BR 全量)可用
D-0 看板:QPS、P99 延迟、Region leader 分布、GC safepoint 推进、TiKV write duration、
存储使用率、死锁次数、coprocessor 错误数
D+0 逐步放开流量,观察 30 分钟无异常再全量
D+24 恢复 replicas/analyze; 缩容多余 TiDB 节点
关键看板指标与阈值:P99 读延迟 > 200ms 告警、GC safepoint 停滞 > 30min 告警、Region leader 倾斜度 > 2 倍告警、TiKV 磁盘 > 80% 告警、死锁次数突增告警
6. 降级预案
- L1:拦截非核心查询(报表、运营后台、推荐特征查询),强制走 TiFlash 或拒绝
- L2:关闭 TiDB 层非必要功能(如 plan cache 之外的诊断采样、慢日志详细采集)
- L3:只读流量切到 TiFlash / follower read;写流量按租户限流
- L4:极端情况下,核心下单链路降级到本地队列 + 异步落库(需业务侧支持最终一致)
五、分布式架构中的使用案例详解
1. 某东:替代分库分表,单表百亿行毫秒级响应
某东集团自 2020 年起正式采用 TiDB,内部运行数百套集群,总数据量达 PB 级,广泛应用于零售广告推荐、物流财务结算、科技金融等场景
替代分库分表的痛点与解决:
早期某东云使用 MySQL 分库分表,随着数据量增大,需频繁扩库,人力成本激增,管理运维繁琐, TiDB 作为替代分库分表的理想方案,具备以下能力:
支持 PB 级容量,业务数据再多也不怕
突破单机容量限制,无需分库分表,降低架构复杂度
支持分布式事务,应用不再受限
可跟随业务量变化随时在线扩容
TiFlash 赋能实时分析:某东在实时分析场景中引入 TiFlash,一个列存储引擎数据副本就能实现实时分析,无需将数据同步到 Hadoop、Clickhouse 或 Doris,简化了架构,业务方接受度更高
Kubernetes 容器化部署:某东云选择完全基于 Kubernetes 容器化部署 TiDB,通过 TiDB Operator 实现自动化管理,高效支持快速扩缩容与资源调度
2. 某全球化消费电子品牌:多业务资源隔离
该企业在引入 TiDB 之前主要使用 MySQL,面临三个瓶颈:
-
库存管理系统:高并发读写,随数据量增长难以满足性能要求
-
业财一体化系统:单表记录数已超过 15 亿行,存在多表关联分析需求
-
业务报表系统:经常涉及十几张表、数百行 SQL 的复杂查询,且对数据实时性有极高要求
迁移到 TiDB 后,通过 TiDB 的资源隔离能力,在同一集群中为不同业务分配独立的资源组,实现了 CPU、IO 等资源的细粒度隔离,多个业务互不影响
3. 某银行:同城双中心高可用
某银行基于 TiDB 分布式架构设计的新一代关键业务系统,通过节点冗余、数据副本、故障转移和负载均衡等机制,实现了系统的高可靠性与可维护性, 在生产集群计划内切换演练中,通过脚本封装整个切换过程持续约 6 分钟,业务影响约 1 秒
故障转移机制 :TiDB 的故障转移是自动的, 当 TiKV 实例心跳丢失时间超过 max-store-down-time(默认 30 分钟)后,PD 将其标为 Down,并开始把该 TiKV 实例上相关 Region 的副本在其它存活 TiKV 上补齐或替换
举例:假设 3 副本集群中 node-2 宕机,它上面有 Region 100 的 Follower 副本, PD 检测到心跳丢失后:
立即将 node-2 标记为不可用
在 node-3 上创建 Region 100 的新 Follower 副本
如果 node-1(Leader)也故障,则 node-3 上的副本可以参与 Leader 选举
整个过程无需人工干预,客户端几乎无感
4. 某单车:P0 级核心业务跨 AZ 部署
某单车自2017年开始将 TiDB 应用到实际业务中,按照业务重要性将使用场景分为三个等级:
-
P0 级核心业务:线上核心业务,必须单业务单集群,跨 AZ 部署,具有异地灾备能力
-
P1 级在线业务:允许适度共享集群资源,但需保证性能隔离
-
P2 级离线/分析业务:对延迟不敏感,可共享资源
这种分级部署策略兼顾了核心业务的稳定性和非核心业务的成本效率
5. 某银联:T+0 实时数据中台
某银联通过采用 TiDB 构建 T+0 实时数据中台,提升了运营效率和开发效率,降低了运维压力,同时满足了实时、准确的数据查询需求,存储周期保留 7 天, 这一场景对数据实时性要求极高,传统方案需要 T+1 批处理,而 TiDB 的 HTAP 能力使得实时查询成为可能
6.MySQL 分库分表 → TiDB 在线迁移(零停机切流)
背景 :订单库已拆分为 16 库 × 64 表 = 1024 张分表,新增查询维度需要改中间件代码,DDL 变更需逐表执行数小时, 方案:
① 兼容性评估:用官方工具做 SQL 兼容性检查(绝大多数 MySQL 5.7 语法可直接跑)
② 全量迁移:DM(TiDB Data Migration)或 TiDB Lightning 导历史数据
③ 增量同步:DM 订阅上游 binlog,持续追平(注意 DM 自身高可用部署)
④ 双写校验期:业务双写 or 反向同步,跑对账脚本比对 count / sum(amount) / 抽样明细
⑤ 灰度切读:先切 1% 流量读 TiDB,观察 P99 与错误率,逐步 5%→30%→100%
⑥ 切写: 选低峰期,停写上游 → 等 DM 追平 → 切写入口 → 观察 → 下线分库分表中间件
⑦ 回滚预案:保留反向同步通道,出问题 10 分钟内切回
收益:分页查询、跨维度查询不再需要改造中间件;新增字段只需一次 DDL;扩容从"重新分片迁移"变为"加机器等待平衡"
踩坑记录:上游若有
AUTO_INCREMENT热点,迁移后务必改为AUTO_RANDOM(可在迁移阶段一并完成)DM 遇到不支持的 DDL 会中断,需提前在任务配置中设置
skip或手动处理唯一索引冲突在增量 replay 阶段容易引发重复键错误,需在迁移前清理脏数据
7. 大促零点热点写入
| 指标 | 改造前(auto_increment) | 改造后(AUTO_RANDOM + 预分裂) |
|---|---|---|
| 峰值写入 TPS | 2.1 万(单点卡死) | 7.6 万 |
| 最忙 TiKV CPU | 96% | 58%(集群均衡) |
| P99 写入延迟 | 1.8s | 45ms |
| 扩容有效性 | 加机器无效 | 线性提升 |
8.HTAP 实时大屏------砍掉 Lambda 架构
Lambda 架构 = 批处理层保准确 + 速度层保实时 + 服务层合并查询
背景 :交易数据经
MySQL → Canal → Kafka → Flink → ClickHouse链路进入大屏,延迟达 15 分钟以上,且链路上任何一环出现故障都会导致数据停滞, 改造:
-- 只需一行,把这张表的列存副本建出来
ALTER TABLE orders SET TIFLASH REPLICA 2;
-- 查询自动走列存(EXPLAIN 里看到 TableReader -> ExchangeSender -> MPP)
SET @@session.tidb_allow_mpp = 1;
SET @@session.tidb_enforce_mpp = 1; -- 强制 MPP(调试验证用)
SELECT city, SUM(amount) AS gmv
FROM orders JOIN store ON orders.store_id = store.id
WHERE create_time >= NOW() - INTERVAL 1 HOUR
GROUP BY city ORDER BY gmv DESC LIMIT 20;
要点:
- TiFlash 作为 Learner 异步复制,延迟通常在秒级以内,且读取时会向 Leader 校验复制进度,确保读到已提交数据
- TiFlash 与 TiKV 需物理隔离部署,否则列存扫描会抢占行存的 IO 与 CPU 资源
- 并非所有表都适合建立副本,建议仅对参与分析的宽表与事实表开启,以节省存储成本
- 复杂聚合可结合物化视图/聚合表预计算(定时刷新)进一步压降延迟
效果参考:实时GMV 看板延迟从15分钟降至 3 秒内,同时省去了一套 Flink + ClickHouse 的运维成本。
9.三地五中心金融级容灾(RPO=0,RTO<30s)
拓扑:上海(主)、杭州(同城备)、成都(异地)。
# TiKV 节点打标签
server.labels: { zone: "shanghai", rack: "rack-1" }
# PD 调度配置:副本按 zone 隔离
location-labels: ["zone","rack"]
max-replicas: 5 # 同城双副本 + 异地两副本,或 3 副本跨三中心
关键机制:
- Placement Rules 可按表级别指定副本落点(例如核心账务表 5 副本,日志表 2 副本)
- 多数派写入意味着同城双中心即可提交,异地副本作为 Learner 或投票成员参与容灾
- Follower Read:允许从 Follower 副本读取(需牺牲线性一致,换取异地读延迟大幅下降),适合异地只读业务与报表
- 故障演练:使用 Chaos Mesh 或 tiup chaos 定期注入
tikv-down、pd-leader-failover、机房断网,验证 RTO结果:任一机房整体掉电时,RPO=0(数据不丢),RTO 通常在 30 秒内完成 Leader 重选举与调度
10.多租户 SaaS 的资源隔离
问题:大客户A月底跑批量结算,导致小客户 B 的下单接口 P99 从 50ms 飙升至 2s
解法(三层隔离,由软到硬):
- 资源组(RU 配额 + 优先级):按租户绑定 resource group,大客户的批量任务设为 LOW 优先级并限制 RU
- 库/表级隔离:大客户单独 schema + 独立 TiFlash 副本策略
- 集群级隔离:Top 级客户独立集群(成本最高但最干净),通过 TiCDC 汇聚到分析集群做统一报表
经验:第 1 层能解决 80% 的吵闹邻居问题,且零成本;不要一开始就追求物理隔离
11.TiCDC下游同步------把 TiDB 变成数据中枢
TiDB → TiCDC → Kafka →(Flink / 数仓 / ES / Redis)
├→ ClickHouse/Doris(离线分析)
└→ Elasticsearch(全文检索,TiDB 不做全文检索!)
典型用途:订单变更实时入湖、搜索索引增量更新(替代上一轮对话里 MySQL CDC → ES 的链路,现在源头是 TiDB,稳定性更好)、缓存失效通知
踩坑清单:
- TiCDC 对大事务敏感:单事务过大可能导致同步延迟陡增甚至OOM,需控制事务大小
- DDL 同步有顺序依赖,下游消费端需做好幂等与跳过策略
- 下游唯一索引冲突会导致 changefeed 中断,需配置 error handling(warn/ignore)与告警
- 监控
ticdc_sink_error_count、changefeed_checkpoint_lag,滞后 > 60s 即告警- TiCDC 本身需至少 2~3 节点部署,避免成为单点
六、 选型注意事项
| 不适合 | 原因 | 替代/补救 |
|---|---|---|
| 单行高频计数器(点赞数、浏览量累加) | 同一行成为 Raft 热点,多数派提交放大写放大 | 前端/Redis 聚合批量写、或用 amount 累加改为异步汇总 |
| 超大事务(一次性百万行更新) | 2PC 开销巨大、锁持有时间长、阻塞 GC | 分批提交,每批数千行 |
| 海量小表(几十万张表) | 元数据与 Region 数量爆炸,PD 压力大 | 合并表结构,用字段区分业务 |
| 频繁 delete/update 的队列模型 | MVCC 版本堆积,GC lag,空间膨胀 | 改用 TTL(8.x 原生支持 TTL = create_time + INTERVAL 30 DAY)自动清理 |
| 复杂多表JOIN + 子查询嵌套 | 分布式 Join 代价高 | 宽表化、或在 TiFlash/数仓处理 |
| 全文检索、模糊匹配 | 不是搜索引擎 | 配 ES(TiDB 做权威源 + TiCDC 增量同步) |
| 存储过程/触发器/部分函数 | 兼容性不完全 | 迁移前做兼容性评估,逻辑上移到应用层 |
| 极低延迟的点查(<1ms P99) | 分布式往返天然比单机高 | 前置本地缓存/Redis,或接受 3~10ms 量级 |
| 场景 | 首选手段 |
|---|---|
| 消除自增主键写入热点 | AUTO_RANDOM + SHARD_ROW_ID_BITS + PRE_SPLIT_REGIONS |
| 让相关数据物理相邻 | 用业务键(user_id)做主键前缀 / 聚簇索引 |
| 高冲突扣减(库存) | 悲观锁 + 索引精确条件 + UPDATE ... WHERE qty>0 乐观扣减 |
| 低冲突高频写入 | 乐观事务 + Async Commit / 1PC 自动生效 |
| 长事务堵 GC | 查 cluster_tidb_trx + 限制 tidb_gc_life_time + 磁盘告警 |
| 大查询拖垮 OLTP | Resource Group 限 RU + tidb_mem_quota_query + 赶去 TiFlash |
| 实时分析 | ALTER TABLE t SET TIFLASH REPLICA 2 + MPP |
| 在线扩缩容 | 直接加 TiDB/TiKV 节点,PD 自动 balance,对业务透明 |
| 在线改表结构 | 直接 DDL(fully online),但大促窗口冻结 |
| 跨机房读延迟 | Follower Read(牺牲线性一致)+ location-labels 副本感知 |
| 容灾 | 3~5 副本跨 zone + Placement Rules + 定期故障演练 |
| 迁移上 TiDB | DM(全量+增量)+ 灰度切读 → 切写 + 对账脚本 + 回滚通道 |
| 下游生态 | TiCDC → Kafka/数仓/ES;BR 物理备份;Lightning 快速导入 |
| 别做的事 | 单行计数器、超大事务、海量小表、把 TiDB 当 ES 用、无限制长事务 |
七、总结
TiDB 不是所有数据库问题的默认答案, 它最适合替代**"容量/写入吞吐撑不住、又不想长期维护分库分表"的单机 MySQL**;如果只是读压力大,应先做读写分离、缓存和索引优化,而不是急着换数据库
1. 选型判断
单机 MySQL 容量或写入吞吐到瓶颈,且分库分表维护成本高 → 优先考虑 TiDB
只是读压力大 → 优先读写分离 + Redis 缓存 + 索引优化 + 从库扩展
不要为了"分布式"而分布式,先优化现有架构
2. TiDB 的适用与边界
擅长:大容量、高写入、混合负载、在线事务 + 实时分析、弹性扩展、高可用
不适合:单行高频计数器、超大事务、海量小表、全文检索
全文检索应交给 ES,而不是硬用 TiDB
3. 合理架构分工
TiDB:权威事务源,负责核心交易、强一致、分布式事务
ES:全文检索、复杂搜索、日志与分析检索
Redis:缓存、热点数据、会话、计数器等
数仓:离线分析、历史数据、大规模批处理
各司其职,避免一个数据库包打天下
4. TiDB 技术内核
计算存储分离 → 弹性扩展
Region + Raft → 数据分片、多副本、强一致
Percolator + MVCC → 分布式事务、多版本并发控制
TiKV + TiFlash → HTAP 一体化,行存 + 列存
高并发手段:热点打散、悲观事务、批量写入、自动扩缩容
分布式能力:多副本、自动故障转移、资源隔离、Kubernetes 容器化
5. 落地价值
TiDB 能替代传统分库分表方案,支撑百万级 QPS,并成为某东、Flipkart、某游戏、某银行等企业的核心数据底座, 但它应与 ES、Redis、数仓配合使用,而不是单独承担所有数据场景
**最终结论:**先判断瓶颈是读还是写/容量;读瓶颈先优化缓存和索引,写/容量瓶颈且不想分库分表再上TiDB;TiDB 做事务源,ES 做检索,Redis 做缓存,数仓做分析,才是更合理的分布式架构