Tikv是PingCAP开源的一款分布式KV数据库,这里摘录一些学习过程中的笔记,基本是摘自PingCAP的官网,在开源这块,PingCAP无疑是非常优秀的,学习资料很多,质量很高,所以这里就直接引用官网中的学习资料,摘录并学习,因为他们真的质量很高。
可参考:tikv简介
Tikv概述
TiKV 是一个分布式事务型的键值数据库,提供了满足 ACID 约束的分布式事务接口,并且通过 Raft 协议 保证了多副本数据一致性以及高可用。与传统的整节点备份方式不同,TiKV 参考 Spanner 设计了 multi raft-group 的副本机制。将数据按照 key 的范围划分成大致相等的切片(下文统称为 Region),每一个切片会有多个副本(通常是 3 个),其中一个副本是 leader,提供读写服务。TiKV 通过 PD 对这些 Region 以及副本进行调度,以保证数据和读写负载都均匀地分散在各个 TiKV 上,这样的设计保证了整个集群资源的充分利用并且可以随着机器数量的增加水平扩展。
Region 与 RocksDB
虽然 TiKV 将数据按照范围切割成了多个 Region,但是同一个节点的所有 Region 数据仍然是不加区分地存储于同一个 RocksDB 实例上,而用于 Raft 协议复制所需要的日志则存储于另一个 RocksDB 实例。这样设计的原因是因为随机 I/O 的性能远低于顺序 I/O,所以 TiKV 使用同一个 RocksDB 实例来存储这些数据,以便不同 Region 的写入可以合并在一次 I/O 中。
Region 与 Raft 协议
Region 与副本之间通过 Raft 协议来维持数据一致性,任何写请求都只能在 leader 上写入,并且需要写入多数副本后(默认配置为 3 副本,即所有请求必须至少写入两个副本成功)才会返回客户端写入成功。
当某个 Region 的大小超过一定限制(默认是 144MB)后,TiKV 会将它分裂为两个或者更多个 Region,以保证各个 Region 的大小是大致接近的,这样更有利于 PD 进行调度决策。同样的,当某个 Region 因为大量的删除请求导致 Region 的大小变得更小时,TiKV 会将比较小的两个相邻 Region 合并为一个。
当 PD 需要把某个 Region 的一个副本从一个 TiKV 节点调度到另一个上面时,PD 会先为这个 Raft Group 在目标节点上增加一个 Learner 副本(虽然会复制 leader 的数据,但是不会计入写请求的多数副本中)。当这个 Learner 副本的进度大致追上 Leader 副本时,Leader 会将他变更为 Follower,之后再移除操作节点的 Follower 副本,这样就完成了 Region 副本的一次调度。
Leader 副本的调度原理也类似,不过需要在目标节点的 Learner 副本变为 Follower 副本后,再执行一次 Leader Transfer,让该 Follower 主动发起一次选举成为新 Leader,之后新 Leader 负责删除旧 Leader 这个副本。
分布式事务
TiKV 支持分布式事务,用户(或者 TiDB)可以一次性写入多个 key-value 而不必关心这些 key-value 是否处于同一个数据切片 (Region) 上,TiKV 通过两阶段提交保证了这些读写请求的 ACID 约束
相比直接落rocksbd,采用tikv多了很多过程。
优势:
- Rust开发,底层存储引擎Rocksdb。
- 异地复制:使用Raft和Placement Driver进行异地复制来保证数据的安全性。
- 水平扩展:直接增加节点即可实现系统扩容一致性分布式事务:使用基于Google Percolator、优化后的两阶段提交协议来支持分布式事务。可以使用“begin”来开启事务,再使用“commit”提交事务或者“rollback”来回滚事务。
怎么部署?
可参考TiDB 整体架构
TiDB相当于Tikv的客户端。
PD Server:整个 TiDB 集群的元信息管理模块,负责存储每个 TiKV 节点实时的数据分布情况和集群的整体拓扑结构,提供 TiDB Dashboard 管控界面,并为分布式事务分配事务 ID。PD 不仅存储元信息,同时还会根据 TiKV 节点实时上报的数据分布状态,下发数据调度命令给具体的 TiKV 节点,可以说是整个集群的“大脑”。此外,PD 本身也是由至少 3 个节点构成,拥有高可用的能力。建议部署奇数个 PD 节点。
存储节点
TiKV Server:负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range(从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region。TiKV 的 API 在 KV 键值对层面提供对分布式事务的原生支持,默认提供了 SI (Snapshot Isolation) 的隔离级别,这也是 TiDB 在 SQL 层面支持分布式事务的核心。TiDB 的 SQL 层做完 SQL 解析后,会将 SQL 的执行计划转换为对 TiKV API 的实际调用。所以,数据都存储在 TiKV 中。另外,TiKV 中的数据都会自动维护多副本(默认为三副本),天然支持高可用和自动故障转移。
实现思路
Rocksdb+Raft
Raft协议
TiKV 利用 Raft 来做数据复制,每个数据变更都会落地为一条 Raft 日志,通过 Raft 的日志复制功能,将数据安全可靠地同步到复制组的每一个节点中。不过在实际写入中,根据 Raft 的协议,只需要同步复制到多数节点,即可安全地认为数据写入成功。
总结一下,通过单机的 RocksDB,TiKV 可以将数据快速地存储在磁盘上;通过 Raft,将数据复制到多台机器上,以防单机失效。数据的写入是通过 Raft 这一层的接口写入,而不是直接写 RocksDB。通过实现 Raft,TiKV 变成了一个分布式的 Key-Value 存储,少数几台机器宕机也能通过原生的 Raft 协议自动把副本补全,可以做到对业务无感知。
TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。
TiKV 使用了 RocksDB 的 Column Families (CF) 特性。
默认 RocksDB 实例将 KV 数据存储在内部的 default、write 和 lock 3 个 CF 内。
default CF 存储的是真正的数据,与其对应的参数位于 [rocksdb.defaultcf] 项中;
write CF 存储的是数据的版本信息 (MVCC) 以及索引相关的数据,相关的参数位于 [rocksdb.writecf] 项中;
lock CF 存储的是锁信息,系统使用默认参数。
Raft RocksDB 实例存储 Raft log。
default CF 主要存储的是 Raft log,与其对应的参数位于 [raftdb.defaultcf] 项中。
编程
这里是具体怎么部署,怎么在开发中应用tikv。