前言:为什么又要学新东西?
还记得那个美好的年代吗?一个MySQL主从架构就能撑起整个公司的业务,DBA喝着咖啡看着慢查询日志,岁月静好。
然后,产品经理来了。
"我们要支持千万级用户!"
"我们要实时分析!"
"我们要99.99%可用性!"
"预算?能不能先欠着?"
于是你开始了分库分表的不归路,写了一堆路由逻辑,改了无数SQL,终于在某个深夜,面对着跨库JOIN的需求,你崩溃了。
这时候,TiDB出现了,像一个骑着白马的...分布式数据库。
一、TiDB是个什么玩意儿?
TiDB(Titanium DB,钛数据库,名字就很硬核)是 PingCAP 公司开发的一款开源分布式 NewSQL 数据库。
用人话说就是:它想当一个能无限扩展的MySQL,同时还能做实时分析,而且不用你操心分库分表。
听起来是不是很美好?别急,继续往下看。
1.1 TiDB的核心组件
行存储引擎
OLTP我最强"] D["TiFlash
列存储引擎
OLAP看我的"] E["PD
调度大脑
你们都得听我的"] end APP --> TIDB TIDB --> C TIDB --> D TIDB --> E E -.->|"调度"| C E -.->|"调度"| D C <-->|"Raft Learner"| D
让我来介绍一下这个"分布式全家桶":
TiDB Server(SQL层)
- 负责接收SQL请求,解析、优化、执行
- 完全无状态,可以随便加机器
- 对外伪装成MySQL,骗过了无数连接池
TiKV(行存储)
- 分布式Key-Value存储引擎
- 基于Raft协议保证数据一致性
- 数据按Region分片,每个Region默认96MB
- 适合OLTP场景(增删改查)
TiFlash(列存储)
- TiKV的列存副本
- 通过Raft Learner机制实时同步数据
- 适合OLAP场景(复杂分析查询)
- 让你在同一个数据库里同时搞OLTP和OLAP
PD(Placement Driver)
- 整个集群的大脑
- 负责存储元数据、分配时间戳、调度Region
- 如果PD挂了,整个集群就傻了
1.2 为什么TiDB说自己是NewSQL?
MySQL"] A1["✅ ACID事务"] A2["✅ SQL支持"] A3["❌ 水平扩展"] A4["❌ 自动分片"] end subgraph NOSQL["NoSQL数据库
MongoDB/Cassandra"] B1["❌ ACID事务"] B2["❌ SQL支持"] B3["✅ 水平扩展"] B4["✅ 自动分片"] end subgraph NEWSQL["NewSQL数据库
TiDB"] C1["✅ ACID事务"] C2["✅ SQL支持"] C3["✅ 水平扩展"] C4["✅ 自动分片"] end SQL -->|"我很稳
但扩展不动"| LIMIT1[" "] NOSQL -->|"我很快
但你得自己保证一致性"| LIMIT2[" "] NEWSQL -->|"我全都要!
代价是复杂度"| WIN[" "] style WIN fill:#90EE90 style LIMIT1 fill:#FFB6C1 style LIMIT2 fill:#FFB6C1
简单说,TiDB想要的是:鱼和熊掌兼得。
既要MySQL的ACID事务和SQL兼容性,又要NoSQL的水平扩展能力。听起来很贪心对吧?但人家还真做到了(大部分情况下)。
二、TiDB的核心特性(硬核时间)
2.1 分布式事务是怎么实现的?
TiDB使用了Percolator事务模型(Google的论文),这是一个基于两阶段提交(2PC)的分布式事务协议。
关键点解读:
- 全局时间戳(TSO):PD负责分配,保证全局递增,这是实现快照隔离的基础
- Primary Key机制:事务的"命门",Primary提交成功=事务成功
- 锁机制:乐观锁为主,写写冲突时才检测
2.2 数据是怎么分片的?
TiDB把数据按照Key的范围划分成一个个Region:
Key范围: [表前缀_0, 表前缀_∞)"] T["按Key范围自动切分"] end TABLE --> R1 & R2 & R3 & R4 subgraph REGIONS["Region分片"] R1["Region1
[0,100)"] R2["Region2
[100,200)"] R3["Region3
[200,300)"] R4["Region4
[300,∞)"] end subgraph TIKV1["TiKV1"] R1L["Region1 Leader"] R3F1["Region3 Follower"] R4F1["Region4 Follower"] end subgraph TIKV2["TiKV2"] R2L["Region2 Leader"] R1F1["Region1 Follower"] R4F2["Region4 Follower"] end subgraph TIKV3["TiKV3"] R3L["Region3 Leader"] R4L["Region4 Leader"] R1F2["Region1 Follower"] R2F1["Region2 Follower"] end R1 --> TIKV1 R2 --> TIKV2 R3 --> TIKV3 R4 --> TIKV3 style R1L fill:#90EE90 style R2L fill:#90EE90 style R3L fill:#90EE90 style R4L fill:#90EE90
📌 每个Region默认3副本,通过Raft协议保证一致性
为什么这么设计?
- 自动分裂:Region超过96MB自动分裂,无需人工干预
- 自动调度:PD会根据负载自动迁移Region,实现负载均衡
- 故障恢复:某个TiKV挂了,其他副本自动选主,业务无感知
2.3 HTAP是怎么玩的?
HTAP = Hybrid Transactional and Analytical Processing
简单说就是:一套数据,既能做交易,又能做分析。
自动选择最优存储引擎"] end SQL --> TIKV & TIFLASH subgraph TIKV["TiKV (行存)"] KV["OLTP场景"] KV1["• 点查"] KV2["• 事务"] KV3["• 高并发"] end subgraph TIFLASH["TiFlash (列存)"] TF["OLAP场景"] TF1["• 聚合"] TF2["• 报表"] TF3["• 大范围扫描"] end TIKV <-->|"Raft Learner
实时同步"| TIFLASH style TIKV fill:#E6F3FF style TIFLASH fill:#FFF0E6
TiFlash的黑科技:
- Raft Learner:作为只读副本,不参与投票,不影响TiKV性能
- 实时同步:数据变更秒级同步到列存
- 智能选择:优化器根据查询特征自动选择走行存还是列存
举个例子:
-- 这种查询走TiKV(点查,OLTP)
SELECT * FROM orders WHERE order_id = 12345;
-- 这种查询走TiFlash(聚合分析,OLAP)
SELECT product_id, SUM(amount)
FROM orders
WHERE create_time > '2024-01-01'
GROUP BY product_id;三、TiDB如何安装使用
3.1 安装方式选择
3.2 本地快速体验(Docker方式)
如果你只是想尝尝鲜,用Docker Compose最快:
# docker-compose.yml
version: '3'
services:
pd:
image: pingcap/pd:latest
ports:
- "2379:2379"
command:
- --name=pd
- --client-urls=http://0.0.0.0:2379
- --peer-urls=http://0.0.0.0:2380
- --advertise-client-urls=http://pd:2379
- --advertise-peer-urls=http://pd:2380
- --initial-cluster=pd=http://pd:2380
tikv:
image: pingcap/tikv:latest
depends_on:
- pd
command:
- --addr=0.0.0.0:20160
- --advertise-addr=tikv:20160
- --pd=pd:2379
tidb:
image: pingcap/tidb:latest
depends_on:
- tikv
ports:
- "4000:4000"
- "10080:10080"
command:
- --store=tikv
- --path=pd:2379启动并连接:
# 启动集群
docker-compose up -d
# 等待30秒让集群初始化...(去泡杯咖啡)
# 连接TiDB(就像连MySQL一样)
mysql -h 127.0.0.1 -P 4000 -u root
# 恭喜你,你已经是一个TiDB用户了!3.3 生产环境部署(TiUP方式)
TiUP是官方推荐的部署工具,一条命令搞定:
# 安装TiUP
curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
# 添加到PATH
source ~/.bashrc
# 查看版本
tiup --version最小生产集群配置(土豪请忽略):
# topology.yaml
global:
user: "tidb"
deploy_dir: "/tidb-deploy"
data_dir: "/tidb-data"
pd_servers:
- host: 192.168.1.1
- host: 192.168.1.2
- host: 192.168.1.3
tikv_servers:
- host: 192.168.1.4
- host: 192.168.1.5
- host: 192.168.1.6
tidb_servers:
- host: 192.168.1.7
- host: 192.168.1.8
# 可选:加上TiFlash支持OLAP
tiflash_servers:
- host: 192.168.1.9部署命令:
# 检查环境
tiup cluster check topology.yaml --user root
# 部署集群
tiup cluster deploy tidb-cluster v7.5.0 topology.yaml --user root
# 启动集群
tiup cluster start tidb-cluster
# 查看集群状态
tiup cluster display tidb-cluster硬件配置建议(来自血泪教训):
| 组件 | CPU | 内存 | 磁盘 | 数量 |
|---|---|---|---|---|
| PD | 4核+ | 8GB+ | SSD 200GB | 3(奇数个) |
| TiKV | 8核+ | 32GB+ | SSD 500GB+ | 3+ |
| TiDB | 8核+ | 16GB+ | 无所谓 | 2+ |
| TiFlash | 16核+ | 64GB+ | SSD 1TB+ | 1+(可选) |
⚠️ 血泪提醒:TiKV对磁盘IOPS要求极高,千万别用HDD,否则你会看到各种神奇的超时错误。
3.4 基本使用
连接TiDB后,基本和MySQL一模一样:
-- 创建数据库
CREATE DATABASE test_db;
USE test_db;
-- 创建表(熟悉的味道)
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_email (email)
);
-- CRUD操作,完全MySQL语法
INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@test.com');
SELECT * FROM users WHERE email = 'zhangsan@test.com';
UPDATE users SET name = '李四' WHERE id = 1;
DELETE FROM users WHERE id = 1;TiDB特有的骚操作:
-- 查看表的Region分布
SHOW TABLE users REGIONS;
-- 手动打散热点Region
ALTER TABLE users SHARD_ROW_ID_BITS = 4;
-- 为表添加TiFlash副本(开启HTAP模式)
ALTER TABLE users SET TIFLASH REPLICA 1;
-- 查看执行计划,看看走的是TiKV还是TiFlash
EXPLAIN SELECT COUNT(*) FROM users;
-- 强制使用TiFlash
SELECT /*+ READ_FROM_STORAGE(TIFLASH[users]) */ COUNT(*) FROM users;3.5 从MySQL迁移
如果你要从MySQL迁移到TiDB,有几个官方工具:
源数据库")] --> DUMP & DM subgraph FULLMIGRATION["全量迁移"] DUMP["Dumpling
数据导出"] DUMP -->|"SQL/CSV文件"| LIGHTNING["TiDB Lightning
数据导入"] end subgraph REALMIGRATION["实时同步"] DM["DM
Data Migration"] end LIGHTNING --> TIDB DM --> TIDB TIDB[("TiDB
目标数据库")] DUMP -.->|"支持并行导出
支持过滤表"| DUMP LIGHTNING -.->|"支持TB级导入
速度可达500GB/h"| LIGHTNING DM -.->|"支持增量同步
支持分库分表"| DM
典型迁移流程:
# 1. 使用Dumpling导出MySQL数据
tiup dumpling -u root -P 3306 -h mysql-host \
--filetype sql \
--output /data/backup \
--threads 8
# 2. 使用Lightning导入到TiDB
tiup tidb-lightning -config lightning.toml
# 3. 验证数据一致性
tiup sync_diff_inspector --config=diff.toml四、如何用好TiDB(性能调优)
4.1 热点问题
TiDB最常见的性能问题就是热点——大量请求集中在少数几个Region上。
33%"] N2["Region2
33%"] N3["Region3
34%"] end subgraph HOTSPOT["热点情况(一个Region被打爆)🔥"] H1["Region1
5%
😴 闲置"] H2["Region2
5%
😴 闲置"] H3["Region3
90%
🔥 爆炸!"] end style N1 fill:#90EE90 style N2 fill:#90EE90 style N3 fill:#90EE90 style H1 fill:#E0E0E0 style H2 fill:#E0E0E0 style H3 fill:#FF6B6B
常见热点原因和解决方案:
| 场景 | 原因 | 解决方案 |
|---|---|---|
| 自增主键写入 | 新数据都写到最后一个Region | 使用AUTO_RANDOM或SHARD_ROW_ID_BITS |
| 时间范围查询 | 按时间排序导致热点 | 复合主键/打散策略 |
| 单点高频更新 | 某条记录被频繁更新 | 拆分热点数据/缓存层 |
-- 解决自增主键热点
-- 方案1:使用AUTO_RANDOM(推荐)
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_RANDOM,
user_id BIGINT,
amount DECIMAL(10,2)
);
-- 方案2:使用SHARD_ROW_ID_BITS
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
amount DECIMAL(10,2)
) SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS = 4;4.2 索引设计
TiDB的索引和MySQL类似,但有些特殊考量:
-- 普通索引
CREATE INDEX idx_user ON orders(user_id);
-- 复合索引(遵循最左前缀原则)
CREATE INDEX idx_user_time ON orders(user_id, create_time);
-- 唯一索引
CREATE UNIQUE INDEX idx_order_no ON orders(order_no);
-- 表达式索引(TiDB特有)
CREATE INDEX idx_lower_email ON users((LOWER(email)));TiDB索引的特殊之处:
(聚簇索引)"] end subgraph TIKV2["TiKV Node 2"] IDX1["索引1 Region
(非聚簇)"] end subgraph TIKV3["TiKV Node 3"] IDX2["索引2 Region
(非聚簇)"] end IDX1 -.->|"回表查询
网络开销"| DATA IDX2 -.->|"回表查询
网络开销"| DATA
注意:TiDB的索引和表数据可能在不同的TiKV节点上,所以索引查询可能涉及网络开销。
4.3 SQL调优
-- 查看执行计划
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;
-- 强制使用某个索引
SELECT /*+ USE_INDEX(orders, idx_user) */ * FROM orders WHERE user_id = 123;
-- 使用IndexMerge(多个索引合并)
SELECT /*+ USE_INDEX_MERGE(orders, idx_user, idx_status) */ *
FROM orders
WHERE user_id = 123 OR status = 'paid';
-- 强制走TiFlash
SELECT /*+ READ_FROM_STORAGE(TIFLASH[orders]) */
DATE(create_time) AS dt, SUM(amount)
FROM orders
GROUP BY DATE(create_time);执行计划解读:
+----------------------------+----------+-----------+---------------+--------------------------------+
| id | estRows | task | access object | operator info |
+----------------------------+----------+-----------+---------------+--------------------------------+
| IndexLookUp_10 | 10.00 | root | | |
| ├─IndexRangeScan_8(Build) | 10.00 | cop[tikv] | table:orders | index:idx_user(user_id) |
| └─TableRowIDScan_9(Probe) | 10.00 | cop[tikv] | table:orders | keep order:false |
+----------------------------+----------+-----------+---------------+--------------------------------+
关键词解读:
- cop[tikv]: 在TiKV上执行
- cop[tiflash]: 在TiFlash上执行
- root: 在TiDB Server上执行
- IndexRangeScan: 索引范围扫描(好)
- TableFullScan: 全表扫描(通常不好)
- IndexLookUp: 索引回表(可能需要优化)4.4 参数调优
-- 查看当前配置
SHOW CONFIG;
-- 调整事务相关参数
SET GLOBAL tidb_txn_mode = 'pessimistic'; -- 悲观事务(默认)
SET GLOBAL tidb_txn_mode = 'optimistic'; -- 乐观事务
-- 调整内存限制
SET GLOBAL tidb_mem_quota_query = 1073741824; -- 单条SQL最大内存1GB
-- 调整并发参数
SET GLOBAL tidb_distsql_scan_concurrency = 15; -- 扫描并发度
SET GLOBAL tidb_index_lookup_concurrency = 4; -- 索引回表并发度五、TiDB的缺点(真相时刻)
好了,吹了这么多,是时候说说TiDB的坑了。毕竟"从入门到放弃"系列的精髓就在这里。
5.1 运维复杂度
• 主从复制
• 慢查询
• 备份恢复"] end subgraph TIDB["TiDB集群 😰"] T1["PD×3 + TiKV×3 + TiDB×2
+ TiFlash×1 + 监控
= 最少9个进程"] T2["关注点:
• 一堆机器
• Region分布
• Raft状态
• 热点问题
• PD调度
• GC策略
• 各种监控指标..."] end style MYSQL fill:#90EE90 style TIDB fill:#FFB6C1
运维痛点:
- 组件多:一个最小集群就要管理7-9个进程
- 学习曲线陡:需要理解Raft、Region、TSO等概念
- 监控指标多:Grafana面板有几十个,看哪个都像有问题
- 故障排查难:分布式系统的问题定位本身就是个坑
5.2 MySQL兼容性(不是100%)
虽然TiDB号称兼容MySQL,但...
-- ❌ 不支持的功能
CREATE TRIGGER ...; -- 触发器
CREATE PROCEDURE ...; -- 存储过程(部分支持)
SELECT GET_LOCK('lock_name', 10); -- 表级锁函数
SELECT SQL_CALC_FOUND_ROWS ...; -- 这个MySQL都deprecated了
-- ⚠️ 行为不一致的功能
SELECT * FROM t LIMIT 10; -- 不加ORDER BY结果可能不确定
AUTO_INCREMENT; -- 不保证连续,可能有空洞
FOREIGN KEY; -- 语法支持但不强制约束
-- 😱 让你踩坑的细节
SELECT LAST_INSERT_ID(); -- 批量INSERT时只返回第一条的ID
CHARACTER SET utf8; -- TiDB的utf8就是utf8mb4兼容性检查清单:
| 特性 | MySQL | TiDB | 备注 |
|---|---|---|---|
| 存储过程 | ✅ | ⚠️ | 部分支持 |
| 触发器 | ✅ | ❌ | 不支持 |
| 外键约束 | ✅ | ⚠️ | 仅语法支持,不强制 |
| XA事务 | ✅ | ❌ | 不支持 |
| 空间函数 | ✅ | ⚠️ | 部分支持 |
| JSON | ✅ | ✅ | 完整支持 |
5.3 性能问题
5.3.1 延迟高于单机MySQL
延迟高的原因:网络往返(TiDB→TiKV)、Raft协议开销、分布式事务开销。
对于延迟敏感的场景(如交易核心链路),需要慎重考虑。
5.3.2 小表性能反而不如MySQL
-- 这种查询MySQL可能更快
SELECT * FROM config WHERE key = 'settings';
-- 因为TiDB需要:
-- 1. TiDB解析SQL
-- 2. 从PD获取Region信息
-- 3. 从TiKV读取数据
-- 4. 返回结果
-- MySQL只需要:
-- 1. 解析SQL
-- 2. 从Buffer Pool读取
-- 3. 返回结果5.3.3 写入吞吐量受限于Region
每个Region同一时刻只有一个Leader处理写入,写入热点会成为瓶颈。
5.4 资源消耗
同样100GB数据的成本对比:
成本大约是MySQL的5-10倍。如果你的数据量不到TB级别,老老实实用MySQL分库分表可能更划算。
5.5 其他坑
5.5.1 GC可能引发性能抖动
TiDB需要定期GC清理历史版本,GC期间可能影响性能。
-- 查看GC状态
SELECT * FROM mysql.tidb WHERE VARIABLE_NAME LIKE '%gc%';
-- 调整GC生命周期(默认10分钟)
UPDATE mysql.tidb SET VARIABLE_VALUE = '24h' WHERE VARIABLE_NAME = 'tikv_gc_life_time';5.5.2 大事务限制
-- 单个事务默认限制
-- 事务大小: 100MB
-- 键值对数: 300,000
-- 如果你的批量操作超过限制,会报错:
-- Error: transaction is too large
-- 解决方案:分批提交5.5.3 冷启动慢
集群重启后,Region需要重新分配Leader,大集群可能需要等待数分钟才能完全可用。
六、什么时候该用TiDB?
别折腾了 😌"] START -->|Yes| SCALE["需要水平扩展?"] SCALE -->|No| READONLY["读写分离就够了吗?"] SCALE -->|Yes| ANALYTICS["需要实时分析?"] READONLY --> MYSQL ANALYTICS -->|No| CLICKHOUSE["ClickHouse可能更适合"] ANALYTICS -->|Yes| MAYBE["TiDB可能适合你!"] MAYBE --> OPS["团队有能力运维吗?"] OPS -->|No| CLOUD["用TiDB Cloud
托管服务 ☁️"] OPS -->|Yes| GO["上TiDB吧!🚀"] style MYSQL fill:#90EE90 style CLICKHOUSE fill:#87CEEB style CLOUD fill:#DDA0DD style GO fill:#FFD700
适合TiDB的场景:
- ✅ 数据量TB级以上,单机MySQL撑不住
- ✅ 需要MySQL兼容性,不想改造应用
- ✅ 业务增长快,需要弹性扩展能力
- ✅ 需要HTAP,不想维护两套系统
- ✅ 有专业的运维团队
不适合TiDB的场景:
- ❌ 数据量小于500GB,杀鸡用牛刀
- ❌ 对延迟极度敏感(<5ms)
- ❌ 重度依赖存储过程/触发器
- ❌ 预算有限,人力有限
- ❌ 领导只是想追求技术时髦
七、总结
TiDB是一个很优秀的分布式数据库,它确实解决了MySQL在大规模场景下的很多痛点。但是:
💡 "分布式系统的第一法则:能不分布式就不分布式"
—— 某个被分布式系统折磨过的程序员
如果你的业务真的需要TiDB的能力,那它确实是个好选择。但如果只是因为"分布式听起来很厉害"就上TiDB,那你可能正在"从入门到放弃"的路上狂奔。
最后送大家一句话:
技术选型没有银弹,只有最适合的方案。
在决定使用TiDB之前,请先问自己三个问题:
- 我真的需要它吗?
- 我有能力驾驭它吗?
- 我的预算够吗?
如果三个答案都是"Yes",那就大胆上吧!
如果有任何一个是"No"... 那就再想想。
参考资料
官方文档
- TiDB官方文档 - 最权威的资料,没有之一
- TiDB GitHub - 源码面前,了无秘密
- PingCAP博客 - 官方技术博客,干货满满
技术原理
- TiDB架构概述 - 了解TiDB的整体设计
- Percolator论文 - TiDB事务模型的理论基础
- Raft协议 - 理解分布式一致性的必读材料
实践指南
社区资源
- AskTUG - TiDB中文社区,问题求助好去处
- TiDB Talent Plan - PingCAP出品的分布式系统学习课程
视频教程
- PingCAP University - 官方培训课程
- TiDB入门系列 - B站 - 适合入门的视频教程
🎉 恭喜你读到了最后!如果这篇文章让你对TiDB有了更清晰的认识,那我的目的就达到了。如果它让你决定暂时不用TiDB,那也是一种收获——毕竟,知道什么时候不该用某个技术,和知道怎么用它一样重要。