高级硬盘缓存技术

随着固态闪存驱动器的引入,性能成为数据存储技术的前沿。在此之前,软件开发人员和服务器管理员需要设计方法来提高存储的 I/O 吞吐量,其中大多数方法导致低容量缓存到随机存取存储器 (RAM) 或 RAM 驱动器。虽然不如 RAM 快,但闪存驱动器几乎是梦想成真,但它也有其局限性——其中之一是封装在基于 NAND 芯片中的低容量。传统的旋转磁盘驱动器提供了用户所需的容量,但在快速访问方面却有所欠缺。即使使用 6Gb SATA 协议,顺序数据访问的最佳性能也约为每秒 150MB(或 MB/s),用于读取和写入操作,而随机访问则在 2-5MB/s 之间变化,因为跨多个扇区、多个磁道和多个旋转盘片的寻道被证明是一个极其破坏性的瓶颈。没有可移动部件的固态驱动器 (SSD) 显着降低了这些访问延迟,从而使这个瓶颈几乎不复存在。

即使在今天,消费级 SSD 也无法与磁性硬盘驱动器 (HDD) 提供的容量相提并论,这就是为什么在本文中,我打算向读者介绍一些经过验证的方法,以使用传统 HDD 获得接近 SSD 的性能。存在多个可以实现这一目标的开源项目,除了一个项目之外,所有项目都使用 SSD 作为缓存节点,而另一个项目则缓存到 RAM。我在这里介绍的设备驱动程序是 dm-cache、FlashCache 和 RapidDisk/RapidCache 套件;我还简要讨论了 bcache 和 EnhanceIO。

注意

要构建本文中显示的内核模块,您需要安装完整内核源代码或当前内核映像版本的内核头文件。

在我的示例中,我使用的是商用 SATA III (6Gbps) SSD,其平均性能如下

  • 顺序读取:231MB/秒

  • 顺序写入:74MB/秒

  • 随机读取:230MB/秒

  • 随机写入:72MB/秒

此 SSD 为较慢的机械 SATA III HDD 提供缓存层,后者的性能如下

  • 顺序读取:115MB/秒

  • 顺序写入:72MB/秒

  • 随机读取:2MB/秒

  • 随机写入:2MB/秒

在我的环境中,SSD 标记为 /dev/sdb,HDD 标记为 /dev/sda3。这些是非侵入式的透明缓存解决方案,旨在实现 SSD 的性能优势。它们可以添加到现有存储目标并从中删除,而不会出现问题或数据丢失(假设所有缓存数据都已成功刷新到磁盘)。此外,此处的所有示例都展示了写回缓存方案,但 RapidCache 除外,后者将改为在直写模式下使用。在写回模式下,新写入的数据会被缓存,但不会立即写入目标目标。直写模式始终会将新数据写入目标,同时仍将其保留在缓存中以供将来读取。

注意

此处显示的基准测试是通过使用 FIO 获得的,FIO 是一种为数据存储技术设计的文件 I/O 基准测试和测试工具。它由 Linux 内核开发人员 Jens Axboe 维护。除非另有说明,否则所有捕获的 I/O 均以典型的 4KB 页面大小异步写入存储目标,每次传输 32 次(即队列深度)。

dm-cache

dm-cache 已经存在相当长一段时间了——至少从 2006 年开始。它最初是 Ming Zhao 博士在 IBM 研究院暑期实习期间开发的一个研究项目。dm-cache 模块最近已集成到 Linux 内核树中,版本为 3.9。无论您选择在最近下载的内核中启用它,还是从官方项目站点编译它,结果都将相同。要加载模块,您需要调用 modprobe 或 insmod


$ sudo modprobe dm-cache

现在模块已加载,您需要告知该模块将哪个驱动器指向缓存,将哪个驱动器指向目标。dm-cache 项目站点提供了一个 Perl 脚本来简化此过程,名为 dmc-setup.pl。例如,如果我想使用整个 SSD 以写回缓存模式和 4KB 块大小,我将键入


$ sudo perl dmc-setup.pl -o /dev/sda3 -c /dev/sdb -n cache -b 8 -w

此脚本是下面等效 dmsetup 命令的包装器


$ echo 0 20971520 cache /dev/sda3 /dev/sdb 0 8 65536 16 1 | 
 ↪dmsetup create cache

托管在项目站点上的 dm-cache 文档提供了有关每个参数字段的详细信息,因此我在此处不再赘述。

