TiKV存储引擎 #
一、TiKV概述 #
1.1 核心定位 #
TiKV 是 TiDB 的存储层,提供分布式、事务性的 Key-Value 存储服务。
text
TiKV 核心特性
├── 分布式存储
│ ├── 数据分片 (Region)
│ ├── 多副本复制
│ └── 水平扩展
│
├── 事务支持
│ ├── ACID 事务
│ ├── 分布式事务
│ └── MVCC
│
├── 高可用
│ ├── Raft 一致性协议
│ ├── 自动故障恢复
│ └── 强一致性
│
└── 高性能
├── RocksDB 存储
├── LSM-Tree 结构
└── 批量写入优化
1.2 架构层次 #
text
TiKV 架构层次
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ TiKV Server │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ gRPC Server │ │ │
│ │ │ (对外服务接口) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Storage Layer │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Transaction Manager │ │ │ │
│ │ │ │ (事务管理、MVCC、锁管理) │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Raft Layer │ │ │ │
│ │ │ │ (共识协议、日志复制) │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Region Manager │ │ │ │
│ │ │ │ (Region 分裂、合并、调度) │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ RocksDB Engine │ │ │
│ │ │ (底层存储引擎) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
二、Key-Value模型 #
2.1 数据编码 #
表数据编码
text
表数据 Key 编码
┌─────────────────────────────────────────────────────────────┐
│ │
│ SQL 表: │
│ CREATE TABLE users ( │
│ id BIGINT PRIMARY KEY, │
│ name VARCHAR(100), │
│ age INT │
│ ); │
│ │
│ Key 编码规则: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 行数据 Key: │ │
│ │ t{table_id}_r{row_id} │ │
│ │ │ │
│ │ 示例 (table_id = 10): │ │
│ │ id=1 → t10_r1 │ │
│ │ id=2 → t10_r2 │ │
│ │ id=3 → t10_r3 │ │
│ │ │ │
│ │ Value: │ │
│ │ [name, age] 编码后的二进制数据 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
索引编码
text
索引 Key 编码
┌─────────────────────────────────────────────────────────────┐
│ │
│ 索引类型: │
│ │
│ 1. 唯一索引 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Key: t{table_id}_i{index_id}{index_value} │ │
│ │ Value: {row_id} │ │
│ │ │ │
│ │ 示例: CREATE UNIQUE INDEX idx_email ON users(email)│ │
│ │ email='alice@test.com' → t10_i1'alice@test.com' │ │
│ │ Value: 1 (row_id) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. 非唯一索引 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Key: t{table_id}_i{index_id}{index_value}{row_id}│ │
│ │ Value: null │ │
│ │ │ │
│ │ 示例: CREATE INDEX idx_age ON users(age) │ │
│ │ age=25, row_id=1 → t10_i2'25'1 │ │
│ │ age=25, row_id=2 → t10_i2'25'2 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. 复合索引 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Key: t{table_id}_i{index_id}{col1}{col2}... │ │
│ │ │ │
│ │ 示例: CREATE INDEX idx_name_age ON users(name,age)│ │
│ │ name='Alice', age=25 → t10_i3'Alice'25 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 有序性保证 #
text
Key 有序性
┌─────────────────────────────────────────────────────────────┐
│ │
│ Key 编码保证有序性: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 表数据连续存储: │ │
│ │ t10_r1 → t10_r2 → t10_r3 → ... → t10_rn │ │
│ │ │ │
│ │ 索引数据连续存储: │ │
│ │ t10_i1'Alice' → t10_i1'Bob' → t10_i1'Carol' │ │
│ │ │ │
│ │ 不同表数据分开: │ │
│ │ t10_... (表10的数据) │ │
│ │ t11_... (表11的数据) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 优势: │
│ - 范围查询高效 │
│ - 顺序扫描高效 │
│ - 前缀匹配高效 │
│ │
└─────────────────────────────────────────────────────────────┘
三、Region管理 #
3.1 Region概念 #
text
Region 分片机制
┌─────────────────────────────────────────────────────────────┐
│ │
│ 整个 Key 空间 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ [minKey .............................. maxKey] │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 按 Range 切分为多个 Region │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Region 1 Region 2 Region 3 Region 4 │ │
│ │ [a, e) [e, k) [k, q) [q, z] │ │
│ │ 96MB 96MB 96MB 96MB │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Region 属性: │
│ ├── Region ID: 全局唯一标识 │
│ ├── Start Key: 起始 Key (包含) │
│ ├── End Key: 结束 Key (不包含) │
│ ├── Region Epoch: 版本号 (用于分裂/合并检测) │
│ └── Peers: 副本列表 │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 Region分裂 #
text
Region 分裂过程
┌─────────────────────────────────────────────────────────────┐
│ │
│ 分裂前: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Region 1 │ │
│ │ [a, z] │ │
│ │ 大小: 200MB │ │
│ │ Leader: TiKV 1 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 触发分裂 (大小超过阈值 144MB) │
│ │ │
│ ▼ │
│ 分裂后: │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Region 1 │ │ Region 2 │ │
│ │ [a, m) │ │ [m, z] │ │
│ │ 大小: 100MB │ │ 大小: 100MB │ │
│ │ Leader: TiKV 1 │ │ Leader: TiKV 1 │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ 分裂流程: │
│ 1. PD 发起分裂命令或 TiKV 自动触发 │
│ 2. Leader 选择分裂点 │
│ 3. 创建新 Region 元数据 │
│ 4. 更新 PD 元数据 │
│ 5. 后台异步迁移数据 │
│ │
└─────────────────────────────────────────────────────────────┘
3.3 Region合并 #
text
Region 合并过程
┌─────────────────────────────────────────────────────────────┐
│ │
│ 合并前: │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Region 1 │ │ Region 2 │ │
│ │ [a, f) │ │ [f, k) │ │
│ │ 大小: 10MB │ │ 大小: 15MB │ │
│ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ 触发合并 (相邻 Region 都小于 20MB) │
│ │ │
│ ▼ │
│ 合并后: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Region 1 │ │
│ │ [a, k) │ │
│ │ 大小: 25MB │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 合并条件: │
│ - 两个 Region 相邻 │
│ - 两个 Region 都小于阈值 │
│ - 没有进行中的分裂/合并 │
│ │
└─────────────────────────────────────────────────────────────┘
3.4 Region调度 #
text
Region 调度类型
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. Balance Leader │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 目的: 均衡各节点的 Leader 数量 │ │
│ │ 方式: 转移 Leader 到其他副本 │ │
│ │ │ │
│ │ TiKV 1 (80 Leaders) ──转移──► TiKV 2 (40 Leaders)│ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. Balance Region │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 目的: 均衡各节点的存储容量 │ │
│ │ 方式: 迁移 Region 副本 │ │
│ │ │ │
│ │ TiKV 1 (80% 容量) ──迁移──► TiKV 2 (40% 容量) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. Hot Region │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 目的: 分散热点 Region │ │
│ │ 方式: 打散热点 Region 的副本 │ │
│ │ │ │
│ │ 热点 TiKV 1 ──打散──► TiKV 2, TiKV 3 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
四、Raft一致性协议 #
4.1 Raft基础 #
text
Raft 共识算法
┌─────────────────────────────────────────────────────────────┐
│ │
│ Raft 角色: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Leader: │ │
│ │ ├── 处理所有客户端请求 │ │
│ │ ├── 日志复制到 Follower │ │
│ │ └── 心跳维护领导权 │ │
│ │ │ │
│ │ Follower: │ │
│ │ ├── 接收 Leader 日志 │ │
│ │ ├── 响应心跳 │ │
│ │ └── 参与选举投票 │ │
│ │ │ │
│ │ Candidate: │ │
│ │ ├── 发起选举 │ │
│ │ └── 争取多数票 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 多数派原则: │
│ - 写入需要多数派确认 │
│ - 选举需要多数派投票 │
│ - 容忍少数节点故障 │
│ │
└─────────────────────────────────────────────────────────────┘
4.2 Multi-Raft #
text
Multi-Raft 架构
┌─────────────────────────────────────────────────────────────┐
│ │
│ 每个 Region 一个 Raft Group: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Region 1 Raft Group │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Leader │ │Follower │ │Follower │ │ │
│ │ │ TiKV 1 │ │ TiKV 2 │ │ TiKV 3 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Region 2 Raft Group │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │Follower │ │ Leader │ │Follower │ │ │
│ │ │ TiKV 1 │ │ TiKV 2 │ │ TiKV 3 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Region 3 Raft Group │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │Follower │ │Follower │ │ Leader │ │ │
│ │ │ TiKV 1 │ │ TiKV 2 │ │ TiKV 3 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 优势: │
│ - 每个 Region 独立 Raft │
│ - 避免单 Raft 组性能瓶颈 │
│ - 支持大规模数据 │
│ │
└─────────────────────────────────────────────────────────────┘
4.3 日志复制 #
text
Raft 日志复制流程
┌─────────────────────────────────────────────────────────────┐
│ │
│ 写入请求流程: │
│ │
│ Client │
│ │ │
│ │ 1. 写请求 │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Leader (TiKV 1) │ │
│ │ │ │
│ │ 2. 追加日志到本地 │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Index: 1 2 3 4 5 │ │ │
│ │ │ Term: 1 1 1 1 1 │ │ │
│ │ │ Log: A B C D E (新日志) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 3. 并行发送 AppendEntries 到 Follower │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Follower │ │ Follower │ │
│ │ (TiKV 2) │ │ (TiKV 3) │ │
│ │ │ │ │ │
│ │ 4. 追加日志 │ │ 4. 追加日志 │ │
│ │ 5. 返回确认 │ │ 5. 返回确认 │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Leader (TiKV 1) │ │
│ │ │ │
│ │ 6. 收到多数派确认 (2/3) │ │
│ │ 7. 提交日志 (commit_index = 5) │ │
│ │ 8. 应用到状态机 │ │
│ │ 9. 返回客户端成功 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
4.4 Leader选举 #
text
Leader 选举过程
┌─────────────────────────────────────────────────────────────┐
│ │
│ 场景: Leader 故障 │
│ │
│ 1. Follower 超时未收到心跳 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Follower (TiKV 2) │ │
│ │ - election_timeout 到期 │ │
│ │ - 转为 Candidate │ │
│ │ - term++ │ │
│ │ - 投自己一票 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 2. 发送 RequestVote 给其他节点 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Candidate (TiKV 2) │ │
│ │ │ │ │
│ │ ├── RequestVote ──► TiKV 1 │ │
│ │ │ │ │
│ │ └── RequestVote ──► TiKV 3 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 3. 收集投票 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiKV 1: 投票给 TiKV 2 │ │
│ │ TiKV 2: 投票给自己 │ │
│ │ TiKV 3: 投票给 TiKV 2 │ │
│ │ │ │
│ │ 结果: 3/3 票,多数派通过 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 4. 成为新 Leader │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiKV 2 成为新 Leader │ │
│ │ - 立即发送心跳 │ │
│ │ - 开始处理请求 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
五、MVCC多版本控制 #
5.1 MVCC原理 #
text
MVCC 多版本并发控制
┌─────────────────────────────────────────────────────────────┐
│ │
│ Key-Value 扩展为 Key-Version-Value: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 传统 KV: │ │
│ │ Key → Value │ │
│ │ │ │
│ │ MVCC: │ │
│ │ Key + commit_ts → Value │ │
│ │ │ │
│ │ 示例: │ │
│ │ t10_r1_100 → [Alice, 25] (ts=100 时写入) │ │
│ │ t10_r1_200 → [Alice, 26] (ts=200 时更新) │ │
│ │ t10_r1_300 → [Bob, 26] (ts=300 时更新) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 版本可见性: │
│ - 读取时指定 start_ts │
│ - 只能看到 commit_ts < start_ts 的版本 │
│ - 实现快照隔离 │
│ │
└─────────────────────────────────────────────────────────────┘
5.2 数据版本示例 #
text
数据版本演变
┌─────────────────────────────────────────────────────────────┐
│ │
│ 操作序列: │
│ │
│ T1 (ts=100): INSERT INTO users VALUES (1, 'Alice', 25) │
│ T2 (ts=200): UPDATE users SET age=26 WHERE id=1 │
│ T3 (ts=300): UPDATE users SET name='Bob' WHERE id=1 │
│ T4 (ts=400): DELETE FROM users WHERE id=1 │
│ │
│ 存储结果: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Key │ commit_ts │ Value │ Type │ │
│ │ ─────────────────┼───────────┼─────────┼─────────│ │
│ │ t10_r1_100 │ 100 │ [Alice, │ Put │ │
│ │ │ │ 25] │ │ │
│ │ t10_r1_200 │ 200 │ [Alice, │ Put │ │
│ │ │ │ 26] │ │ │
│ │ t10_r1_300 │ 300 │ [Bob, │ Put │ │
│ │ │ │ 26] │ │ │
│ │ t10_r1_400 │ 400 │ - │ Delete │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 读取示例: │
│ - ts=150 读取 → [Alice, 25] │
│ - ts=250 读取 → [Alice, 26] │
│ - ts=350 读取 → [Bob, 26] │
│ - ts=450 读取 → 空 (已删除) │
│ │
└─────────────────────────────────────────────────────────────┘
5.3 版本回收 #
text
MVCC 垃圾回收
┌─────────────────────────────────────────────────────────────┐
│ │
│ 问题: 旧版本数据持续累积 │
│ │
│ 解决: GC (Garbage Collection) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ GC 流程: │ │
│ │ │ │
│ │ 1. 确定 safe_point │ │
│ │ - safe_point 之前的版本可以删除 │ │
│ │ - 由 PD 计算 │ │
│ │ │ │
│ │ 2. 扫描所有 Key │ │
│ │ - 找到 commit_ts < safe_point 的版本 │ │
│ │ │ │
│ │ 3. 删除旧版本 │ │
│ │ - 保留每个 Key 最新版本 │ │
│ │ - 删除其他旧版本 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 配置: │
│ tikv_gc_life_time = "10m" # 保留10分钟内的版本 │
│ │
└─────────────────────────────────────────────────────────────┘
六、事务模型 #
6.1 事务类型 #
text
TiKV 事务类型
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. 悲观事务 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 特点: │ │
│ │ - 修改前先加锁 │ │
│ │ - 避免写写冲突 │ │
│ │ - 适合冲突多的场景 │ │
│ │ │ │
│ │ 流程: │ │
│ │ BEGIN → SELECT FOR UPDATE → UPDATE → COMMIT │ │
│ │ (加锁) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. 乐观事务 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 特点: │ │
│ │ - 提交时检测冲突 │ │
│ │ - 冲突时回滚重试 │ │
│ │ - 适合冲突少的场景 │ │
│ │ │ │
│ │ 流程: │ │
│ │ BEGIN → SELECT → UPDATE → COMMIT │ │
│ │ (检测冲突) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
6.2 事务流程 #
text
乐观事务提交流程
┌─────────────────────────────────────────────────────────────┐
│ │
│ 阶段1: 获取 start_ts │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiDB Server ──请求──► PD │ │
│ │ ◄──start_ts=100── │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 阶段2: 读取数据 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiDB Server ──读取──► TiKV │ │
│ │ (start_ts=100) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 阶段3: 执行修改 (本地缓存) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiDB Server 本地缓存修改 │ │
│ │ 不写入 TiKV │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 阶段4: Prewrite (两阶段提交第一阶段) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 对每个修改的 Key: │ │
│ │ 1. 检查是否有冲突 (其他事务已提交) │ │
│ │ 2. 写入锁 (primary lock 或 secondary lock) │ │
│ │ 3. 写入数据 (start_ts 版本) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 阶段5: 获取 commit_ts │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TiDB Server ──请求──► PD │ │
│ │ ◄──commit_ts=110── │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 阶段6: Commit (两阶段提交第二阶段) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. 提交 Primary Key │ │
│ │ - 写入 commit_ts │ │
│ │ - 清除锁 │ │
│ │ │ │
│ │ 2. 异步提交 Secondary Keys │ │
│ │ - 可以延迟处理 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
七、RocksDB存储 #
7.1 RocksDB架构 #
text
RocksDB 存储架构
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ RocksDB │ │
│ │ │ │
│ │ 写入流程: │ │
│ │ │ │
│ │ ┌─────────┐ │ │
│ │ │ Write │ 1. 写入 WAL │ │
│ │ │ Request │ (预写日志) │ │
│ │ └────┬────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ MemTable│ 2. 写入内存表 │ │
│ │ │ (活跃) │ (跳表结构) │ │
│ │ └────┬────┘ │ │
│ │ │ 满 │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ MemTable│ 3. 转为不可变 │ │
│ │ │ (不可变)│ │ │
│ │ └────┬────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ Flush │ 4. 刷写到 SST 文件 │ │
│ │ │ to Disk │ │ │
│ │ └────┬────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ SST Files (LSM-Tree) │ │ │
│ │ │ │ │ │
│ │ │ L0 L1 L2 L3 L4 L5 L6 │ │ │
│ │ │ ↓ ↓ ↓ ↓ ↓ ↓ ↓ │ │ │
│ │ │ [新] ─────────────────────────→ [旧] │ │ │
│ │ │ │ │ │
│ │ │ Compaction: 后台压缩合并 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
7.2 两个RocksDB实例 #
text
TiKV 双 RocksDB 架构
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ TiKV │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Raft DB │ │ KV DB │ │ │
│ │ │ │ │ │ │ │
│ │ │ 存储: │ │ 存储: │ │ │
│ │ │ - Raft Log │ │ - 用户数据 │ │ │
│ │ │ - Raft 元数据 │ │ - MVCC 版本 │ │ │
│ │ │ │ │ - 锁信息 │ │ │
│ │ │ 特点: │ │ │ │ │
│ │ │ - 写入频繁 │ │ 特点: │ │ │
│ │ │ - 数据量小 │ │ - 数据量大 │ │ │
│ │ │ - 顺序写入 │ │ - 读写混合 │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 分离优势: │
│ - Raft 日志顺序写入,优化配置 │
│ - 用户数据随机读写,独立优化 │
│ - 避免相互影响 │
│ │
└─────────────────────────────────────────────────────────────┘
八、配置调优 #
8.1 关键配置 #
yaml
# TiKV 配置示例
[raftstore]
sync-log = true # 同步刷盘,保证数据安全
capacity = "100GB" # 存储容量限制
[rocksdb]
max-open-files = 4096 # 最大打开文件数
max-background-jobs = 8 # 后台线程数
[rocksdb.defaultcf]
block-size = "64KB" # 块大小
write-buffer-size = "128MB" # 写缓冲区大小
compression = "lz4" # 压缩算法
[rocksdb.writecf]
block-size = "64KB"
write-buffer-size = "128MB"
[raftdb]
max-open-files = 4096
8.2 性能参数 #
sql
-- 查看配置
SHOW CONFIG WHERE TYPE = 'tikv' AND NAME LIKE '%raftstore%';
-- 动态修改配置
SET CONFIG tikv `raftstore.sync-log` = true;
九、总结 #
TiKV 核心要点:
| 模块 | 要点 |
|---|---|
| Key-Value | 有序编码、表数据索引分离 |
| Region | 数据分片、分裂合并、调度 |
| Raft | 多Raft组、日志复制、选举 |
| MVCC | 多版本、快照隔离、GC |
| 事务 | 乐观/悲观、两阶段提交 |
| RocksDB | LSM-Tree、双实例 |
下一步,让我们学习 PD 调度器!
最后更新:2026-03-27