本文分享自华为云社区《浅析KV存储之长尾时延问题,华为云 GeminiDB Redis 探寻行业更优解决方案!》,作者:华为云数据库GaussDB NoSQL团队。
目前,KV存储的广泛使用极大程度上源于快速访问的业务需求,而这种业务通常对时延敏感度高,在较好的平均性能下,还需要解决特定场景下的性能抖动。开源Redis在AOF重写、RDB、主从同步等操作时,为不影响主线程,采用fork创建子线程去执行,但由于主线程仍在提供服务,触发Copy-On-Write时会引起性能抖动,导致长尾时延。
华为云GeminiDB(原华为云GaussDB NoSQL,后统称为GeminiDB)是采用存算分离架构的NoSQL多模数据库,在性能、稳定性方面业界领先。KV接口上,GeminiDB 100%兼容Redis 5.0协议,用户无需修改代码即可平迁到GeminiDB。针对业界的Redis fork技术痛点,GeminiDB提供了终极的优化方案。
我们先来看下业界的两种通用解法:
业界解法一:实现层面优化fork问题
常规的解决方案是在fork实现层进行魔改,也就是找到造成fork长尾时延的代码所在然后对其进行优化。通过多次实验发现,fork的执行时间随着实例大小增长而剧增,其中最耗时的是页表拷贝操作,如下图(a)所示,在Invoke Fork操作之后,主进程需要花时间进行页表拷贝,服务出现毛刺现象。
由此产生fork重写的核心思路:由于父进程在fork原生内部实现中并不纯粹,其在页表复制时仍需陷入内核态,出现短暂阻塞现象。通过将父进程耗时占比最高的页拷贝操作移至子进程去执行,足以大幅削弱父进程在fork过程中的阻塞现象,从而可以在对程序无任何修改的条件下解决原生fork带来的长尾时延。
业界有种算法,如上图(b)所示,可以通过让子进程去异步完成页表拷贝动作(Copy Page Table)和主进程主动同步页表(Proactively Synchronize)来解决毛刺以及主子进程的可能不一致问题,可以做到主进程近乎零阻塞。不难看出,修改fork算法有以下几点优势:
1. 实现层面消除了fork场景带来的长尾时延。
2. 对内存型键值存储服务完全透明。
但由于涉及魔改操作系统fork实现,导致维护和演进成本较高,向前兼容性较差。相比之下,在架构层面去解决这个问题,或许更加简单且自然。
业界解法二:架构层面优化fork问题
除了针对fork的优化,直接消除fork或许是工程上更加迫切的需要。
我们分析一下,之所以会有fork的引入,是因为Redis做了AOF重写、RDB、主从同步的操作。恰恰对于Redis这种内存型KV存储而言,AOF操作可以保证了数据不丢,而RDB和主从同步也是其持久化需要。但如果是非易失型KV存储,从内存到持久化介质的链路就不存在,类RDB和类主从同步操作也就可以交给存储层独立解决,从而彻底消除fork所带来的长尾时延。
基于此,业界有些数据库将KV数据通过其存储引擎直接写入持久化介质中,且在计算层做了性能上的高度优化,达到了不劣于开源Redis的性能:
以PMem为存储底座的存算分离架构
采用PMem作为其主要持久化存储介质的存储引擎,在某种程度上来说,其兼具DRAM的性能和字节寻址能力以及SSD的可持久化特性。下图是几种存储介质的对比:
同时,通过实现存储引擎的Cache模块,在服务运行期间存放业务热数据的数据页会被加载到PMem上,在处理用户请求期间不再直接操作SSD上的数据页,而是操作读写延迟更低的PMem,使得计算层的性能以及吞吐量得到了进一步的提升。
总的来说,使用PMem存储底座的优势在于:
1. 没有fork场景,不存在fork带来的长尾时延。
2. 提供了比开源Redis更大的容量。
3. 数据可冷热分级存储。
但是,强依赖PMem也带来了一些难以解决的问题:
1. 非易失型内存编程难度高且鲁棒性差,需要框架和工具层面去降低其开发难度,总的来说,开发和维护成本过高。
2. 由于编程复杂,而且Redis索引结构繁多,数据模型相关API高达300多个,造成Redis命令兼容的实现可靠性极具下降,同样面临如何降低编码复杂度的问题。
3. PMem相比于DRAM有数量级的性能下降,在读性能上有3倍以上的性能下降以及10倍以上的带宽减少,性能问题不可忽视。
在可靠性和开发维护成本上,以PMem为存储底座的架构还是有一定不足之处。
华为云的NoSQL数据库GeminiDB在这方面有更加强大的实现方案。GeminiDB兼容Redis接口(原GaussDB(for Redis),后统称为GeminiDB兼容Redis接口),以RocksDB+分布式文件系统+高性能存储池为底座,实现了领先的存算分离架构,综合表现更佳。
GeminiDB存算分离架构
华为云GeminiDB兼容Redis接口,存储架构采用RocksDB+分布式文件系统+高性能存储池,如下图所示,在架构层面消除了长尾时延的影响外,通过高性能存储池提供高可靠存储特性,分布式文件系统封装高性能存储池向外暴露类标准文件系统接口,降低开发难度。
而在性能选择方面,选择RocksDB作为存储引擎。它针对快速、低延迟的存储进行了优化,具有极高的写入吞吐。同时,RocksDB支持预写日志,范围扫描和前缀搜索,在高并发读写以及大容量存储时能够提供一致性的保证。RockDB的追加写特征恰好解决了磁盘I/O最耗时磁盘寻道时间,达到了接近内存随机读写的性能。
高可靠的实现,选择华为研发的高性能存储池分布式存储,最高支持128TB的海量存储,支持跨AZ部署、故障秒级切换,保证了在极度恶劣的情况的数据无损和快速恢复,支持数据的自动备份。
除此之外,分布式文件系统借助HDFS Snapshot实现了秒级快照,产生整个文件系统或某个目录在某个时刻的镜像,向用户提供了数据恢复、数据备份、数据测试的能力。
简言之,通过RocksDB+分布式文件系统+高性能存储池的存储架构,已经做到:
1. 低时延,基于高性能的存储架构,访问时延有了高度保障。
2. 大容量,基于存算分离,存储层可自由扩容。
3. 低成本,基于冷热数据分级存储,贴合客户诉求。
4. 高可靠, 基于分布式文件系统+高性能存储池,支持优秀的数据备份和数据同步特性,且不对主进程造成时延影响。
不过,RocksDB的数据存储模式也会带来一些复杂性。由于RocksDB存在读、写和空间放大的问题,且三者相互制约。尽管RocksDB提供了多种Compaction策略和参数以适应不同应用场景,但由于影响因子过多,策略的选择和调参成本会比较高。
小结
通过不同解决方案之间的对比,在解决长尾时延的问题上,架构解决方案更加贴合大多数客户诉求。同时,在大部分场景下,GeminiDB兼容Redis接口的架构相比于业界方案提供了更高的可靠性和良好的性能表现,预计年底可达到单片百万QPS的性能水平。
附录
更多产品信息,欢迎访问官方博客:bbs.huaweicloud.com/blogs/248875