Database · #tidb#distributed-database#newsql

TiDB分布式数据库架构解析

2025.03.12 8 min 3.1k
// 目录 · contents

引言

传统的分库分表方案虽然解决了单机数据库的容量和性能瓶颈,但引入了大量的业务复杂性:跨分片查询、分布式事务、数据迁移等问题让开发和运维成本居高不下。NewSQL数据库的出现正是为了在不牺牲SQL能力的前提下,提供原生的分布式存储和计算能力。TiDB是国内最具代表性的NewSQL数据库,由PingCAP公司开发,兼容MySQL协议,提供水平扩展、强一致性和HTAP能力。

TiDB 整体架构

graph TD
    Client[客户端<br/>MySQL协议兼容] --> TiDB1[TiDB Server 1<br/>SQL Layer]
    Client --> TiDB2[TiDB Server 2<br/>SQL Layer]
    Client --> TiDB3[TiDB Server N<br/>SQL Layer]

    TiDB1 --> PD[PD Cluster<br/>Placement Driver<br/>元数据 + 调度]
    TiDB2 --> PD
    TiDB3 --> PD

    TiDB1 --> TiKV1[TiKV Node 1<br/>Region 1, Region 5]
    TiDB1 --> TiKV2[TiKV Node 2<br/>Region 2, Region 6]
    TiDB2 --> TiKV3[TiKV Node 3<br/>Region 3, Region 7]
    TiDB3 --> TiKV4[TiKV Node N<br/>Region 4, Region 8]

    TiDB1 --> TiFlash1[TiFlash Node<br/>列式存储副本]

    PD --> TiKV1
    PD --> TiKV2
    PD --> TiKV3
    PD --> TiKV4

    TiKV1 <-->|Raft| TiKV2
    TiKV2 <-->|Raft| TiKV3
    TiKV3 <-->|Raft| TiKV4

TiDB的架构由三个核心组件组成:

组件 角色 特点
TiDB Server SQL计算层 无状态,水平扩展,MySQL协议兼容
TiKV 分布式存储层 有状态,KV存储,Raft复制
PD (Placement Driver) 调度中心 元数据管理,TSO时钟,负载均衡

TiDB Server:SQL 计算层

功能职责

TiDB Server是无状态的SQL计算节点,负责接收SQL请求、解析优化、生成执行计划并从TiKV获取数据。

flowchart TD
    A[Client SQL] --> B[Protocol Layer<br/>MySQL协议解析]
    B --> C[Parser<br/>SQL解析为AST]
    C --> D[Planner<br/>逻辑优化 + 物理优化]
    D --> E[Executor<br/>火山模型/向量化执行]
    E --> F{DistSQL API}
    F --> G[TiKV Coprocessor<br/>下推计算]
    F --> H[TiFlash<br/>OLAP查询]

SQL 兼容性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-- TiDB高度兼容MySQL语法
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
amount DECIMAL(10, 2),
status VARCHAR(20),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_status_time (status, created_at)
);

-- 支持MySQL的大部分功能
-- 事务
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- 窗口函数
SELECT user_id, amount,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn
FROM orders;

-- CTE
WITH RECURSIVE cte AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM cte WHERE n < 10
)
SELECT * FROM cte;

-- JSON支持
SELECT * FROM products WHERE JSON_EXTRACT(attributes, '$.brand') = 'Apple';

-- 视图
CREATE VIEW active_orders AS
SELECT * FROM orders WHERE status = 'active';

计算下推

TiDB会将部分计算下推到TiKV的Coprocessor执行,减少网络传输:

sequenceDiagram
    participant TiDB as TiDB Server
    participant TiKV1 as TiKV Region 1
    participant TiKV2 as TiKV Region 2
    participant TiKV3 as TiKV Region 3

    Note over TiDB: SELECT COUNT(*) FROM orders WHERE status='paid'

    TiDB->>TiKV1: Coprocessor请求<br/>过滤 status='paid' 并 COUNT
    TiDB->>TiKV2: Coprocessor请求
    TiDB->>TiKV3: Coprocessor请求

    TiKV1->>TiDB: count=1500
    TiKV2->>TiDB: count=2300
    TiKV3->>TiDB: count=1800

    Note over TiDB: 汇总: 1500+2300+1800=5600
    TiDB->>TiDB: 返回 COUNT=5600