您可能会注意到,在两个示例中,我都将两个驱动器的映射命名为“cache”。因此,当我需要访问驱动器映射时,我必须将其称为“cache”。

以下映射将所有数据请求传递给缓存驱动程序,然后缓存驱动程序执行必要的魔法来处理请求,要么完全从缓存中处理,要么同时从缓存和较慢的设备处理


$ ls -l /dev/mapper
total 0
lrwxrwxrwx 1 root root       7 Jun 30 12:10 cache -> ../dm-0
crw------- 1 root root 10, 236 Jun 30 11:52 control

就像任何其他启用设备映射器的目标一样,我也可以拉取详细的映射数据


$ sudo dmsetup status cache
0 20971520 cache stats: reads(83), writes(0), 
 ↪cache hits(0, 0.0),replacement(0), replaced dirty blocks(0)

$ sudo dmsetup table cache
0 20971520 cache conf: capacity(256M), associativity(16), 
 ↪block size(4K), write-back

如果目标驱动器已经格式化并包含数据,您只需挂载它即可;否则,将其格式化为您指定的文件系统


$ sudo mke2fs -F /dev/mapper/cache

请记住,这些解决方案是非侵入性的,因此如果您有需要保留在该磁盘驱动器上的现有数据,请跳过上述步骤,直接挂载它以进行数据访问


$ sudo mount /dev/mapper/cache /mnt/cache
$ df|grep cache
/dev/mapper/cache  10321208 1072632   8724288  11% /mnt/cache

使用基准测试实用程序,数字会有所不同。在读取操作中,这完全取决于所需数据是否驻留在缓存中,或者模块是否需要从较慢的磁盘检索它。在写入操作中,这取决于闪存技术本身,以及它是否需要经历典型的可编程擦除 (PE) 周期才能写入新数据。无论如何,对较慢驱动器的随机读/写访问都得到了显着提高

  • 顺序读取:105MB/秒

  • 顺序写入:50MB/秒

  • 随机读取:67MB/秒

  • 随机写入:51MB/秒

您可以通过键入以下内容继续监控缓存状态


$ sudo dmsetup status cache 
0 20971520 cache stats: reads(301319), writes(353216), 
 ↪cache hits(24485, 0.3),replacement(345972), 
 ↪replaced dirty blocks(92857)

要删除缓存映射,请卸载驱动器并调用 dmsetup


$ sudo umount /mnt/cache
$ sudo dmsetup remove cache
FlashCache

FlashCache 是 Facebook 开发和维护的一个项目。它的灵感来自 dm-cache。与 dm-cache 非常相似,它也是从设备映射器框架构建的。它目前托管在 GitHub 上,可以从那里克隆。该存储库包含内核模块和管理实用程序。构建并安装后,加载内核模块,并以与前面示例类似的方式,创建 SSD 和 HDD 的映射


$ sudo modprobe flashcache
$ sudo flashcache_create -p back -b 8 cache /dev/sdb /dev/sda3
cachedev cache, ssd_devname /dev/sdb, disk_devname /dev/sda3 
 ↪cache mode WRITE_BACK block_size 8, md_block_size 8, 
 ↪cache_size 0
FlashCache metadata will use 223MB of your 3944MB main memory

flashcache_create 管理实用程序类似于用于 dm-cache 的 dmc-setup.pl Perl 脚本。它是一个包装实用程序,旨在简化 dmsetup 过程。与 dm-cache 模块一样,一旦创建映射,您可以通过键入以下内容查看映射详细信息


$ sudo dmsetup table cache
0 20971520 flashcache conf:
    ssd dev (/dev/sdb), disk dev (/dev/sda3) cache mode(WRITE_BACK)
    capacity(57018M), associativity(512), data block size(4K) 
     ↪metadata block size(4096b)
    skip sequential thresh(0K)
    total blocks(14596608), cached blocks(83), cache percent(0)
    dirty blocks(0), dirty percent(0)
    nr_queued(0)
Size Hist: 4096:83 
$ sudo dmsetup status cache
0 20971520 flashcache stats: 
    reads(83), writes(0)
    read hits(0), read hit percent(0)
    write hits(0) write hit percent(0)
    dirty write hits(0) dirty write hit percent(0)
    replacement(0), write replacement(0)
    write invalidates(0), read invalidates(0)
    pending enqueues(0), pending inval(0)
    metadata dirties(0), metadata cleans(0)
    metadata batch(0) metadata ssd writes(0)
    cleanings(0) fallow cleanings(0)
    no room(0) front merge(0) back merge(0)
    disk reads(83), disk writes(0) ssd reads(0) ssd writes(83)
    uncached reads(0), uncached writes(0), uncached IO requeue(0)
    disk read errors(0), disk write errors(0) ssd read errors(0) 
     ↪ssd write errors(0)
    uncached sequential reads(0), uncached sequential writes(0)
    pid_adds(0), pid_dels(0), pid_drops(0) pid_expiry(0)

