【论文阅读】NobLSM: 用于SSD的具有非阻塞写入的LSM tree

摘自一篇有关存储的论文:

摘要:

固态驱动器 (SSD) 越来越受欢迎。同时,基于日志结构合并树(LSM-tree)的键值存储被广泛用于数据管理。 LSM-tree 经常调用同步来持久化新生成的文件以实现崩溃一致性。阻塞同步对于性能来说代价高昂。我们重新审视了 LSM-tree 同步的必要性。我们发现 Ext4 日志包含异步提交以隐式保存文件。因此,我们设计了 NobLSM,它使 LSM-tree 和 Ext4 协作以非阻塞异步提交替换大多数同步,而不会失去一致性。实验表明,NobLSM 在普通 SSD 上具有更高的吞吐量,明显优于最先进的 LSM 树。

对传统的LSM tree做了对比:

Minor Compaction:

传统的LSM tree的写操作将(key,value)对写入 Mutable MemTable(可变的),当该表写满后再转换为 Immutable MemTable(不可变的),然后进行一次 Minor Compaction(次要压缩),并且写入𝐿0层的 SSTable。

Major Compaction:

然后在L0层一下会发生 Major Compaction(主要压缩):LSM-tree 选择几个 𝐿𝑛 和 𝐿𝑛+1 个 SSTable,对存储在其中的 KV 对进行合并排序,并将排序后的 KV 对有序地打包到新的 𝐿𝑛+1 个 SSTable 中。

为了排除由于主要压缩失败导致的不一致,LSM-tree 在处理新旧 SSTable 时强制执行严格的顺序。简而言之,只有在通过同步(fsync 或 fdatasync)持久化新的 SSTable 之后,LSM-tree 才能删除已保留以备不时之需的旧 SSTable,以防突然崩溃。同步是一种阻塞写入操作,它直接将数据持久化到存储设备中,并强制阻止后续 I/O 操作,直到它完成。

但是同步操作会给性能上带来很大的影响,因为在执行同步操作的时候,必须先生成新的SSTable并且全部执行完后,才能将旧的SSTable删除,这样的话会造成操作的停顿,从而影响执行操作的速度;如果 𝐿0 和 𝐿1 之间的主要压缩在不可变的 memtable 等待转换时尚未完成,它将暂停在前台。若放弃一致性,则可以带来速度和性能上的提升;

需要解决的问题:

而本文的重点就是在保持一致性的同时,尽最大的可能减少同步操作,从而提升存储引擎的性能。

内容:

本文提出的设计主要依赖于非阻塞写入,并且每个 KV 对只同步一次以实现崩溃一致性。它被命名为 NobLSM(非阻塞 LSM-tree),它从文件系统中寻求帮助,以尽量减少同步的使用。

NobLSM的本质:

LSM-tree通过底层文件系统将sstable存储为文件,这必须保证系统级崩溃的一致性。
流行的日志文件系统Ext4在其 default data = ordered下,通过在持续写回文件的修改后的数据后将文件inode ofa有序地提交到日志中,来确保文件系统元数据 (例如,inode) 的一致性。
Ext4由于sync的显式调用而同步地启动提交,或者异步地启动提交,即每隔一段时间或在dram页面缓存不足时启动。一旦提交成功,Ext4保证提交文件的元数据和数据都是可崩溃的。

因此,如果我们可以精确地跟踪Ext4何时提交为主要压缩生成的新sstable,那么我们就不必费心用大量的性能损失来强制同步它们。

NOBLSM的主要思想:

  1. NobLSM生成崩溃一致的LSM树,而无需在主要压缩的关键路径上使用同步;
  2. 当 NobLSM 在次要压缩期间从不可变的 memtable 生成 𝐿0 SSTable 时,它​​只会同步打包在 𝐿0 SSTable 中的 KVpairs 一次;
  3. NobLSM 剥夺了压缩的 SSTable 为搜索请求提供的服务并在适当的时候丢弃它们,因为它们在主要压缩之后是短暂的和易变的。

