新闻资讯

关注百度智能云最新动态,了解产业智能化最新成果

磁盘型Redis在RocksDB上的优化实践

2023-08-23 15:30:01

背景

PegaDB2.0 是基于 RocksDB 构建的兼容 Redis 协议的 NoSQL 存储服务,在介绍性能优化之前,简单介绍一下 Kvrocks 是如何与 RocksDB 交互的。


从实现上来看,Kvrocks 会将 Redis 数据类型编码成 Key-Value 数据写入 RocksDB 的不同 Column Family (以下简称 CF)中。目前主要有以下几种 CF:


  • Metadata CF:主要存储String 类型的数据,以及  Hash/Set/List 这些复杂类型的元数据(长度,过期时间等),不存储具体元素内容


    Subkey CF:存储复杂类型元素内容


    ZSetScore CF:存储 Zset Score 信息


    Pub/Sub CF:Pub/Sub 相关信息


    Propagated CF: 作为主从同步和存放数据之外的内容,比如  Lua 脚本


    交互逻辑如图所示:



「术说」第8期-节省70%+成本,磁盘Redis的设计与实现 中,我们团队同学详细介绍了 PegaDB2.0 的设计与实现,感兴趣的同学可以去看看。接下来重点介绍 PegaDB2.0 如何使用 RocksDB 的高级特性优化性能。

优化细节

引擎升级


PegaDB2.0 此前使用的是 RocksDB 6.4.6,版本较老,无法使用某些优化后的新特性。RocksDB 的版本迭代非常快,我们调研了业界比较有名的使用 RocksDB 的项目,比如 MyRocks,ArangoDB 使用的是最新的 6.26.1 版本,StarDog 使用的是 6.20 版本


PegaDB2.0 选择较新的 6.26.1 版本,并提供多种存储引擎版本以满足不同的需求,我们也在考虑引入存储引擎热拔插的机制在不影响线上服务的前提下切换存储引擎。我们团队将持续关注 RocksDB 社区进展,及时反馈、解决 RocksDB 使用中的问题,并回馈社区。


Memtable 优化


PegaDB2.0 使用 SkipList Memtable,相比 HashSkipList Memtable 拥有更好的跨多个前缀查找性能,并且也更节省内存。同时针对 SkipList Memtable 打开 whole_key_filtering 选项,该选项会为 Memtable 中的 key 创建 Bloom Filter,这可以减少在跳表中的比较次数,降低查询时的CPU使用率。


相关配置:
metadata_opts.memtable_whole_key_filtering = true
metadata_opts.memtable_prefix_bloom_size_ratio = 0.1

SST 优化

Data Block

 

PegaDB2.0 在 Data Block 上使用 Hash 索引,提升点查询的效率。 查找 Data Block 时候,会使用二分查找,二分查找会导致 CPU Cache Miss,提高 CPU 使用率。如果在 Data Block 上使用 Hash 索引,将会避免二分查找,在点查询场景下降低 CPU 利用率。官方的测试数据显示该特性会降低 21.8% CPU 利用率,提升 10% 吞吐,但是会增加 4.6% 的空间占用。相比磁盘资源,CPU 资源更加昂贵,权衡之下,我们选择打开 Hash 索引。


相关配置:
BlockBasedTableOptions::data_block_index_type = DataBlockIndexType::kDataBlockBinaryAndHash
BlockBasedTableOptions::data_block_hash_table_util_ratio = 0.75 // 如果此值小的话,说明 Hash 桶多,冲突就比较小。


Filter/Index Block


旧版本的 RocksDB 默认使用的 BloomFilter 是 BlockBasedFilter,这也是 LevelDB 的方式。基本原理是每 2KB 的 KV 数据产生一个 Filter,最后组成一个 Filter 数组。在查找的时候,先查找 Index Block, 对于可能存在该 Key 的 Data Block,再查找对应的 Filter Block 判断 Key 是否存在。


