TiKV — 分布式事务 KV
是什么
TiKV 是一个分布式的、支持事务的 key-value 存储。日常类比:把一本超大的电话簿撕成几百段,每段交给三家”分馆”一起抄一份;任何一家分馆失火,另外两家还能继续查;要修改条目时,三家先举手投票确认,再一起改。
更准确点:
- 用 Rust 写,由 PingCAP 2016 年开源
- 每个节点本地存储用 RocksDB(一个文件型 LSM-Tree 引擎,下层”硬盘”)
- 数据按 key 顺序切成一段段叫 Region,每段默认 96MB
- 每个 Region 自己有一个 Raft 组(一般 3 副本),独立选 leader、独立复制
- 集群顶上还有一个调度大脑叫 Placement Driver(PD),管元数据 + 发全局时间戳
它是 TiDB 的存储层(TiDB 是 SQL 层),但 TiKV 自己就能单独当 KV 用,2020 年 9 月从 CNCF 毕业。
为什么重要
不理解 TiKV,下面这些事都没法解释:
- 为什么 TiDB 敢说”MySQL 兼容 + 水平扩展 + 强一致事务”——它把 KV 这一层独立做完整了
- 为什么 Rust 在分布式基础设施圈这么受关注——TiKV 是少数几个工业级、跑生产、还活跃维护的 Rust 大型项目
- Google 2010 年的 Percolator 论文到底怎么落地的——TiKV 是开源世界最完整的实现
- “Multi-Raft”(不是单一 Raft)这个工程模式怎么运转——TiKV 把它跑到了极致:单节点同时跑上百个 Raft 组
核心要点
TiKV 的整体架构可以拆成 四层:
-
本地引擎:每节点跑两个 RocksDB 实例。一个存真正的数据,另一个专门存 Raft 日志(写入路径上 Raft log 必须先落盘,分开能减少互相干扰)。
-
Region + Multi-Raft:所有 key 按字典序排成一条长线,每 96MB 切一刀,叫一个 Region。每个 Region 是一个独立的 Raft 组,3 副本分散在 3 个节点。一个节点同时是上百个 Region 的成员——这就是 Multi-Raft,区别于”整集群一个 Raft”的简化模型。
-
PD(Placement Driver):另一个独立进程(通常 3 副本,用 etcd 做一致性)。它干两件事:(a) 元数据——告诉客户端某个 key 在哪个 Region、leader 是谁;(b) TSO——全局递增时间戳服务,给事务用。PD 自己不存数据。
-
事务层(Percolator):模仿 Google Percolator 论文的 2PC——先在所有 key 上写”锁列”占位,再用 PD 给的 commit 时间戳一次性提交。读的时候按时间戳看见对应版本(MVCC)。
实践案例
案例 1:写一条数据,幕后发生了什么
客户端调用 put("k1", "v1"):
- 客户端先问 PD:“k1 归哪个 Region?leader 在哪个节点?“(结果会本地缓存)
- 请求发到该 Region 的 leader
- leader 把这条写打包成 Raft log 提案,复制到 2 个 follower
- 多数派(leader + 1 个 follower)落盘后,Raft log 就 committed
- leader 把 log 应用到状态机(写到数据 RocksDB),返回给客户端
整个过程只有这一个 Region 的 3 个节点参与,其他几百个 Region 在干自己的活——这就是 Multi-Raft 能水平扩展的原因。
案例 2:跨 Region 事务(Percolator)
事务要改 100 个 key,分布在 10 个 Region 上:
- 客户端从 PD 拿一个 start_ts(开始时间戳)
- 选一个 key 当”主锁”(primary lock),其它 99 个是”从锁”
- Prewrite 阶段:把所有 100 个 key 的”锁记录”写下去(每个 key 在它自己的 Region 走一遍 Raft)
- 全部成功后,从 PD 拿一个 commit_ts
- Commit 阶段:先提交 primary 那一个,从锁可以异步清理
- 读的时候,按 commit_ts 选 MVCC 版本
如果 prewrite 中途崩了,下一次有事务读到挂着的锁,会去查 primary 的状态——primary 还没 commit,从锁就回滚;commit 了,从锁就跟着 commit。这就是 Percolator 用一个 primary 串起整个事务的核心。
案例 3:Multi-Region 跨 DC 部署
某团队在北京、上海各有一个机房:
- 用 Placement Rules 强制要求每个 Region 在两地都有副本(比如 5 副本:北京 3 + 上海 2)
- 上海的应用读数据,开 Follower Read——不必跨地域去问 leader,本地副本读就行(牺牲一点延迟换数据时效)
- 部分极远的副本可以设成 Learner——接 Raft log 但不投票,不影响多数派延迟
这套组合让 TiKV 能在跨大洲部署里同时拿到”强一致事务 + 就近读”。
案例 4:TiFlash 接 Raft log 做 OLAP
同一份订单数据,既要支持”按订单号查一条”(OLTP,TiKV 强项),又要支持”按时间维度做销售统计”(OLAP,列存才合适):
- TiFlash 节点作为 Raft learner 加入每个 Region 的 Raft 组——接 log 但不投票
- 收到 log 后转成列式格式存到本地 ClickHouse 风格引擎里
- TiDB 的优化器会自动选:点查走 TiKV 行存,分析查询走 TiFlash 列存
- 一份数据两种形态,不需要 ETL 同步——HTAP 概念在 TiDB 这套体系里就这么落地的
踩过的坑
- 不是单 Raft:很多人以为整集群一个 Raft,因此推不动。TiKV 是 每个 Region 一个 Raft 组,节点同时跑上百组。
- 事务不是 Spanner:没用 TrueTime,用的是 PD 的 TSO(单点全局时间戳服务)——所以 PD 的可用性极其关键,但 PD 本身用 etcd Raft 做了高可用。
- Region 大小是 96MB 不是 64MB:这是文档里反复见到的常见错记。也可调,但默认 96。
- TiKV 不是 SQL:纯 KV。SQL 在 TiDB 这一层;列存 OLAP 在 TiFlash 那个独立进程(接 Raft log 当 learner 拿数据)。
- 写放大:本地 RocksDB 是 LSM-Tree,加上 Raft log 又一份,再加 MVCC 多版本——磁盘空间和 IO 比单机数据库都更高,做容量规划时要算清楚。
- PD 是单点服务但不是单点故障:PD 看起来”全局唯一”,容易让人担心瓶颈。其实 PD 自身是 3 副本 etcd,TSO 也能做到几十万 QPS;真正瓶颈往往是网络 RTT 而非 PD 处理力。
- Region 太多会拖慢心跳:节点上 Region 数量过万会让 Raft 心跳和元数据上报压力暴增——所以默认要把空闲 Region 合并(merge),新数据时再分裂(split)。
适用 vs 不适用场景
适用:
- 想要”水平扩展 + 强一致事务”的 KV 场景(金融账单、库存、订单)
- 作为 TiDB 的底层,跑 NewSQL(兼容 MySQL 协议 + 分布式)
- HTAP:TiKV 跑 OLTP,TiFlash 跑 OLAP,同一份数据两个引擎
- 跨 DC 多活/灾备,需要 placement rule 灵活安排副本
不适用:
- 单机几 GB 数据量——上 TiKV 是用大炮打蚊子,直接 RocksDB / SQLite 就够
- 极低延迟(亚毫秒)KV——Raft + Percolator 多一轮 RTT,单机内存 KV 才能做到
- 海量小 key 高频写(计数器场景)——Region 元数据和 Raft 状态都是开销
- 没有专职 SRE 的小团队——PD / TiKV / TiDB / TiFlash 四层运维不轻松
历史小故事(可跳过)
- 2015 年:PingCAP 三位创始人刘奇 / 黄东旭 / 崔秋离开豌豆荚,受 Google Spanner / F1 论文启发,开始做”开源版 Spanner”。最早叫 TiDB(Ti = titanium,钛)
- 2016 年 4 月:TiKV 作为 TiDB 的存储层独立开源,第一版用 Go 写,几个月后整体重写成 Rust——理由是 Go GC 在 KV 这种延迟敏感场景抖动太大
- 2018 年:捐给 CNCF,进入 sandbox
- 2019 年:升级到 incubating
- 2020 年 9 月:CNCF 毕业,成为继 etcd 之后第二个 Raft 系毕业存储项目
学到什么
- “分片 + 共识”是分布式存储的标准做法:TiKV 的 Region + Multi-Raft 是这套组合的工业级范本,几乎所有现代 NewSQL(CockroachDB / YugabyteDB / OceanBase)都走类似套路
- 存储和计算分层是大势:TiKV 只做 KV,SQL 给 TiDB,列存给 TiFlash——每层自己演化、自己迭代版本,不互相绑死
- 2PC 不一定要 Spanner 那么贵:Percolator 用一个全局 TSO + primary lock 也能撑起百节点级强一致事务,代价是 PD 不能太远(跨大洲会拖慢提交)
- CNCF 毕业项目里 Rust 占比正在上升:TiKV 是开路先锋之一,证明 Rust 不仅能写浏览器引擎,也能写工业级分布式存储
延伸阅读
- 官方架构文档:TiKV docs
- 论文:Google Percolator 2010(TiKV 事务的祖宗)
- TiKV 源码导读:tikv/tikv on GitHub
- etcd —— 同样基于 Raft,但只做元数据级小数据,对照看
- raft-consensus —— TiKV Multi-Raft 的理论基础(如已收录)
关联
- etcd —— 都用 Raft,etcd 是单 Raft 元数据存储,TiKV 是 Multi-Raft 大数据存储
- rocksdb —— TiKV 节点本地引擎(如已收录)
- spanner-2012 —— 另一条路线:TrueTime 而非全局 TSO(如已收录)
- cncf-graduated —— TiKV 2020 毕业项目之一(如已收录)
一句话总结
TiKV = Rust 写的”分片 + Multi-Raft + Percolator 事务”分布式 KV,靠一个独立的 PD 大脑发全局时间戳和管 Region 调度,TiDB 的存储底座。理解它,就理解了 NewSQL 时代 OLTP 存储层的工业级范式。