热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

KVSSD:结合LSM与FTL以实现写入优化的KV存储

本次分享的Paper[1]:《KVSSD:CloseintegrationofLSMtreesandflashtranslationlayerforwrite-efficientK

本次分享的 Paper[1]:《 KVSSD:Close integration of LSM trees and flash translation layer for write-efficient KV store 》是在 18 年的 Design, Automation & Test in Europe Conference & Exhibition (DATE) 会议上出现的 KVSSD,作者为:Sung-Ming Wu[2]、Kai-Hsiang Lin[3]、 Li-Pin Chang[4]。

这篇 Paper 主要思路是在 SSD 上直接提供 KV 接口,将 LSM Tree 与 FTL 深度结合,从而避免从 LSM Tree,主机文件系统到 FTL 多个软件层的写入放大。跟大家分享这篇 Paper ,一方面是蹭一蹭 KV 接口已经成功进入 NVMe 2.0 规范被标准化的热点,另一方面是为了和 TiKV / TiDB 的同学探讨未来存储硬件的更多可能性,希望能带来一些启发。

本文将首先介绍问题的背景,什么是写放大,哪里产生了写放大,然后引出解决方案,介绍 KVSSD 做了哪些优化,之后再介绍 KVSSD 的性能评估数据,以及工业上的进展。

file


背景

首先我们来聊聊背景。这是一个 TiKV 的架构图:

file

我们都知道 TiKV 是一个分布式的 Key-Value 数据库,TiKV 的每一个节点都运行着一个 RocksDB 的实例,就像是这样:

file

RocksDB 基于 Log-structed merge-tree (LSM) 开发的,LSM tree 是目前业界运用最为广泛的持久化数据结构之一。我们要讨论的问题就是 LSM tree 在 SSD 上遇到的写入放大问题及其解决方案。


KV 存储系统中的写放大

从存储的视角来看,一个 KV 存储的软件堆栈大概是这样的:

file

最顶层是一颗 LSM tree,具体的实现就不展开了。大体的思路是在内存中维护可变的 Memtable,在 SSD 上维护不可变的 SSTable。Memtable 写满后会作为 SSTable 输入存储,而所有的 SSTable 会组合成一颗分层的树,每一层写满后就会向下一层做 compaction。LSM tree 维护过程中产生的 IO 会通过文件系统与 BIO 层的转换落到 SSD 上。

file

然后看一下文件系统。显然的,文件落到文件系统上必然会有一些额外的开销,比如说我们需要维护文件的 Metadata。inode、大小、修改时间、访问时间等都需要持久化。此外,文件系统需要能够保证在 crash 的时候不丢失已经写入的数据,所以还需要引入日志,写时复制这样的技术。

file

然后再来看看 SSD 这一层。一个典型的 NAND Flash 芯片通常由 package、die、plane、block 和 page 组成。package,又叫做 chips,就是我们能在 SSD 上看到的颗粒。一个 pakage 通常由多层堆叠而成,每一层就叫做一颗 die。一颗 die 里面会被划分为多个 plane,而每个 plane 里面会包括一组 Block,每个 Block 又可以进一步细化为 Page。其中 Block 是擦除动作的最小单位,通常是 128KB 到 256KB 不等,而 Page 是读取和写入的最小单位,通常为 2KB 到 32KB 不等。为了维护逻辑地址到物理地址的转换,SSD 中引入了 FTL。此外,FTL 还需要承担垃圾回收,坏块回收,磨损均衡等职责。

我们知道 SSD 设备的特性决定了它在写之前必须要进行擦除操作,设备需要将数据全部读到内存中修改并写回。为了均衡芯片损耗与性能,SSD 通常会选择标记当前 block ,寻找新的可用 block 来写入,由 FTL 来执行垃圾回收,这也就是我们常说的 SSD Trim 过程。

file

