Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

30.6. 调整 VDO

30.6.1. VDO 调优简介

与调优数据库或其他复杂软件一样,调优 VDO 涉及在多个系统限制之间实现利弊,需要进行一些试验。可用于调优 VDO 的主要控制是分配给不同类型的工作的线程数量、这些线程的 CPU 关联性设置以及缓存设置。

30.6.2. VDO 架构背景信息

VDO 内核驱动程序是多线程的,通过在多个并发 I/O 请求间增加处理成本来提高性能。它将一个线程处理从头到尾的 I/O 请求,而是将不同的工作阶段委派给一个或多个线程或线程组,它们之间传递的消息通过管道进行。这样,一个线程可以序列化对全局数据结构的所有访问,而无需锁定并在每次处理 I/O 操作时解锁它。如果 VDO 驱动程序是精心调优的,则每次线程完成请求处理阶段时,通常会进行另一个排队以进行相同的处理。保持这些线程忙碌可减少上下文切换和调度开销,从而提高性能。单独的线程也用于可阻止的操作系统的一部分,如将 I/O 操作排队到底层存储系统或消息到 UDS。
VDO 使用的各种 worker 线程类型有:
逻辑区线程
逻辑 线程(包括字符串 kvdo:logQ )在逻辑块号(LBN)之间维护提供给 VDO 设备用户和基础存储系统中的物理块号(PBN)之间的映射。它们还实施锁定,以便尝试写入同一块的两个 I/O 操作不会被同时处理。逻辑区线程在读写操作过程中处于活动状态。
LBN 划分为块( 块映射页面 包含 3 MB 以上的 LBN),这些块被分成划分在线程中 的区域
处理应该在线程中平均分配,但有些未灵活的访问模式偶尔可能集中在一个线程或其他线程中。例如,在给定块映射页面中频繁访问 LBN 将导致其中一个逻辑线程处理所有这些操作。
可以使用 vdo 命令的 --vdoLogicalThreads=thread count 选项控制逻辑区线程数量
物理区线程
物理, 或 kvdo:physQ, threads 管理数据块分配和维护参考计数。它们在写入操作过程中处于活跃状态。
与 LBNs 一样,PBNs 被分成名为 slabs 的块,这些块被进一步划分为区域,并分配给分发处理负载的 worker 线程。
可以使用 vdo 命令的 --vdoPhysicalThreads=thread count 选项控制物理区线程数量。
I/O 提交线程
kvdo:bioQ 线程将块 I/O (bio)操作从 VDO 提交到存储系统。它们接受由其他 VDO 线程排队的 I/O 请求,并将它们传递给底层设备驱动程序。这些线程可以与设备关联的数据结构通信并更新与设备关联的数据结构,或者为设备驱动程序的内核线程设置请求进行处理。如果底层设备的请求队列已满,提交 I/O 请求可以阻止,因此此工作由专用线程完成,以避免处理延迟。
如果这些线程经常由 pstop 工具显示在 D 状态,则 VDO 通常会使存储系统忙于 I/O 请求。如果存储系统可以并行服务多个请求,或者请求处理被管道,则这通常可以正常工作。如果线程 CPU 使用率在这些期间非常低,则可能会减少 I/O 提交线程的数量。
CPU 使用量和内存争用取决于 VDO 下的设备驱动程序。如果在添加更多线程时每个 I/O 请求的 CPU 使用率增加,请检查这些设备驱动程序中的 CPU、内存或锁定争用。
可以使用 vdo 命令的 --vdoBioThreads=thread count 选项控制 I/O 提交线程数量。
CPU 处理线程
kvdo:cpuQ 线程可用于执行任何 CPU 密集型工作,如计算哈希值或压缩不阻止或需要独占访问与其他线程类型关联的数据结构。
可以使用 vdo 命令的 --vdoCpuThreads=thread count 选项控制 CPU 处理线程数量。
I/O 确认线程
kvdo:ackQ 线程向位于 atop VDO 的任何位置发出回调(例如,内核页面缓存或应用程序程序线程进行直接 I/O)来报告 I/O 请求的完成。CPU 时间要求和内存争用将依赖于其他内核级别的代码。
可以使用 vdo 命令的 --vdoAckThreads=thread count 选项控制确认线程数量。
不可扩展的 VDO 内核线程:
重复数据删除线程
kvdo:dupeQ 线程使用排队的 I/O 请求和联系 UDS。由于如果服务器无法快速处理请求,或者内核内存受其他系统活动限制,则套接字缓冲区可能会填满,因此如果线程应阻止,其他 VDO 处理可以继续。还有一个超时机制,用于在较长的延迟后跳过 I/O 请求(以秒为单位)。
日志线程
kvdo:journalQ 线程更新恢复日志,并调度用于写入的日志块。VDO 设备只使用一个日志,因此无法在线程间分割工作。
packer thread
启用压缩时,kvdo:packerQ 线程在写入路径中处于活跃状态,收集 kvdo:cpuQ 线程压缩的数据块,以最小化浪费的空间。每个 VDO 设备有一个 packer 数据结构,因此每个 VDO 设备有一个 packer 线程。