可下推的操作: - 过滤条件(WHERE) - 聚合函数(COUNT, SUM, AVG, MIN, MAX) - TopN(ORDER BY + LIMIT) - 表达式计算

TiKV:分布式存储层

Region 分片

TiKV将整个Key-Value空间按Key的范围划分为多个Region,每个Region默认大小96MB。

graph LR
    subgraph "Key Space"
        R1["Region 1<br/>[Key_a, Key_d)"]
        R2["Region 2<br/>[Key_d, Key_h)"]
        R3["Region 3<br/>[Key_h, Key_m)"]
        R4["Region 4<br/>[Key_m, Key_z)"]
    end

    subgraph "TiKV Nodes"
        N1[Node 1]
        N2[Node 2]
        N3[Node 3]
    end

    R1 -->|Leader| N1
    R1 -->|Follower| N2
    R1 -->|Follower| N3
    R2 -->|Leader| N2
    R3 -->|Leader| N3
    R4 -->|Leader| N1

数据编码

TiDB将SQL表数据编码为KV对存储在TiKV中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
行数据编码:
Key: tablePrefix{tableID}_recordPrefixSep{rowID}
Value: [col1, col2, col3, ...]

索引数据编码:
唯一索引:
Key: tablePrefix{tableID}_indexPrefixSep{indexID}{indexColumnValues}
Value: rowID

非唯一索引:
Key: tablePrefix{tableID}_indexPrefixSep{indexID}{indexColumnValues}{rowID}
Value: null

示例: 表ID=10, 索引ID=1
行记录: t10_r1 -> ["Alice", 25, "[email protected]"]
索引记录: t10_i1_Alice -> 1 (name索引)

Raft 复制

每个Region使用Raft协议在多个TiKV节点间复制,保证数据的强一致性。

sequenceDiagram
    participant C as TiDB
    participant L as Leader
    participant F1 as Follower 1
    participant F2 as Follower 2

    C->>L: Write Request
    L->>L: 写入Raft Log
    L->>F1: Append Entries
    L->>F2: Append Entries

    F1->>L: ACK
    F2->>L: ACK

    Note over L: 过半数确认(Quorum)<br/>提交日志

    L->>L: Apply to RocksDB
    L->>C: Write Success

    Note over F1, F2: 异步Apply to RocksDB

Raft的关键特性: - Leader选举:每个Region的Raft Group选举一个Leader,所有读写请求由Leader处理 - 日志复制:写入必须在过半数节点(Quorum)确认后才提交 - Leader Transfer:PD可以调度Leader在节点间迁移,实现负载均衡

Multi-Raft

TiKV采用Multi-Raft架构,每个Region是一个独立的Raft Group:

graph TD
    subgraph "Node 1"
        A1["Region 1 (Leader)"]
        A2["Region 3 (Follower)"]
        A3["Region 5 (Leader)"]
    end

    subgraph "Node 2"
        B1["Region 1 (Follower)"]
        B2["Region 3 (Leader)"]
        B3["Region 5 (Follower)"]
    end

    subgraph "Node 3"
        C1["Region 1 (Follower)"]
        C2["Region 3 (Follower)"]
        C3["Region 5 (Follower)"]
    end

    A1 <-->|Raft| B1
    A1 <-->|Raft| C1
    A2 <-->|Raft| B2
    A2 <-->|Raft| C2
    A3 <-->|Raft| B3
    A3 <-->|Raft| C3

PD:调度中心

PD 的核心职责

graph TD
    PD[PD Cluster<br/>基于etcd] --> F1[TSO时钟分配<br/>全局唯一递增时间戳]
    PD --> F2[元数据存储<br/>Region -> Store映射]
    PD --> F3[Region调度<br/>负载均衡 热点打散]
    PD --> F4[Label调度<br/>跨机房/跨AZ部署]