RocksDB 对 Filter 进行了优化,引入 Full Filter。每个 SST 都有一个 Filter,这样可以检查 Key 是否存在于 SST 中,避免读取 Index Block ,但是如果 SST 中 key 较多的话,会导致 Filter Block 和 Index Block 较大,对于 256MB 的 SST,Index/Filter Block 的大小大约为 0.5MB 和 5MB,这比 Data Block(通常4-32KB)大得多。当 Index/Filter Block 完全存于内存时,每个 SST 生命周期只会读取一次,这是最理想的情况,但当它们与 Data Block 竞争 Block Cache 时,很可能从磁盘上重新读取很多次,导致读放大非常严重。


PegaDB2.0 以前的做法是动态的调节 SST 相关的配置,使得 SST 文件不会过大,从而避免 Index/Filter Block 过大,但是这种机制存在的问题是当数据量非常大时,SST 文件过多,占有过多系统资源,也会带来性能的衰减。新版本 PegaDB2.0 对此进行了优化,打开 Partitioned Block 相关的配置, Partitioned Block 的原理是在 Index/Filter Block 基础上加一层二级索引,当读 Index 或者 Filter 的时候,先将二级索引读入内存,然后根据二级索引,找到所需的分区 Index Block,将其加载进 Block Cache 。Partitioned Block 机制带来的优点如下:


  • 增加缓存命中率:大 Index /Filter Block 会污染缓存空间,将大的 Block 进行分区,允许以更细的粒度加载 Index/Filter Block,从而有效地利用缓存空间

  • 提高缓存效率:分区 Index/Filter Block 将变得更小,在 Cache 中锁的竞争将进一步降低,提升了高并发下的效率

  • 降低 IO 利用率:当索引/过滤器分区的缓存 Miss 时,只需要从磁盘加载一个小的分区,与读取整个 SST 文件的 Index/Filter Block 相比,这会使磁盘上的负载更小

相关配置:


format_version = 5
index_type = IndexType::kTwoLevelIndexSearch: 使用 partition index
NewBloomFilterPolicy(BITS, false) : 使用 Full Filter
BlockBasedTableOptions::partition_filters = true:使用partition filter, index_type 必须为 kTwoLevelIndexSearch
cache_index_and_filter_blocks = true
pin_top_level_index_and_filter = true
cache_index_and_filter_blocks_with_high_priority = true
pin_l0_filter_and_index_blocks_in_cache = true
optimize_filters_for_memory = true

压缩策略优化

RocksDB 在数据落盘时会对数据进行压缩。下图是不同压缩算法压缩速度和压缩比的测试数据。我们在 PegaDB2.0 上对不同的压缩算法进行了对比测试,发现不同的压缩算法对性能影响非常大,特别是 CPU 资源紧张的情况下,会显著增加长尾延迟。



在 PegaDB2.0 中对 L0 层和 L1 层的 SST 不设置压缩,因为这两层数据量较少,压缩这些层级的数据并不能减少很多磁盘空间,但是可以通过不压缩这些层级的数据来节省 CPU。每个 L0 到 L1 的Compaction 都需要访问 L1 中的所有文件,另外,范围扫描不能使用 Bloom Filter,需要查找 L0 中的所有文件。如果读L0和L1中的数据时不需要解压缩,写 L0 和 L1 中的数据不需要压缩,那么这两种频繁的CPU密集型操作会占用更少的 CPU,相比压缩获得的磁盘空间,收益更大。


对于其他层级,我们使用 LZ4。对于大数据量、低QPS的场景,我们还会将最后一层设置为 ZSTD,进一步降低空间放大,减少成本。

Cache 优化

PegaDB2.0 涉及多个Column Family(以下简称CF)。对于简单数据类型(字符串操作),将数据存到 Metadata CF;复杂数据类型会将元数据存到 Metadata CF中,实际数据存在 Subkey CF 中。默认情况下,不同的CF使用不同的 Block Cache。线上场景复杂,无法预知用户使用的数据类型,也就无法提前给每个 CF 分配合适的 Block Cache 大小。PegaDB2.0 默认为这两个 CF 分配了相同大小的 Block Cache,如果用户使用简单类型和使用复杂类型比例不相当时,会使得 Block Cache 使用效率降低。PegaDB2.0 让不同的CF共享同一个大的 Block Cache,这提高了 Block Cache 的利用率,也提升了 30% 的性能。 


方法:不同 BlockBasedTableOptions 使用同一个 Block Cache 的指针


