Skip to content
rockeet edited this page Feb 22, 2022 · 14 revisions

Todis 是什么

  • Todis 是 Redis On ToplingDB,兼容 Redis 的分布式数据库
  • Todis 是基于公有云的托管 Redis 服务,对用户可以即刻交付,立马可用
  • Todis 性能优异,弹性伸缩,按量付费,价格低廉(内测期间,完全免费
  • Todis 包含非常丰富、完善的 Grafana 指标监控以及存储引擎观测界面

为什么要使用 Todis

1. 现有的大容量持久化 Redis

目前市面上有很多种大容量、持久化的 Redis 实现,基本上都基于 RocksDB。

2. 这些现有的 Redis 实现有何不足

基于 RocksDB 的数据库,它们的问题主要是 RocksDB 的问题,其次才是其 Redis 实现本身的问题。

2.1. Compact 性能不足

先说结论:RocksDB 的写负载中,有 80% 以上的 CPU 用在 Compact 上。

前台线程将数据写进 RocksDB,后台线程通过 Flush/Compact 将数据压缩并落盘。压缩数据会占用 CPU,不压缩会占用 SSD 空间和 IO 带宽,RocksDB 为此有很多配置选项可以调节。

然而数据还是经常写得太快,Compact 跟不上,导致 L0 数据积压,从而引发读放大。为此 RocksDB 加入了很多限流策略:主动降低写速度。然而这只是转移了矛盾————牺牲写性能,换取读性能!

能不能三者都要呢?既要写得快,又要读得快,还要压缩率高,当然可以,花钱呗,增加 CPU 核心,用傲腾内存+DAX文件系统……

但是,在实际的业务场景中,负载不是一成不变的,负载高的时候,256核都不够用,负载低的时候,机器在空转。

例如某互联网巨头,为了在流量高峰时仍维持较低的延时(较快的响应速度),让高配服务器负载常年维持在 10% 以下,当然,那个巨头富得流油,有钱没处花,不在乎成本,不在乎高配低能。但是,我们相信,大部分用户很在乎这一点。

2.2. CPU 和存储的利用率低下

RocksDB 的一个核心组件是 BlockBasedTable,其核心是内存中的 BlockCache + 外存中的压缩文件(sst)。其工作方式为:每个 BlockBasedTable 的 sst 文件由多个(压缩的) Block 组成,每个 Block 中保存多条数据,sst 中同时存储 Block 的索引,搜索时:

  1. 数据先定位到具体的 sst 文件
  2. 在 sst 中,从 Block 索引定位到 Block
  3. 去 BlockCache 中搜索该 Block,如果找到了,直接返回
  4. 如果没找到,按照索引中保存的 Block offset + len 去文件中读取该(压缩的)Block
  5. 解压该 Block,并将解压后的 Block 存入 BlockCache
  6. 存入 BlockCache 时,如果 BlockCache 达到容量上限,需(按照某种策略)丢弃一个(解压的)Block
  7. 从解压的 Block 中搜索需要的数据

大体如此,当然其中有很多繁杂的细节。主要的问题有两点:

2.2.1. CPU 和外存(SSD)占用

  1. 数据(使用传统压缩算法)按 Block 压缩
  2. 而压缩算法只有在数据上下文足够大时,才能有较高的压缩率
  3. Block 尺寸设得大了,压缩率就高了,同一 Block 中保存的数据就更多,BlockCache 未命中时,需要加载并解压的数据就更多,而所需的数据可能只有一条,这可以认为是另一种读放大
  4. Block 尺寸设得小了,压缩率就低了,同一 Block 中保存的数据就更少,BlockCache 未命中时,需要加载并解压的数据就更少,这个意义上的读放大就更小

2.2.2. 内存占用

  1. 从外存(SSD)中的文件读取数据时,操作系统先将外存中的数据读取到内存(PageCache)中
  2. 将数据从 PageCache 拷贝到用户提供的 buffer 中(如使用 mmap 可略过这一步)
  3. 将读取到的数据解压到另一个用户 buffer(单个解压的 Block) 中,并放入 BlockCache

其中,同一份数据在内存中存在两份,一份是操作系统的 PageCache(压缩的形式),一份是用户空间的 BlockCache(解压的形式)。

3. Todis 解决了哪些问题

Todis 最主要的是,使用 ToplingDB 代替 RocksDB 作为存储引擎,其次,在 Redis 实现的层面上有一些优化。

3.1. ToplingDB 是什么

ToplingDB 是兼容 RocksDB 的存储引擎,解决了 RocksDB 的诸多问题。

3.2. ToplingDB 的性能/成本优势

3.2.1. 弹性分布式 Compact

既然 Compact 占了那么多(80% 以上) CPU,那如果我把 Compact 从存储引擎中移走,CPU 不就释放出来了。我们把这个叫做“前台计算与后台计算分离”,这有诸多优点:

  1. Compact 计算集群,其单个结点可以随时回收(Compact进程可以随时终止),不会对 DB 产生影响
  2. Compact 计算集群,可以使用“计算型”结点,而前面的 DB 结点,使用“内存型”结点
  3. Compact 计算集群,可以多实例共享,即多个 DB 结点共享一个 Compact 集群
  4. Compact 计算集群,可以使用“空闲算力”,任何有空闲算力的结点,闲着也是闲着,那就执行点 Compact 吧
    • 大厂的数据中心,从来不缺算力,而是大量的“空闲算力”苦于无处利用
    • 相比一般大厂,公有云厂商的资源利用率要高得多,然而他们的“空闲算力”仍然卖得非常便宜,甚至可以低至 1折

3.2.2. 可检索内存压缩

topling-zip (fork 自 terark-zip)实现了诸多此类算法,曾经的 terarkdb 就利用 terark-zip 解决了上述 RocksDB 读取数据的问题(2.2)。

这类压缩算法相比传统的通用(RocksDB 使用的)压缩算法,其压缩(Compact)过程中的 CPU 消耗更大,如果说使用传统压缩算法,写负载中 Compact 占用 80% 的 CPU,那么如果使用这类压缩算法,Compact 将占用 90% 的 CPU。

相反,这类压缩算法的“解压”过程非常高效,使得 DB 结点的负载大大降低。

这类压缩算法的这两个特点,结合弹性分布式 Compact,简直是天作之合。

3.2. ToplingDB 的人性化优势

除了性能/成本方面的考虑,ToplingDB 同时也进行了充分的“人性化”设计。

3.2.1. 兼容生态

目前,在 DB 领域,RocksDB 就是存储引擎的事实标准。只要兼容了 RocksDB,就融入了这个生态圈。

3.2.2. 插件化

RocksDB 自身实现了非常基本的插件机制,但其插件机制非常原始,用户必须侵入性地修改代码,才能使用“自定义”的“插件”。

ToplingDB 通过 旁路插件 解决了这个问题。

3.2.3. 可视化

依托旁路插件,在 ToplingDB 内部集成了一个 Http WebServer,对外展示引擎的各种内部信息。

3.2.4. 监控指标

内部集成的 Http WebServer,将 ToplingDB 的各种指标(ticker, histogram 等等),以 Prometheus 的格式开放出去,从而可以在 grafana 中进行监控。

3.2.5 Histogram 定制曲线

prometheus 包含基本的 histogram 方案,但是不够全面,不够完美,我们通过定制 grafana panel,将 histogram 包含的信息,更全面,更完美地展示出来。