从上面的分析我们不难观察到严重的写放大问题:



  • LSM tree 的 compaction 过程



  • 文件系统自身



  • 块请求落到 FTL 上会出现的 read-modify-write 过程



  • FTL 的垃圾回收



  • Paper 中没有考虑文件系统本身的写放大,只取了剩下三点的乘积作为总体的写入放大率。写入放大显然是个坏东西,既加大了存储设备的磨损,又降低了写入的吞吐,这些因素最终都会反映到用户的总体持有成本上。




如何缓解写放大?

为了解决或者说缓解这个问题,大家提出过很多不同方向的方案。

file

比如说我们可以对算法做一些改造,比如 LSM-trie[5]、PebblesDB[6] 或者 WiscKey[7]。WiscKey 大家可能比较熟悉一点,将 LSM tree 中的 Key 和 Value 分开存储,牺牲范围查询的性能,来降低写放大。TiKV 的 titan 存储引擎、dgraph 开源的 badger[8]还有 TiKV 社区孵化中的 Agatedb[9] 都是基于这个思路设计的。

或者我们也能在文件系统这一层做些事情,比如说专门开发一个面向写方法优化的文件系统,减少在日志等环节的写入 IO,比如说开启压缩比更高的透明压缩算法,或者面向 KV 的典型负载做一些优化和调参。

但是算法上和软件上的优化终究还是有极限的,想要突破就只能不做人啦,直接对硬件下手,从固件的层面进行优化。一般的来说,系统优化都有拆抽象和加抽象两个方向的优化。拆抽象是指我们去掉现有的抽象,将更多的底层细节暴露出来,这样用户可以更自由的根据自己的负载进行针对性优化。加抽象是指我们增加新的抽象,屏蔽更多的底层细节,这样可以针对硬件特点做优化。

存储系统的优化也不例外。

file

拆抽象思路的先驱者是 Open-Channel SSD,它的思路是把固件里的 FTL 扬了,让用户自己来实现。这个思路是好的,但是 Open-Channel Spec 只定义了最通用的一部分,具体到厂商而言,他们考虑到自己 SSD 的产品特性和商业机密,往往选择在兼容 Open-Channel Spec 的同时,再加入一些自己的定义。这就导致至今都没有出现通用的 Open-Channel SSD 和针对业务的通用 FTL。对用户来说,并不通用的 Open-Channel SSD 带来了更严重的 vendor-lock 问题。所以 Open-Channel SSD 迟迟无法得到大规模应用。

NVMe 工作组也看到了这样的问题,所以他们消化吸收了 Open-Channel 的精髓,提出了 Zoned Namespace (ZNS) 的新特性。ZNS 将一个 namespace 下的逻辑空间地址划分为一个个的 zone,zone 当中只能进行顺序写,需要显式的擦除操作才能再次进行覆盖写。通过这种方式 SSD 将内部结构的边界透露给外界,让用户来实现具体的地址映射,垃圾回收等逻辑。

另一个思路是加抽象,既然上层业务做不好这个事情,那就把它加到固件里面,硬件自己做。比如说在固件中直接实现 Key-Value 接口,或者使用计算型 SSD 将更多的计算任务下推到 SSD 上来做。

这里额外插一句感慨,三国演义开篇的“天下大势,分久必合,合久必分”真是太对了。软件定义存储发展到现在,硬件厂商也不甘于成为纯粹的供货商,他们也想加入到产业链上游,获取更多的利润。所以在存算分离已经成为大势所趋的时候,业界还孕育着一股存算融合的潮流:通过更合理更规范的抽象,充分利用自己软硬一体的优势,提供在延迟和吞吐上更具优势的产品。比如有消息称三星开发中的 KVSSD 上搭载的芯片计算能力相当于两三年前的手机芯片。考虑到 FPGA 和 ARM 这样精简指令集的芯片的持续发展,相信这股潮流会带来更多系统架构上的可能性。


KVSSD 设计

好的,回归正题。这篇 Paper 就是采用了加抽象的路线,在固件中直接实现 Key-Value 接口。

file