挂载映射以进行文件访问


$ sudo mount /dev/mapper/cache /mnt/cache

使用相同的基准测试实用程序,观察 FlashCache 和先前模块之间的差异

  • 顺序读取:284MB/秒

  • 顺序写入:72MB/秒

  • 随机读取:284MB/秒

  • 随机写入:71MB/秒

这些数字看起来更像原生 SSD 性能。但是,我想指出的是,本文的目的不是证明一种解决方案比另一种解决方案性能更好,而是为了启发读者可以使用多种方法来加速对现有和较慢配置的数据访问。

要卸载和删除驱动器映射,请在终端中键入以下内容


$ sudo umount /mnt/cache
$ sudo dmsetup remove /dev/mapper/cache
RapidDisk 和 RapidCache

RapidDisk 当前版本为 2.9,是一款高级 Linux RAM 磁盘,其功能包括动态分配 RAM 作为块设备、将其用作独立磁盘驱动器,甚至通过 RapidCache 将其映射为较慢本地磁盘驱动器的缓存节点(后者受 FlashCache 启发,并使用设备映射器框架)。RAM 通过在需要时分配内存页来处理数据存储。它是一种易失性存储形式,因此如果断电或计算机重启,RAM 中存储的所有数据都将无法保存。这就是 RapidCache 模块设计为仅处理直读/直写缓存的原因,这意味着任何打算写入较慢存储设备的内容都将被缓存到 RapidCache 并立即写入硬盘驱动器。并且,如果正在从硬盘驱动器请求数据,并且该数据在 RapidCache 节点中不存在,它将从较慢的设备读取数据,然后将其缓存到 RapidCache 节点。此方法将保留与硬盘驱动器相同的写入性能,但显着提高了缓存数据的顺序和随机访问读取性能。

一旦构建并安装了包含两个内核模块和一个管理实用程序的软件包,您需要通过在命令行中键入以下内容来插入模块


$ sudo modprobe rxdsk
$ sudo modprobe -r rxdsk

假设您正在运行一台包含 4GB RAM 的计算机,并且您可以自信地说,操作系统及其应用程序永远不会使用其中至少 1GB 的 RAM。使用 RapidDisk 创建 1GB 大小的 RAM 驱动器,您将键入


$ sudo rxadm --attach 1024

请记住,RapidDisk 不会预先分配此存储空间。它仅在使用时分配 RAM。

仅对 RAM 驱动器进行的快速基准测试产生了一些非常快的 4KB I/O 传输结果

  • 顺序读取:1.6GB/秒

  • 顺序写入:1.6GB/秒

  • 随机读取:1.3GB/秒

  • 随机写入:1.1GB/秒

它使用 1MB I/O 传输产生以下结果

  • 顺序读取:4.9GB/秒

  • 顺序写入:4.3GB/秒

  • 随机读取:4.9GB/秒

  • 随机写入:4.0GB/秒

令人印象深刻,对吧?要使用如此快速的 RAM 驱动器作为较慢驱动器的缓存节点,必须创建一个映射,其中 /dev/rxd0 是用于访问 RAM 驱动器的节点,/dev/mapper/rxc0 是用于访问两个驱动器映射的节点


$ sudo rxadm --rxc-map rxd0 /dev/sda3 4

您可以通过键入以下内容获取附加设备和映射的列表


$ sudo rxadm --list
rxadm 2.9
Copyright 2011-2013 Petros Koutoupis

List of rxdsk device(s):

 RapidDisk Device 1: rxd0
    Size: 1073741824

List of rxcache mapping(s):

 RapidCache Target 1: rxc0
0 20971519 rxcache conf:
    rxd dev (/dev/rxd0), disk dev (/dev/sda3) mode (WRITETHROUGH)
    capacity(1024M), associativity(512), block size(4K)
    total blocks(262144), cached blocks(0)
 Size Hist: 512:663 

与之前的基于设备映射器的解决方案一样,您甚至可以通过键入以下内容列出映射的详细信息


