前言
好玩的是,饿了么基于TiKV 构建统一KV系统,TiKV 之上增加了redis协议
本文主要讲 上图的最下面一层
代码访问
基于golang的代码访问示例
func main() {
cli, err := tikv.NewRawKVClient([]string{"192.168.199.113:2379"}, config.Security{})
key := []byte("Company")
val := []byte("PingCAP")
// put key into tikv
err = cli.Put(key, val)
// get key from tikv
val, err = cli.Get(key)
// delete key from tikv
err = cli.Delete(key)
fmt.Printf("key: %s deleted\n", key)
// get key again from tikv
val, err = cli.Get(key)
fmt.Printf("found val: %s for key: %s\n", val, key)
}
支持事务
Begin() -> Txn
Txn.Get(key []byte) -> (value []byte)
Txn.Set(key []byte, value []byte)
Txn.Iter(begin, end []byte) -> Iterator
Txn.Delete(key []byte)
Txn.Commit()
实现原理
- 单机存储使用了rocksdb,本质上还是kv 存储。解锁 LevelDB 的奥秘 非常经典,建议细读。
- 数据的写入是通过 Raft 这一层的接口写入,通过 Raft将“log”复制到多台机器上,而不是直接写 RocksDB。
数据分片
-
分片的考量
- 如何划分
- 数据规模变大时,是否可以通过新增节点来动态适应
- 当某个节点故障的时候,能否将该节点上的任务均衡的分摊到其他节点
- 对于可修改的数据(比如数据库数据),如果某节点数据量变大,能否以及如何将部分数据迁移到其他负载较小的节点,及达到动态均衡的效果?
- 元数据的管理(即数据与物理节点的对应关系)规模?元数据更新的频率以及复杂度?
-
分片的几种方式
- hash
- consistent hash without virtual node
- consistent hash with virtual node
-
range based。
- 假设以id 作为分片特征值,那么一个节点可能负责0~100,300~400,800~900等,元数据服务记录range与节点的映射关系
- 区间的大小不是固定的,以数据量的大小为片段标准。即0~100占了1M,100~150 也可能占了1M
对于range based 来说,如果一个节点负责的数据只有一个区间,range based与没有虚拟节点概念的一致性hash很类似;如果一个节点负责多个区间,range based与有虚拟节点概念的一致性hash很类似。
- 分片特征值的选择
- 分片元数据及元数据服务