30.6.3. 要调整的值

30.6.3.1. CPU/内存

30.6.3.1.1. 逻辑, 物理, cpu, ack 线程数
逻辑、物理、cpu 和 I/O 确认工作可以分布到多个线程中,可以在初始配置或之后重启 VDO 设备时指定的数量。
一个内核或一个线程可以在指定时间内执行有限的工作。只有一个线程计算所有数据块哈希值,例如,对每秒可以处理的数据块数施加硬限制。划分多个线程(和内核)的工作减轻了这种瓶颈。
当线程或核心接近 100% 的使用时,更多工作项目往往会排队进行处理。虽然这可能会导致 CPU 的闲置周期减少,但对单个 I/O 请求设置延迟和延迟通常会增加。根据某些队列模型,利用率级别高于 70% 或 80% 可能会导致超过正常处理时间的延迟。因此,对于具有 50% 或更高利用率的线程或核心,即使这些线程或内核并不总是忙碌,也可能有助于进一步分发工作。
相反,如果线程或 CPU 非常轻便加载(通常是睡眠状态),为它提供工作的可能性更有可能造成一些额外的成本。(尝试唤醒另一个线程的线程必须在调度程序的数据结构上获取全局锁定,并可能会发送处理器中断来转移到其他内核。)当将更多内核配置为运行 VDO 线程时,给定数据片段会尽可能地缓存,因为线程在线程之间移动,或者在内核之间移动时 - 因此,太多的工作分布也会降低性能。
每个 I/O 请求由逻辑、物理和 CPU 线程执行的工作将因工作负载的类型而异,因此系统应该使用服务的不同类型工作负载进行测试。
在涉及成功 deduplication 的同步模式下写入操作需要额外的 I/O 操作(读取之前存储的数据块)、一些 CPU 周期(复制新数据块以确认它们匹配),以及日志更新(将 LBN 映射到之前存储的数据块的 PBN)与新数据的写入。当以 async 模式检测到重复时,以上述读和比较操作的成本避免数据写入操作;每个写入只能发生一个日志更新,无论是否被检测到重复。
如果启用了压缩,对压缩数据进行读写将需要 CPU 线程进行更多处理。
包含所有零字节( 零块)的块会特别考虑,因为它们经常发生。特殊条目用于表示块映射中的此类数据,零块不会写入或从存储设备读取。因此,写入或读取全零块的测试可能会产生误导的结果。也是如此,到更短的测试中,写入零块或未初始化的块(自 VDO 设备创建后永远不会写入)的测试是一样的,因为零或未初始化的块不需要物理线程执行的参考计数。
确认 I/O 操作的唯一任务是不受正在完成的工作类型的影响或正在操作的数据类型,因为每个 I/O 操作都会发出一个回调。
30.6.3.1.2. CPU 关联性和 NUMA
访问 NUMA 节点边界的内存所需的时间比访问本地节点上的内存要长。当 Intel 处理器在节点上的内核间共享最后一个级别的缓存时,节点之间的缓存竞争比节点中缓存争用要大得多。
top 等工具无法区分工作和停滞周期的 CPU 周期。这些工具将缓存争用解释,并将内存访问速度减速为实际工作。因此,在节点间移动线程可能会显示以减少线程的明显 CPU 使用率,同时增加它每秒执行的操作数量。
虽然很多 VDO 内核线程维护只能被一个线程访问的数据结构,但它们会经常交换有关 I/O 请求本身的消息。如果 VDO 线程在多个节点上运行,或者由调度程序将线程从一个节点重新分配给另一个节点,则竞争可能很高。如果可以在与 VDO 线程相同的节点上运行其他与 VDO 相关的工作(如 I/O 提交到 VDO 或中断处理),则竞争可能会进一步减少。如果一个节点没有足够的周期来运行所有与 VDO 相关的工作,则当选择线程移到其他节点时,应该考虑内存争用。
如果实际情况,请使用 taskset 工具在一个节点上收集 VDO 线程。如果也可以在同一节点上运行其他与 VDO 相关的工作,这可能会进一步减少竞争。在这种情况下,如果一个节点缺少 CPU 电源来满足处理需求,那么在选择线程以移动到其他节点时需要考虑内存争用。例如,如果存储设备的驱动程序具有大量用于维护的数据结构,则可能有助于将设备的中断处理和 VDO 的 I/O 提交(调用设备的驱动程序代码)移到另一节点。使 I/O 确认(线程)和更高级别的 I/O 提交线程(用户模式线程执行直接 I/O,或者内核的页面缓存 清除 线程)对也很好。
30.6.3.1.3. 频率节流
如果电源消耗不是问题,请将字符串 性能 写入 /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 文件(如果它们存在)可能会生成更好的结果。如果这些 sysfs 节点不存在,Linux 或系统的 BIOS 可能会提供其他选项来配置 CPU 频率管理。
性能测量会进一步复杂,CPU 根据工作负载动态变化其频率,因为完成特定工作所需的时间可能会因其他工作而不同,即使没有任务切换或缓存争用,即使没有任务切换或缓存争用,也会不同。