此外,PegaDB2.0 还引入 Row Cache 应对热点 Key 问题。RocksDB 先检查 Row Cache,再检查 Block Cache,对于存在热点的场景,数据会优先存放在 Row Cache 中,进一步提高 Cache 利用率。

Key-Value 分离

LSM 型的存储引擎会将 Key 和 Value 存放在一起,在 Compaction 的过程中,Key 和 Value 都会被重写一遍,当 Value 较大时,会带来非常严重的写放大。针对此问题,WiscKey(FAST'16)这篇论文提出了 KV 分离的方案,业界也基于此论文实现了 LSM 型存储引擎的 KV 分离,比如: RocksDB 的 BlobDB、PingCAP 的 Titan 引擎、厂内的 UNDB 所使用的 Quantum 引擎


RocksDB 6.18 版本重新实现了 BlobDB(RocksDB的KV分离方案),将其集成到 RocksDB 的主逻辑中,并且也一直在完善、优化 BlobDB 相关特性。PegaDB2.0 引入此特性,应对大 Value 的场景。测试显示,当 PegaDB2.0 打开 KV 分离开关时,针对 Value 为10KB 的场景,写性能提升 2.5 倍,读性能并没有衰减; Value 越大,写性能提升幅度越大,Value 为 50KB 场景下,写性能提升了 5 倍。


具体配置:

ColumnFamilyOptions.enable_blob_files = config_->RocksDB.enable_blob_files;
min_blob_size = 4096
blob_file_size = 128M
blob_compression_type = lz4
enable_blob_garbage_collection = true
blob_garbage_collection_age_cutoff = 0.25
blob_garbage_collection_force_threshold = 0.8

未来工作

目前 PegaDB2.0 使用 RocksDB 作为底层 Key Value 存储引擎。未来,我们将抽象出底层存储,使其更加方便的适配其他存储引擎,也便于应用新的硬件、新的协议栈、新的架构。


持久内存的应用


英特尔傲腾持久内存(Optane PMem)弥补了传统 SSD 和 DRAM 之间的空白,以创新的技术提供独特的操作模式,满足各种工作负载的需求。随着高性能存储硬件的发展,传统的存储架构逐渐无法发挥新硬件的性能,传统引擎的架构需要在 PMem上重新调整。
我们团队正在积极跟进新存储硬件的发展,与英特尔团队深入合作,探索在 RocksDB 以及 Redis 场景下如何更好的使用 PMem,进而降低用户成本、提升访问性能。


用户态协议栈


采用用户态协议栈,可以减少系统调用以及处理数据包的开销,降低数据包的频繁内存分配、降低内存拷贝,提高内存使用效率。PegaDB 后续将在底层引入用户态协议栈,进一步提升性能。


计算存储分离


在 Rocksdb Virtual Meetup 2021 上, RocksDB 团队分享了 RocksDB 的计算存储分离方案,其将 SST 文件存储到远程分布式文件系统之上,其团队负责人透露未来将高优开发计算存储分离相关特性,尽快将此特性在 Facebook 内部落地。


LSM 型数据库需要进行 Compaction 来减少空间放大,Compaction 是 CPU 密集型的操作,传统架构下 Compaction 和上层服务耦合在一起,相互影响,甚至会阻塞上层写入(称为 Write Stall)。RocksDB 引入 Remote Compaction 特性将 CPU 密集型的 Compaction 转移到远程去执行,实现服务计算与存储引擎计算剥离,达到计算资源的极致弹性。为了降低访问远程存储的延迟 RocksDB 引入 Secondary Cache(可以是内存、PMem、NVMe-SSD 组成的多级 Cache,将 Block Cache 淘汰的数据缓存在本地,减少访问远程存储的次数。
未来我们也会持续跟踪 RocksDB 的进展,自研与拥抱开源,双管齐下,尽快推出计算存储分离架构的新版本 PegaDB,积极拥抱云原生,实现计算、存储极致的弹性,进一步降低用户云上成本。

总结

本文重点介绍了基于 RocksDB 的磁盘 Redis 服务是如何使用 RocksDB 高级特性提升性能的。未来,BDRP 团队将持续优化 PegaDB2.0,为大家带来更卓越的性能体验。