$ sudo dmsetup table rxc0
0 20971519 rxcache conf:
    rxd dev (/dev/rxd0), disk dev (/dev/sda3) mode (WRITETHROUGH)
    capacity(1024M), associativity(512), block size(4K)
    total blocks(262144), cached blocks(0)
 Size Hist: 512:663 

$ sudo dmsetup status rxc0
0 20971519 rxcache stats: 
    reads(663), writes(0)
    cache hits(0) replacement(0), write replacement(0)
    read invalidates(0), write invalidates(0)
    uncached reads(663), uncached writes(0)
    disk reads(663), disk writes(0)
    cache reads(0), cache writes(0)

根据需要格式化映射并挂载它


$ sudo mount /dev/mapper/rxc0 /mnt/cache

基准测试产生以下结果

  • 顺序读取:794MB/秒

  • 顺序写入:70MB/秒

  • 随机读取:901MB/秒

  • 随机写入:2MB/秒

请注意,写入性能不是很出色,那是因为它本来就不是为了实现出色的写入性能。直写模式仅承诺更快的缓存数据读取性能和与原始驱动器一致的写入性能。但是,读取性能在访问缓存数据时显示出显着提高。

要删除映射并分离 RAM 驱动器,请键入以下内容


$ sudo umount /mnt/cache
$ sudo rxadm --rxc-unmap rxc0
$ sudo rxadm --detach rxd0
其他值得一提的解决方案

bcache

bcache 对于硬盘缓存领域来说相对较新。它提供与先前解决方案相同的所有特性和功能,但其功能除外,它可以将一个或多个 SSD 映射为一个或多个 HDD 的缓存,而不是一个卷到一个卷。但是,该项目的维护者确实吹嘘其在从缓存访问数据性能方面优于其他解决方案。从我所能判断的来看,bcache 与之前的解决方案不同,它不依赖设备映射器框架,而是一个独立的模块。在撰写本文时,它已设置为集成到 Linux 内核树的 3.10 版本中。不幸的是,我还没有机会或合适的设置来测试 bcache。因此,我还没有能够更深入地研究这个解决方案并对其性能进行基准测试。

EnhanceIO

EnhanceIO 是 STEC, Inc. 生产并托管在 GitHub 上的 SSD 缓存解决方案。它很大程度上受到了 Facebook 为 FlashCache 所做工作的启发,虽然它是开源的,但该公司为那些寻求额外支持的人提供了商业版本。STEC 并没有简单地修改 FlashCache 的几行代码并重新发布它。相反,STEC 重写了写回缓存逻辑,同时还改进了其他方面,例如内存占用、故障处理等。与 bcache 一样,我还没有机会安装和测试 EnhanceIO。

总结

这些解决方案旨在以显着降低的成本为用户提供接近 SSD 速度和 HDD 容量的性能。从数据中心到您的家庭办公室,这些解决方案几乎可以部署在任何地方。它们也可以进行调整,以便在其预期环境中更适当地运行。它们中的一些甚至提供了多种缓存算法选项,例如最近最少使用 (LRU)、最近最多使用 (MRU)、两者的混合,或者只是简单的先进先出 (FIFO) 缓存方案。前三个选项在性能方面可能很昂贵,因为它们需要跟踪缓存数据集以了解已访问的内容以及最近的访问时间,以便确定是否丢弃它。然而,FIFO 的功能类似于循环缓冲区,其中最旧的缓存数据集将首先被丢弃。除了 RapidCache 之外,以 SSD 为中心的模块还保留缓存的元数据,以确保任何中断,包括电源周期/中断,都不会损害数据的完整性。

资源

dm-cache: http://visa.cs.fiu.edu/tiki/dm-cache

FlashCache: https://github.com/facebook/flashcache

EnhanceIO: https://github.com/stec-inc/EnhanceIO

bcache: http://bcache.evilpiepirate.org

RapidDisk: http://www.rapiddisk.org

FIO Git 存储库: http://git.kernel.dk/?p=fio.git;a=summary

维基百科缓存算法页面: http://en.wikipedia.org/wiki/Cache_algorithms

Petros Koutoupis,《Linux Journal》特约编辑,目前是 Cray 公司 Lustre 高性能文件系统部门的高级性能软件工程师。他也是 RapidDisk 项目的创建者和维护者。Petros 在数据存储行业工作了十多年,并帮助开创了当今广泛应用的许多技术。

加载 Disqus 评论