在这里插入图片描述

背景

1. LSM tree 崩溃一致性

LSM-tree 维护内存中的 memtables 以吸收那些已经到达的 KV 键值对,并维护多个磁盘级别 (𝐿𝑛 , 𝑛 ≥ 0) 以持久存储 KV 对。 LSM-tree 利用预写日志记录到达的 KV键值对,然后再将它们放入 memtable。一旦 KV 键值对被转储到 𝐿0,LSM-tree 通过备份副本和同步来确保它们的一致性。在将不可变 memtable 转换为 𝐿0 SSTable 的Minor Compaction之后,LSM-tree 通过在删除相应日志之前调用 sync 来保持 SSTable。对于𝐿𝑛和𝐿𝑛+1之间的Major Compaction,LSM-tree首先生成并同步新的𝐿𝑛+1 SSTables。然后它安全地删除压缩的𝐿𝑛和𝐿𝑛+1 SSTables。总而言之,LSM-tree 在次要和主要压缩期间不断调用同步以保持 KV 键值对。此外,只要 KV 键值对参与未来的压缩,LSM-tree 就会再次同步它。

2. 阻止同步和ext4日志记录

许多kV存储依赖于同步(fsync或fdatasync)来实现耐用性和一致性。在Linux中,像LevelDB这样的LSM树默认调用功能几乎与fsync相同的fdatasync。同步对性能的影响是有害的。同步不仅强制将数据保存在存储设备中,而且还施加了阻止后续I/O操作的排序障碍;
同步由底层文件系统执行,该文件系统确保系统级崩溃一致性以支持应用程序。Ext4作为利用JBD2进行日志记录的流行文件系统,保证了文件系统元数据(例如,文件的索引节点)的一致性,并在其默认的data=ordered模式中强制执行文件元数据和数据的写入顺序。例如,当名为“dac22.txt”的文件的数据块被修改时,ext4将保存文件inode的元数据块提交到持久性日志中。在执行此操作之前,ext4要求修改的数据块“dac22.txt”必须已写回存储设备。因此,一旦提交了inode,与其相关的所有数据块都应该已经持久化。

同步对 LSM-tree 的影响

我们进行了另一项测试,以观察同步对真实 LSM 树的实际影响。 我们禁用了 LevelDB 的所有同步,从而在没有一致性保证的情况下使其“不稳定”。 然而,它通过减少同步的使用产生了我们试图达到的最佳性能。 我们使用 LevelDB 中嵌入的微基准 db_bench 随机放置 1000 万个 1KB 大小的 KV 对(fillrandom),然后覆盖它们(overwrite)。 如图 2a 的左半部分所示,在没有同步的情况下,填充随机和覆盖 2MB SSTables 的执行时间分别缩短了 53.2% 和 51.4%。 因此,KV 对的频繁、重复同步严重降低了 LSM 树的性能。
在这里插入图片描述

不同大小对 SSTable 的影响。除了 2MB,我们还测试了 64MB SSTables。 64MB 是 RocksDB [16] 的默认大小

如图 2b 所示,从 2MB 到 64MB,原始 LevelDB 的执行时间分别减少了 62.4% 和 56.2%,用于填充随机和覆盖。较大的 SSTable 会导致聚合刷新并减少障碍。尽管如此,即使使用 64MB SSTables,对于两个工作负载,使用同步仍然会分别降低 45.6% 和 59.4% 的性能。因此,单独使用大型 SSTables 而不大幅减少同步不能完全减轻同步的灾难性成本。在本文中,我们采用了一种整体方法并开发了 NobLSM,它将大多数同步替换为 Ext4 日志中隐含的异步提交。

NobLSM 的设计