TSO(Timestamp Oracle)

PD负责分配全局唯一的时间戳(TSO),用于MVCC和事务排序:

1
2
3
4
5
6
7
TSO格式 (64 bits):
+----------------------------------+------------------+
| 物理时间 (ms) | 逻辑计数器 |
| 高46位 | 低18位 |
+----------------------------------+------------------+

每毫秒可分配 2^18 = 262,144 个时间戳

调度策略

flowchart TD
    A[PD调度器] --> B[Region均衡调度]
    A --> C[Leader均衡调度]
    A --> D[热点调度]
    A --> E[Region分裂/合并]

    B --> B1["当节点间Region数量差异过大<br/>迁移Region到负载低的节点"]
    C --> C1["当节点间Leader数量差异过大<br/>Transfer Leader到负载低的节点"]
    D --> D1["检测热点Region<br/>分裂热点Region<br/>调度Leader到不同节点"]
    E --> E1["Region > 96MB: 分裂为两个Region<br/>Region < 20MB且相邻: 合并"]

分布式事务

TiDB实现了Percolator模型的分布式事务,支持Snapshot Isolation。

事务执行流程

sequenceDiagram
    participant C as TiDB
    participant PD as PD (TSO)
    participant TiKV as TiKV

    Note over C: BEGIN TRANSACTION

    C->>PD: 获取 start_ts
    PD->>C: start_ts = 100

    Note over C: 执行SQL读写操作...
    C->>TiKV: 读取数据 (snapshot at ts=100)
    TiKV->>C: 返回数据
    C->>C: 在内存缓存写入

    Note over C: COMMIT

    Note over C, TiKV: Phase 1: Prewrite
    C->>TiKV: Prewrite (选择一个key作为Primary)
    TiKV->>TiKV: 检查冲突, 写入Lock + Data
    TiKV->>C: Prewrite OK

    C->>PD: 获取 commit_ts
    PD->>C: commit_ts = 105

    Note over C, TiKV: Phase 2: Commit
    C->>TiKV: Commit Primary Key (commit_ts=105)
    TiKV->>TiKV: 清除Lock, 写入Commit记录
    TiKV->>C: Commit OK

    Note over C: 事务成功, 异步清理Secondary Locks
    C->>TiKV: 异步Commit Secondary Keys

乐观事务 vs 悲观事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- TiDB默认使用悲观事务(与MySQL行为一致)
-- tidb_txn_mode = 'pessimistic' (默认)

-- 悲观事务:在执行DML时立即加锁
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 立即加悲观锁
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

-- 乐观事务:只在Commit时检查冲突
SET tidb_txn_mode = 'optimistic';
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 不加锁,只在Commit时检查
COMMIT; -- 如果有冲突,事务会失败,需要重试
维度 悲观事务 乐观事务
冲突检测时机 DML执行时 Commit时
冲突处理 等待锁释放 事务重试
适用场景 高冲突(默认推荐) 低冲突,高吞吐
MySQL兼容性 行为一致 需要应用层重试逻辑

HTAP 与 TiFlash

HTAP 架构

TiDB通过TiFlash列式存储引擎实现了HTAP(混合事务分析处理)能力。

graph TD
    subgraph "OLTP Path"
        TiDB1[TiDB] --> TiKV1[TiKV<br/>行存储<br/>事务处理]
    end

    subgraph "OLAP Path"
        TiDB2[TiDB] --> TiFlash1[TiFlash<br/>列存储<br/>分析查询]
    end

    TiKV1 -->|Raft Learner<br/>异步复制| TiFlash1

    subgraph "智能路由"
        TiDB3[TiDB优化器] --> R{查询类型?}
        R -->|点查/事务| TiKV1
        R -->|分析/聚合| TiFlash1
        R -->|混合| TiKV1
        R -->|混合| TiFlash1
    end

TiFlash 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 为表创建TiFlash副本
ALTER TABLE orders SET TIFLASH REPLICA 1;

-- 查看TiFlash副本进度
SELECT * FROM information_schema.tiflash_replica;