KVSSD 采用了闪存原生的 LSM tree 实现,叫做 nLSM (NAND-flash-LSM)。nLSM tree 把 FTL 的 L2P(Logical To Physic) 层转换为了 K2P ( Key To Physic) 映射,每个树节点都代表一个 SSTable 的 Key 范围。nLSM tree 将整个闪存花费为元数据区和 KV 区,KV 区中存储排序后的 KV 对,元数据区中的每一页叫做元数据页,只包含指向 KV 页和键范围的指针。

nLSM 运用了如下设计来优化写放大:


K2P Mapping

file

首先我们来看一下 K2P 映射的设计。显然的,K2P 的抽象层次比 L2P 高很多,不可能在 SSD 的内存中直接存储所有 Key 对应的物理 Page。所以作者选择了在 K2P 中使用 Key Range Tree 来存储 彼此不相交的 key-range 到 SSTable 的映射。nLSM tree 使用 Key Range Tree 来找到一个元数据页,然后使用元数据页中的 key range 信息来找到一个 KV 页,然后再从 KV 页中检索目标 KV 对。nLSM tree 给每个 SSTable 分配了一个闪存块,闪存块的大小是 4MB 跟 SSTable 的大小一样大,保证 SSTable 物理上连续且跟页面边界对齐。在 compaction 的时候,nLSM tree 会对旧的 SSTable 进行多向合并排序,并写入新的 SSTable,并丢弃旧的 SSTbale。之后的垃圾回收过程可以直接擦除这些块,不需要进行任何的数据复制。


Remapping Compaction

file

其次是 Remapping Compaction。

假设我们现在 Key Range 被划分为 A 到 I 这几个区间。Ta 表示的是 Level i 层的数据,Tb 和 Tc 表示 Level i+1 层的数据,现在我们要进行 Compaction 的话,就需要以某种形式将 Ta 中的数据塞进 Tb 和 Tc。Tb 和 Tc 组成一一组区间连续的 Key,而 Ta 跟他们都有一些重叠的地方。如果按照传统的方式重写这些 Page 的话,我们需要写 12 个 KV page,再加上 3 个 metadata page。但是在 Remapping Compaction 中,会选择重新写 Tx、Ty、Tz 三个 metadata page 分别指向已经存在的 KV Page。这样就把重写 page 的代价从 15 降低到了 3。


Hot-cold Separation

最后是冷热分离。显然的,高效的垃圾回收依赖数据分布的特征。假如相对较冷的数据能分布在一起,避免重复的 gc 热数据,可以极大的降低 gc 的写入放大。在 LSM tree 的写入模型当中,上层总是比下层的数据要小,换句话来说,上层的数据参与 gc 更多、更频繁。不同层次的数据有着不同的生命周期。基于这样的特性,有一个可能优化是在垃圾回收迁移数据的时候,尽可能的在同一级别的 KV 页中写入数据,这样能保证相似寿命的页面能被分组到相似的区块中。


KVSSD 性能分析

接下来我们看看 Paper 的性能分析环节。这篇 Paper 主要涉及三个性能方面的因素:写放大、吞吐和读放大。实验中使用的 SSD 设备是 15GB,5% 是保留空间,page size 是 32KB,block size 是 4MB。实验的方法是使用 blktrace 记录 leveldb 的 block I/O trace 然后在 SSD 模拟器上重放来收集闪存的操作数据。分别对比了



  • LSM: 基于 leveldb



  • dLSM: 一种 delay compaction 的优化



  • lLSM: 一种轻量级 compaction 的优化



  • nLSM



  • rLSM(-): nLSM with remapping compaction



  • rLSM: nLSM with remapping compaction and hot-cold sparation



file

file

根据这一组图可以看到,在给定的测试条件下 rLSM 能将写放大降低至原来的 12%,同时将吞吐提升了 4.47 倍,但是带来了 11% 的读放大。

