背景数据库
Redis做为一款简洁、高效的开源K/V数据库,能够被用于内存缓存、持久化存储等不一样场景,大量服务于各种互联网应用。同时也提供了丰富的功能配置,客户能够根据各自业务需求,在读写性能、缓存容量、数据可靠性等方面做出灵活的选择。缓存
Redis提供了RDB和AOF两种持久化方式供选择,4.0中更是引入了RDB-AOF混合持久化的方式,整合RDB和AOF的优点,提供更实时的数据持久化保证、更快的恢复速度和更紧凑的空间使用。针对AOF的写入,Redis提供了两种选项供选择:安全
• always:aoflog实时写入落盘,保证写入数据的安全性,但写入性能降低严重。服务器
• everysec:buffer写入aoflog,后台按期刷盘,能够很好的保证写入性能,但在failure场景下,须要承担秒级新写入数据丢失的风险。数据结构
这两种模式须要用户在性能和数据安全性之间作出取舍,鱼和熊掌没法兼得。对一些对数据安全性有更高要求的场景,须要应用层协同来保证数据安全,会给系统设计和实现带来必定的复杂度。另外一方面,在Redis发生failover的时候,会有一个缓存预热重建的过程,期间对应用会有一个可感知的不可服务时间、以及访问延时抖动。异步
关于上述问题,很重要的一个缘由在于目前DRAM和SSD(请忽略HDD)之间巨大的性能鸿沟。近几年,备受学术界和工业界关注的NVM(Non-volatile Memory) 技术,给这类问题的解决带来了新的机遇。性能
图1:NVM产品的存储层次结构测试
目前已有的NVM产品,对上层应用提供DIMM形态的访问接口。做为一种NVM设备,相比于DRAM具有掉电不丢数据的特性,容量上也会比DRAM高出一个数量级,成本优点明显。相比于传统SSD,不但读写速度更快(百ns量级),并且具有字节寻址的能力。同时也要看到,NVM产品仍然存在读写不对称、顺序和随机访问不对称等特征。优化
从应用场景上来看,NVM产品能够定位于替代部分DRAM功能,支撑持久Memory或In-Memory应用。具体来讲可被应用在以下场景:阿里云
• 持久化内存:做为数据持久层,对数据一致性要求很高的持久化系统,同时兼顾数据可靠性和数据读写性能。
• 内存数据库:做为数据In Place空间,提供数据运行和持久化存储空间。
• 系统日志卷:做为日志卷,例如,在HPC系统中一般采用Checkpointing实现对计算中间状态进行持久化保存,这是一个耗时、耗系统吞吐量的过程。
基于NVM产品提供的字节寻址、持久化、高性能的能力,以及考虑到其读写、顺序和随机访问不对称等特性,对Redis做了细致的设计和深度的定制化改造,针对上面几个问题取得很是好的测试效果。
前面提到Redis的always模式经过实时flush操做确保AOF文件的实时持久化,但这会致使性能大幅降低。Everysec模式经过大幅减小flush操做的频率,基于page cache缓冲对设备的读写访问大幅提高QPS性能,可是这会引入秒级的数据丢失风险。而基于NVM产品提供的持久化能力能够很是优雅地解决这个问题,兼顾性能和可靠性。整个的数据流图以下:
图2: 基于NVM产品的数据读写流程
首先将AOF文件直接放在基于NVM产品的PMEM-aware filesystem上(好比EXT4 DAX模式),经过mmap将AOF文件映射到用户态地址空间,以后对AOF的访问操做就变成了很是轻量的直接load/store方式,并且要确保数据持久化也仅须要在用户态执行persist操做(主要是cache flush)。可见,基于NVM产品的AOF持久化机制相比传统的IO栈要轻量的多:
B• Bypass整个传统IO栈(Block层->设备驱动等),实现直接load/store操做。
• 经过cache flush操做便可实现持久化,取代了flush系统调用。
AOF机制的另外一个问题是AOF文件的持续增大会形成巨大的空间浪费,因此阿里云Redis团队经过后台线程的方式按照必定的策略(考虑吞吐和资源占用量等)对AOF文件进行replay操做。即根据AOF命令在NVM产品上构造持久化的KV数据结构,而后完成回放的AOF文件就能够删除,从而解决了AOF占用空间的问题。
之因此选择后台线程异步replay的方式在NVM上构建持久化数据结构,是由于该过程须要经过事务操做来保证写操做的原子性和数据结构的一致性,耗时较大,因此数据先写到DDR的方式能够保证客户端写操做的QPS不降低。考虑到NVM拥有出色的读性能,数据异步replay到NVM以后,会根据数据冷热和内存占用量释放部分value比较大的内存副本,转而直接基于NVM提供读服务。因此DRAM逐渐演变为NVM的写cache和热数据的读cache,以充分发挥NVM的读性能和成本优点,同时规避NVM写性能(相对)的短板问题。
在两台96核/384GB神龙服务器上,实测string数据结构的SET操做,从结果数据来看几乎与everysec模式的性能持平,同时兼顾了always模式的数据安全性和everysec模式的高性能。
图3:Redis写入性能对比
Redis在重启时须要进行数据恢复操做。原生Redis重启后都须要从RDB和AOF中加载数据到内存,完成加载后才能够正常提供服务。通过实测,10GB左右数据的RDB加载时间大概为53秒左右,这段时间内Redis服务处于不可用状态。而在基于NVM的方案中,Redis重启后能够先基于NVM的持久化数据结构直接提供读服务,DRAM数据结构重建完成后便可提供完整的读写服务。一样针对10GB左右的数据集,系统shutdown save后重启,实测1秒内能够提供只读服务,35秒内能够提供完整读写服务,整个数据恢复时间大幅降低。以下图所示:
图4: Redis recovery时间对比
另外,原生Redis经过fork一个子进程来保存全量DB数据到RDB或AOF文件,即便相比上次保存的数据仅有一个key的变动,也依然会全量保存整个DB,显然这不是一种高效的实现方式。而且该过程会对Redis带来较大的性能抖动。而基于NVM的方案是一种持续增量持久化的方式,更加高效和平滑,这点对于在线服务来讲相当重要。
NVM相比DRAM能提供更高的存储密度和更大容量的数据存储空间,所以能够有效下降单位数据存储成本。基于NVM的字节寻址能力和与DRAM的速度差别,咱们设计了NVM非易失性内存和DRAM易失性内存间的数据换入与换出策略,能在不影响Redis基本性能的前提下,提升数据的存储容量并节约成本。
整个方案中,充分发挥了NVM的字节寻址、持久化等能力,借助DRAM作cache来弥补NVM读写不对称的问题,从而实现了高可靠、高性能、低成本的Redis数据库,从测试数据能够看出NVM对Redis在持久化以及其余性能方面提高效果很是显著。
除此以外,NVM相比DRAM能提供更高的存储密度和更大容量的数据存储空间,所以能够有效下降单位数据存储成本。在不影响Redis基本读写性能的前提下,基于NVM和DRAM的动态数据输入换出,是咱们下一步工做的方向之一。
固然,目前方案仍存在一些待优化的点,好比:对于高写入场景,replay性能跟不上DRAM写入速度;failover时候,须要等DRAM重建完成才能提供写服务等。后续会继续跟进这些问题,结合技术和产品来一块儿合理改进。