-- TiDB优化器自动选择行存还是列存
-- 也可以通过Hint强制指定
SELECT /*+ READ_FROM_STORAGE(TIFLASH[orders]) */
DATE_FORMAT(created_at, '%Y-%m') AS month,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
WHERE created_at >= '2025-01-01'
GROUP BY month
ORDER BY month;

-- 强制使用TiKV
SELECT /*+ READ_FROM_STORAGE(TIKV[orders]) */
* FROM orders WHERE id = 12345;

TiFlash vs TiKV 对比

维度 TiKV TiFlash
存储格式 行存(RocksDB) 列存(Delta Tree)
适用查询 点查、小范围查询 聚合、扫描、分析
数据一致性 Raft Leader读 Raft Learner,强一致读
压缩率 一般 高(列式压缩)

TiDB vs CockroachDB

graph LR
    subgraph "TiDB"
        TA[MySQL协议兼容] --> TB[TiKV: Rust实现]
        TB --> TC[RocksDB存储引擎]
        TA --> TD[Percolator事务模型]
        TA --> TE[TiFlash HTAP]
    end

    subgraph "CockroachDB"
        CA[PostgreSQL协议兼容] --> CB[Go实现<br/>计算存储一体]
        CB --> CC[Pebble存储引擎]
        CA --> CD[Serializable隔离级别]
        CA --> CE[原生多区域部署]
    end
维度 TiDB CockroachDB
协议兼容 MySQL PostgreSQL
实现语言 Go (TiDB) + Rust (TiKV) Go
架构 计算存储分离 计算存储一体
默认隔离级别 Snapshot Isolation Serializable
HTAP TiFlash列存 无专门列存
多区域 TiDB 6.0+ Placement Rules 原生支持
开源协议 Apache 2.0 BSL (核心功能)
生态 国内生态更好 海外生态更好

运维与监控

关键监控指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- TiDB Dashboard (内置Web UI)
-- 访问: http://<pd-address>:2379/dashboard

-- 关键SQL查询
-- 查看集群版本
SELECT tidb_version();

-- 查看Region分布
SELECT * FROM information_schema.tikv_region_status
WHERE db_name = 'mydb' AND table_name = 'orders'
LIMIT 10;

-- 查看热点Region
SELECT * FROM information_schema.tidb_hot_regions
ORDER BY flow_bytes DESC LIMIT 10;

-- 慢查询日志
SELECT * FROM information_schema.slow_query
WHERE time > '2025-03-15 00:00:00'
ORDER BY query_time DESC LIMIT 10;

-- 查看执行计划
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 1 AND status = 'paid';

扩缩容操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用tiup管理TiDB集群

# 扩容TiKV节点
tiup cluster scale-out <cluster-name> scale-out.yaml

# scale-out.yaml
# tikv_servers:
# - host: 192.168.1.104
# port: 20160
# deploy_dir: /data/tikv

# 缩容TiKV节点
tiup cluster scale-in <cluster-name> --node 192.168.1.104:20160

# PD会自动将该节点的Region调度到其他节点
# 数据迁移完成后节点自动下线

# 查看集群状态
tiup cluster display <cluster-name>

# 升级集群
tiup cluster upgrade <cluster-name> v7.5.0

总结

TiDB作为NewSQL数据库的代表,在很多场景下可以替代传统的分库分表方案:

  • 架构设计精巧:TiDB(无状态SQL层)+ TiKV(Raft分布式存储)+ PD(智能调度)三层分离
  • MySQL高度兼容:大部分MySQL应用可以低成本迁移
  • Raft保证强一致性:数据不会丢失,读取一致
  • 分布式事务支持悲观和乐观两种模式,默认悲观事务与MySQL行为一致
  • HTAP能力:TiFlash列存引擎让同一份数据同时服务于OLTP和OLAP
  • 自动运维:Region自动分裂/合并/调度,扩缩容对业务透明
  • 但也有局限性:单行事务延迟高于单机MySQL(网络RTT),不适合延迟要求极高的场景;运维复杂度高于单机数据库
作者 · authorzt
发布 · date2025-03-12
篇幅 · length3.1k 字 · 8 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论