NobLSM 是由 LSM-tree 和 Ext4 之间简单但有效的协作制成的。它主要依靠非阻塞写入来实现崩溃一致性,并且在次要压缩中将不可变 memtable 转换为 𝐿0 SSTable 时仅使用一次同步。至于主要压缩,NobLSM 利用 Ext4 的异步日志提交,而不是同步,来隐式地持久化新的 SSTables。提交成功后,NobLSM 安全地删除旧的 SSTables 以提高 SSD 空间效率。它要求 LSM-tree 和 Ext4 在用户和内核空间之间进行全面合作。通过这样做,NobLSM 设法避免了主要压缩的关键路径上的阻​​塞同步,从而提高了性能并同时实现了一致性。

Minor Compaction:

NobLSM 将完全可变的 memtable 变成不可变的。它会在内存表空间用完时启动次要压缩,并将不可变内存表转储为𝐿0 SSTable。它通过调用 sync 来保持 𝐿0 SSTables。这是 NobLSM 同步 KV 对的唯一一次。同步后,NobLSM 会删除相应的日志并释放不可变的 memtable。

Major Compaction:

在 𝐿𝑛 和 𝐿𝑛+1 之间的主要压缩中,NobLSM 合并排序来自选定 SSTables 的所有 KV 对。 然后它将它们打包到新的 𝐿𝑛+1 SSTables 中。 NobLSM 既不会同步新的 SSTable,也不会立即删除旧的。 它异步写入新文件。 接下来,它利用我们用 Ext4 开发的系统调用来精确跟踪新的 SSTable 何时在 SSD 中变得持久(参见第 4.2 节),其效果与通过同步持久化文件相同。 因此,NobLSM 从主要压缩的关键路径中消除了由同步引起的直接 I/O 和障碍。

在这里插入图片描述
首先,Ext4 的异步提交意味着时间不确定性,NobLSM 需要一个结构来连续删除过时的 SSTables。其次,NobLSM 减少同步带来了吞吐量,进而需要更多的压缩。
上图便采用了两个集合之间的映射关系来监控 Ext4 尚未完成提交其新 SSTables 的正在进行的和历史的主要压缩(有点病句);

2.使用异步提交的Ext4

Ext4 日志的含义:

Ext4 将每个事务提交到日志,然后检查点文件到位。 由于同步,它同步或异步启动提交,即每隔一段时间(默认为 5 秒)或当 DRAM 页缓存中的脏页达到阈值(默认为 10%)时,以较早者为准。 一旦成功提交到日志,文件元数据或数据是可崩溃恢复的。

文件数据的变化导致文件元数据的变化,尤其是文件的inode。 在其默认 data=ordered 模式下,Ext4 仅记录元数据。 给定一个包含修改数据的文件,data=ordered 模式在将文件的 inode 提交到日志之前强制将数据保存到文件中。 因此,一旦 Ext4 提交了包含文件 inode 的事务,该文件必须是持久的,因为文件的数据和元数据都已连续持久化。

模式含义
journal可靠性最高,提供了完全的数据块和元数据块的日志,所有的数据都会被先写入到日志里,然后再写入磁盘上。在文件系统崩溃的时候,可以通过日志重放,把数据和元数据恢复到一致性的状态。但同时,journal模式性能是三种模式中最差的,因为所有的数据都需要日志来记录。
ordered不记录data的journal,只记录metadata的journal日志,但是在写metadata的journal前,必须先确保data已经落盘。
writeback不记录data journal,仅记录metadata journal。并且不保证data比metadata先落盘。
两个内核空间表:

Ext4 依赖于 Linux 内核的 writeback 线程来提交事务。但是随着时间的推移,Ext4 日志由系统和所有应用程序全局共享,这样就会出现两个问题:

  1. 一个事务可能是由NobLSM之外的inode组成;
  2. 在一个主要压缩中生成的新 SSTables 的 inode 可能在不同的事务中挂起;

我们在内核空间中为 Ext4 维护了两张表来记录每个新的 SSTable 是否被持久化。 Pending Table 记录 NobLSM 跟踪的所有新 SSTables 的 inode,而 Committed Table 保存已提交的那些。提交事务完成后,Ext4 日志将事务覆盖的 inode 从 Pending Table 转移到 Committed Table。
在这里插入图片描述