30.6.3.2. Caching

30.6.3.2.1. Block Map Cache
VDO 缓存多个块映射页面以提高效率。缓存大小默认为 128 MB,但可以使用 vdo 命令的 --blockMapCacheSize=megabytes 选项增加它。使用较大的缓存可能会给随机访问工作负载带来显著的好处。
30.6.3.2.2. 读取缓存
第二个缓存可用于缓存从存储系统读取的数据块,以验证 VDO 的 deduplication 建议。如果在短时间内看到类似的数据块,则可以减少所需的 I/O 操作数量。
读取缓存也保存包含压缩用户数据的存储块。如果在短时间内写入多个可压缩块,则它们的压缩版本可以位于同一存储系统块中。同样,如果它们在短时间内读取,缓存可能会避免需要从存储系统进行额外的读取。
vdo 命令的 --readCache={enabled | disabled} 选项控制是否使用读缓存。如果启用,缓存的最小大小为 8 MB,但可使用 --readCacheSize=megabytes 选项增加。管理读取缓存会导致开销小,因此如果存储系统足够快,则它可能无法提高性能。默认情况下禁用读取缓存。

30.6.3.3. 存储系统 I/O

30.6.3.3.1. bio 线程
对于 RAID 配置中的通用硬盘驱动器,一个或多个 bio 线程可能足以提交 I/O 操作。如果存储设备驱动程序需要其 I/O 提交线程才能显著提高工作(更新驱动程序数据结构或与设备通信),则一个或多个线程通常处于空闲状态,因此可能会增加 bio 线程数以编译。但是,根据驱动程序的实现,线程数过高可能会导致缓存或变换锁争用。如果设备访问时间不是在所有 NUMA 节点之间统一,则在节点"关闭"到存储设备控制器上运行 bio 线程会很有帮助。
30.6.3.3.2. IRQ 处理
如果设备驱动程序在其中断处理程序中无法正常工作,且没有使用线程 IRQ 处理程序,则可能会阻止调度程序提供最佳性能。为硬件中断提供服务的 CPU 时间可能类似于普通的 VDO (或其他)内核线程执行。例如,如果硬件 IRQ 处理内核周期需要 30%,则同一内核的忙碌的内核线程只能使用剩余的 70%。但是,如果为该线程排队的工作需要 80% 的核心周期,线程永远不会捕获,调度程序可能只让线程在该内核上运行,而不是将线程切换到更忙的核心。
在大量 VDO 工作负载中使用这样的设备驱动程序可能需要大量循环才能服务硬件中断( 顶部显示 标头中的 %hi 指示符)。在这种情况下,可能需要为某些内核分配 IRQ 处理,并调整 VDO 内核线程的 CPU 关联性,使其不在这些内核上运行。

30.6.3.4. 最大 Discard Sectors

