RDB
本文关键字: LSM、RocksDB、Raft、Redis Cluster
诞于脑洞
KV 的现状
Redis目前大部分场景下处于「性能过剩」而「存储短缺」的状态,当然也可以发动「钞能力」HBase作为老牌的LSM树实现的DB,写性能还算过得去,但是读性能就十分磕碜了- 早期也有
Twiter开源的twemproxy方案来做Redis、Memcached基于Hash的Cluster实现可惜只能「单线程跑」,且数据扩缩容十分不便 Nefix参考AWS DyanmoDB白皮书实现的Dynomite,目前已经不怎么维护了,且一堆Bug,有过邮件交流但是无果。PS: 当初接SpringCloud也被坑惨了- 近几年也涌现了基于
TiKV生态的兼容Redis 协议的KV例如:Titan等 - 另起炉灶的
Pika目前还是推荐用15年左右火爆的Codis引入更多的「基础组件」来做集群管理,同时也在自行实现另一套Cluster的管理逻辑 - 大部分的方案最底层采用
Facebook基于Google的LSM tree实现的LevelDB再针对SSD优化而来的RocksDB - 当然还有很多很多
KV存储在冒出来,例如: 腾讯云的Tendis、阿里大佬整的Tair、美图大佬整的KVrocks,兼容Redis协议,字节魔改的RocksDB等等,是不是发现很眼熟似乎大部分都是基于RocksDB的 Redis Labs也推出了基于SSD的存储版本,当然不是免费给你用的啦,可惜的是我还没去实际测试过它- 似乎存在不少的场景只要简单的
KV存储,但是需要大量的存储空间,再贪心一点点「追求一下」「性能」似乎能选择的就不多了 - 这里扯到了「性能」我为什么试着搞一个简单的
KV而不是像Redis一样全都要,甚至还支持各种数据结构,譬如:SQL的拓展插件,个人感觉 Redis 是成功到奇葩的数据库了- 其实原因很简单,之前也有参与以为小伙伴的
sdb前期实现的讨论,结论是如果要支持各种数据结构那就是要「加锁」的,甚至incr也是,有兴趣的小伙伴可以跳转到 sdb 去了解一波
- 其实原因很简单,之前也有参与以为小伙伴的
- 说白了
KV的集群方式也就是两种Hash- 一致性
Hash: 譬如Dynomite,相比普通Hash当节点上下线时数据移动少 - 普通
Hash: 譬如twemproxy
- 一致性
Raft- 单
Raft: 譬如sdb,Raft之前以ETCD为代表,如果完全参考Raft论文实现,性能会非常差,况且所有的写请求都只能由Leader处理,可参考Raft作者实现的 Logcabin Mutl-raft: 譬如TiKV,有多少个Raft实例就相当于有多少个写入口
- 单
- 总结下现在已经迈出了当初需要自己解决
Redis集群问题的时代,但是依然没有解决持久化的问题 - 正好兄弟团队业务场景上需要一款高性能写入同时读性能不能太差的业务场景,之前有试过
Hbase,据说写了2个星期数据还没写完... - 所以我决定撸一个能够「开箱即用」、「可持久化」、「可扩展」、「够稳定」、「够简单」的数据库,仅仅聚焦于简单的
KV存储- 之前有看到过一篇文章让我感触很深「为什么国内出不了百亿的 SaaS 公司?」
- 大概有这么几点:
- 不敢做取舍,什么都想要,但是很可能什么都做不好
- 这里
AWS让我肃然起敬,基本是专注于最底层,然后拉合作,譬如CloudWatch真的很难用,但是大名鼎鼎的DataDog的底层却是用的它,还有EKS、ELB等等等,跑题了...
- 这里
- 「用户成功」和 「为客户创造」价值是口号
- 譬如: 有用
A/B两款省成本的平台,A是海外的公司的收费标准是从省掉的钱里抽x%,B是家国内的公司,采用一次性付费的方式,当我知道他们的收费模式之后心中已经有倾向了。
- 譬如: 有用
- 不敢做取舍,什么都想要,但是很可能什么都做不好
目标
大致的方向
- 低成本(高性能)
- 大存储(持久化)
- 易使用(
Redis Cluster Client接入,单体架构没有Proxy,没有注册中心) - 可扩展 (基于
Single Raft管理集群) - 高可用 (拥抱
Redis Cluster生态)
具体的实现
- 借用
NewSQL中的一极CockRoach参考RocksDB实现的Pebble,来实现单点的可持久化的KV存储,来解「决低成本」、「高性能」的存储问题LSM的读写复杂度O(1) / O(logn)、而 B+ 的读写复杂度O(logn)LSMRed Black TreeVSLevelDB的Skip List实现,Skip List用数据概率来实现了大概率的均分分配,代码逻辑相对简单,也能免去树的旋转。
- 兼容
Redis Cluster协议- 主流的技术栈都可通过
Redis Cluster Client快速接入(这样可以帮我解决很多其他类型DB必须在Server上实现的逻辑,其实也可以考虑另起炉灶上RPC) - 这里做了些思考最终做了「取舍」,如果「自定义协议」大概率在性能上是可以胜过
Redis协议的,举个例子:Memcached更为紧凑的二进制协议 - 其实就是在「易用性」和 「效率」中做选择,实际的 DB 性能表现瓶颈也是在硬盘的
IO上
- 主流的技术栈都可通过
- 借助
Redis Cluster Slots实现可扩展的集群,支持基于Cluster的Hash Tag - 接入
Single Raft来替代过于臃肿的Gossip协议管理集群信息 - 其他功能,原则上「不引入任何降低」目前命令(
get/set/mget/mset)性能的特性- 添加
Cache层,做数据的冷热分离 - 魔改
Redis Cluster协议实现Leader - Follower的读写分离
- 添加
- 实现必要的
Redis运维命令,如: 服务的关键性指标的统计、一键扩缩容等
调研
-
Redis「可持久化」存储版百家争鸣 -
Redis Cluster的发展历程14 - 16年打杀四方的Codis,听说当时很多大厂也在用,顺便提一嘴,其实Codis的核心开发就是现在PingCAP的CTO-Edward Huang大佬- 借助
Codis的各种组件套壳的KV Cluster而实现从单机到集群的组建 Redis Cluster官方的简单易用的实现停止了Redis Cluster还需要各种折腾的时代
-
之前提到的解法基本都是
RocksDB,既然有了TiDB的TiKV甚至天生就能组集群了,还有必要自己整KV吗?- 不在乎成本是可以的,
19年试用TiDB Cloud至少是3 * 8C16G TiKV+2 * 8C16G PD起步了 TiDB的基本思路RocksDB解决存储问题Raft解决集群问题- 设计
KV-SQL的映射规则
TiDB的基本概念RegionRaft&&Muti-Raft- 那
TiDB是如何把KV变成SQL的呢? - 最近
TiDB又弄了一个TiFlash似乎想一统OLAP和OLTP,emmmmm既然扯到了SQL了就和rdb没啥关系了
- 不在乎成本是可以的,
选型
B+ / LSM or LSM + B+?LSM:HBaseLevelDB -> RocksDB -> Pebble(CockRoachdb)- 基于
LSM tree在存储引擎的级别已经做好了Key的排序 - 必然存在「读写放大」的问题,而且「数据越多」就「越严重」
- 单节点
500G的情况下能做到「线上使用情况」的性能数据 - 如果从极限的角度去算把
Redis Cluster Slots全部耗尽,将是16384 * 500G约为8PB的数据,当然如果没那么看重读性能,可以往单节点1T的数据量级试试
- 基于
B+:botlDB:ETCD的底层数据就是存储在Golang版本的实现,这是一个非常精简的B+/MVCC实现,核心代码不过几千行,非常值得一读
B+ + LSM: 一位B站应届生写的,同样代码十分精简,想法十分骚气,我差点就用它来做底层存储了。LotusDB
- 文档型数据库
B or B+(Append-only B+MongoDB: 特别有意思的选择了B,因为如果当做KV文档存储来用,不需要太多的范围查询,B的查询效率反而会更高- CouchDB: 总结一下,只有追加操作并利用
MVCC去锁化
Memcached、RedisorCoucseBDMemcached: 单从KV来看性能是优于Redis的,据说快手的重保项目上来就是几十万个缓存节点,Redis Cluster也没法组这么大的集群,之前用C++标准库撸过一个Memcached的Demo比官方面向内存编程的C的实现多消耗了30%的内存CoucseBD: 用Restful的方式提供服务,所以存在HTTP报文比实际数据还要大的问题
Lucene-FST与Tire Tree: 这里更多的检索类(倒排索引)的DB了,Lucene-FST类似Hashmap但是内存用得更少而查询速度要慢,朴素版的Tire Tree就很吃内存了,当然也有不少优化的版本,例如: 三元Tire Tree。啊哈哈哈该项显然不是我们的选择方向。
Roadmap
-
- 单节点支持
pebble
- 单节点支持
-
-
set/mset/get/mget常用命令支持
-
-
- 支持
Redis Cluster通过redis-benchmark&&redis-py-cluster的测试
- 支持
-
- 引入
Single Raft
- 引入
-
- []
cluster数据交给Raft管理
- []
-
- [] 支持一键扩缩容
-
- [] 支持更多的数据压缩算法(目前是
snappy,想试试Kafka较新版本所支持的的zstd),得到硬盘与 CPU「成本和性能」的关系性结论
- [] 支持更多的数据压缩算法(目前是
-
- [] 添加
Prometheus的关键性监控指标
- [] 添加
-
- [] 添加
Cache层,做数据的冷热层
- [] 添加
-
- [] 魔改
Redis Cluster协议实现Leader - Follower的读写分离
- [] 魔改
-
- []
sdb特性冻结深入pebble进一步的性能优化
- []
上线使用情况
集群总数据大概为 2T 左右,目前 7 台 8C 的节点可承载 30W QPS 大概 100Bytes 的 KV 写入,大概 10W QPS 的读取(瓶颈在 IO...),顺便一提 15 个小时内即可完成兄弟团队的数据写入需求了