两个新的系统调用:

我们为NobLSM添加了一个syscall (check_commit),以告诉Ext4后者将开始跟踪哪些inode。因此,check_commit填充了待定表中NobLSM寻址的inode。另一个syscall (is_committed) 供NobLSM查询Ext4是否已将特定inode移至CommittedTable。当noblsm意识到所有新的sstable实际上都承诺用于主要压实时,它会安全地删除压实的旧sstable;

这两个内核空间表支持由 NobLSM 的 LSM 树在运行时维护的全局用户空间集对。 通过两个系统调用连接,它们在系统和应用程序级别共同运行。 这种系统化的设计使 NobLSM 能够有效地管理 SSTables 而不会失去一致性保证。 此外,NobLSM 在后台执行所有操作,从而在 LSM-tree 操作的关键路径上产生最小成本。

已压缩的SSTables的管理

需要注意两个问题:

  1. 剥夺他们为搜索请求提供服务的权利;
  2. 在适当的时候丢弃它们,以提高SSD的空间效率;
1. Transient Duplicate Copies of KV Pairs.:

由于 NobLSM 会暂时保留新旧 SSTable,因此有时会在两个 SSTable 中存在一个有效的 KV 对。传统的 LSMtrees 维护一个由 Manifest 文件支持的内存版本,以跟踪所有有效的 SSTables。由于旧的 SSTable 具有潜在的易失性,因此使用它们来服务搜索请求是不可行的。因此,NobLSM 将它们标记为“影子”并且不向它们发送搜索请求;

2.Reclamation of Obsolete SSTables:

在成功提交日志后,NobLSM 要求 Ext4 删除相关的影子 SSTable。我们为 NobLSM 设置了每 5 秒的频率,以通过 is_committed 系统调用向 Ext4 查询新 SSTables 的提交。查询间隔和 Ext4 的提交间隔之间的这种匹配减少了跨用户和内核空间的不必要检查。

旧的 SSTables 用于过去的主要压缩。 Ext4 在删除时从 Commtted 表中删除它们的 inode。 这提高了管理内核空间表的时间和空间效率,并避免了由于 inode 重用而导致的表间循环依赖。

NobLSM的崩溃一致性:

NobLSM 记录一个到达的 KV 对,然后在次要压缩期间通过同步将其持久存储到 𝐿0 SSTable 中。 𝐿𝑛 和 𝐿𝑛+1 (𝑛 ≥ 0) 之间的任何后续主要压缩都取决于该同步。 NobLSM 保证,自从第一次使 KV 对变得持久时,它在崩溃后永远不会丢失。基本原理是,在主要压缩中,NobLSM 严格遵守在删除压缩的之前隐式持久化新 SSTable 的顺序。总而言之,NobLSM 实现了与传统 LSM 树相同的崩溃一致性,但调用了最少数量的同步。

Putting Everything Together:

根据图3,可逐步理解下列步骤:

  • (1) :NobLSM 的 LSM-tree 分别在 𝐿1 和 𝐿2 处选择和压缩 SSTables (127 和 123) 到新的𝐿2 SSTables (230 和 231);
    (2) : Ext4 异步写入它们;
    (3) : LSM-tree 获得它们的 inode编号#4567 和 #4568。 LSM-tree 要求 Ext4 通过系统调用 check_commit ;
    (4):填充 Pending Table 中的两个 inode 并更新𝑝-to-𝑞 依赖项;
    (5) : 同时,Ext4 将两个新 SSTables 的数据写回到 SSD 中;
    (6): 并将两个 inode 与事务一起提交到日志中 。
    (7): 当提交成功时,ext4将索引节点移动到提交的表中;
    (8): 这样LSM-Tree就可以通过_提交的系统调用来感知两个新的SSTable的持久性;
    (9): 接下来,LSM-Tree删除过时的SSTables (123和127);
    (10): 因此,ext4删除了两个文件,并清除了已提交表中的相应条目。
    在这里插入图片描述
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值