可以使用 /sys/kvdo/max_discard_sectors 根据系统使用情况调整 DISCARD (TRIM)操作的最大允许大小。默认值为 8 个扇区(即 4 KB 块)。可以指定较大的大小,但 VDO 仍然会在循环中处理它们,但一次一个块的一个块,确保在启动下一个块前写入一个丢弃的块的元数据更新,并刷新到磁盘。
当使用 VDO 卷作为本地文件系统时,红帽测试发现小的丢弃大小最适合工作,因为 Linux 内核中的通用块设备代码会将大型丢弃请求分成多个较小的请求,并并行提交它们。如果设备上有低 I/O 活动,VDO 可以同时处理许多较小的请求,且比一个大型请求快得多。
如果要将 VDO 设备用作 SCSI 目标,则启动器和目标软件会引入需要考虑的额外因素。如果目标 SCSI 软件是 SCST,它会读取最大丢弃大小并将其转发到启动器。(红帽没有尝试调整 VDO 配置与 LIO SCSI 目标代码。)
因为 Linux SCSI 启动器代码一次只允许一个丢弃操作,因此丢弃超过最大大小的请求会分为多个较小的丢弃并发送,一次发送到目标系统(和 VDO)。因此,除了 VDO 处理串行中的多个小丢弃操作外,两个系统之间的往返通信时间会增加延迟。
设置较大的最大丢弃大小可减少这个通信开销,虽然大型请求将在整个 VDO 传递给 VDO 并一次处理一个 4 KB 块。虽然没有每个块的通信延迟,但较大的块的额外处理时间可能会导致 SCSI 启动器软件超时。
对于 SCSI 目标使用情况,红帽建议将最大丢弃大小配置为中等,同时仍然在启动器的超时设置中保持典型的丢弃时间良好。例如,每几秒钟的额外往返成本(例如,如果 30 秒或 60 秒超时)不应显著影响性能和 SCSI 启动器。

30.6.4. 识别 Bottlenecks

有几个影响 VDO 性能的关键因素,以及很多工具来识别影响最大影响的工具。
topps 等实用程序中所示,线程或 CPU 使用率高于 70%,通常意味着过多的工作被集中在一个线程或一个 CPU 上。然而,在某些情况下,可能意味着 VDO 线程被调度到 CPU 上运行,但没有实际发生任何工作;这种情况可能会在硬件中断处理器处理、内核或 NUMA 节点之间内存争用,或者对 spin 锁定争用。
当使用 top 工具检查系统性能时,红帽建议运行 top -H 来分别显示所有进程线程,然后输入 1 f j 键,后跟 Enter/Return 键;然后,顶部 命令显示单个 CPU 内核的负载,并确定每个进程或线程最后一次运行的 CPU。这些信息可以提供以下 insights:
  • 如果内核没有较低的 %id (空闲)和 %wa (等待I/O)值,则它会一直保持在某种程度上工作。
  • 如果内核的 %hi 值非常低,则核心正在进行正常处理,这是由内核调度程序进行负载均衡的。向该集合添加更多内核可能会减少负载,只要它不引入 NUMA 争用。
  • 如果内核的 %hi 超过百分比,且只为那个内核分配一个线程,%id%wa 为零,则核心将被过度使用,且调度程序不会解决这种情况。在这种情况下,应重新分配内核线程或设备中断处理,使其保存在单独的内核中。
perf 工具可以检查许多 CPU 的性能计数器。红帽建议使用 perf top 子命令作为检查线程或处理器正在执行的工作的起点。例如,bioQ 线程会花费很多周期试图获取 spin 锁定,则 VDO 下设备驱动程序可能会太多竞争,并减少 bioQ 线程的 数量可能缓解这种情况。使用高 CPU (获取 spin 锁定或其他)也可以表示 NUMA 节点之间争用(例如,bio Q 线程和设备中断处理器在不同节点上运行。如果处理器支持它们,则诸如 stalled-cycles-backendcache-missesnode-load-misses 等计数器可能值得关注。
sar 实用程序可以提供关于多个系统统计的定期报告。sar -d 1 命令报告块设备利用率级别(它们至少有一个 I/O 操作百分比)和队列长度(每秒等待的 I/O 请求数)一次。但是,并非所有块设备驱动程序都可以报告此类信息,因此 sar 有用的性可能会依赖于正在使用的设备驱动程序。