好,到这里我们这篇 paper 的整体思路就已经介绍完了。我们来回顾一下 KVSSD 的价值,首先最明显的是 KVSSD 能带来更小写入放大,可以提高吞吐,进而降低 TCO,符合现在业界降本增效的潮流。其次从系统架构设计的角度上来看,KVSSD 能够进一步的将 I/O Offload 到 SSD 设备上。以 rocksdb 为例,使用 KVSSD 能降低 rocksdb 的 compaction 和 log 开销。此外,SSD 的计算能力实际上是在逐步提升的,未来可以在 SSD 中进行压缩,加密,校验等一系列重计算的任务。这些都为架构提供了新的可能性。


KVSSD 在工业上的进展

最后我们来看看业界的跟进情况。

在 2019 的 SYSTOR 会议上,三星沿用这一思路,发表了论文 Towards building a high-performance, scale-in key-value storage system[10],在论文中提到三星与 SNIA 联手制定了 Key Value Storage API 规范,基于现有的 Block SSD 实现了 KV-SSD 的原型:

file

还发表了公开的 KVSSD 相关的 API 与驱动:

https://github.com/OpenMPDK/KVSSD

根据三星论文中的分析来看,KV-SSD 展现了非常强的线性扩展能力,随着设备数量的增加,系统整体的 TPS 成线性增长,基本不受 CPU 的限制,感兴趣的同学可以找来看看。

这里我补充一下,三星的 KV-SSD 跟本次分享的论文只是大体思路相同,具体的设计和实现上还是有很大差异。

在 2021 年 6 月发布的 NVMe 2.0 规范中,KVSSD 相关的指令集已经被规范化为 NVMe-KV 指令集,成为新的 I/O 命令集之一,允许使用 Key 而不是 Block 地址来访问数据。考虑到业界对 NVMe 规范的广泛支持,预计完全支持 NVMe 2.0 的 SSD 很快就有商用的产品上市,希望大家保持关注。


Q&A

业界更关心 ZNS 还是 KVSSD?

ZNS 实现上要比 KVSSD 容易的多,成本也比 KVSSD 更好控制,所以目前业界对 ZNS 还是更热心一点。


KVSSD 冷热分离的设计是不是会导致 Block 擦写不均衡?

是的,论文里面没有展开论述相关的细节。按照目前这样的设计确实会导致这个问题,需要在实现的时候讲磨损均衡的问题也考虑进来。


KVSSD 需要占用宿主机的内存和 CPU 吗?

不需要,KVSSD 自带独立的内存和处理芯片,不依赖宿主机的资源。这也是使用 KVSSD 的意义之一:我们可以将这部分的负载 Offload 到 SSD 上,使得单一宿主机上可以接入更多的设备。


引用链接

[1] IEEE: https://ieeexplore.ieee.org/document/8342070

[2] Sung-Ming Wu: https://ieeexplore.ieee.org/author/37086370119

[3] Kai-Hsiang Lin: https://ieeexplore.ieee.org/author/37086098744

[4] Li-Pin Chang: https://ieeexplore.ieee.org/author/37733936200

[5] LSM-trie: https://www.usenix.org/conference/atc15/technical-session/presentation/wu

[6] PebblesDB: https://www.cs.utexas.edu/~vijay/papers/sosp17-pebblesdb.pdf

[7] WiscKey: https://www.usenix.org/conference/fast16/technical-sessions/presentation/lu

[8] badger: https://github.com/dgraph-io/badger

[9] Agatedb: https://github.com/tikv/agatedb

[10] Towards building a high-performance, scale-in key-value storage system: https://dl.acm.org/doi/10.1145/3319647.3325831


作者

丁皓 青云科技存储工程师


本文由博客一文多发平台 OpenWrite 发布!




推荐阅读
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了OkHttp3的基本使用和特性,包括支持HTTP/2、连接池、GZIP压缩、缓存等功能。同时还提到了OkHttp3的适用平台和源码阅读计划。文章还介绍了OkHttp3的请求/响应API的设计和使用方式,包括阻塞式的同步请求和带回调的异步请求。 ... [详细]
author-avatar
mobiledu2502916503
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有