BCLinux 7 性能调优手册


  • BCLinux Developers

    BCLinux 7 性能调优手册


    1 CPU

    1.1 配置内核滴答时间

    默认情况下,BCLinux 7 使用无时钟内核,它不会中断空闲 CPU 来减少用电量,并允许较新的处理器利用深睡眠状态。

    BCLinux 7 同样提供一种动态的无时钟设置(默认禁用),这对于延迟敏感型的工作负载来说是很有帮助的,例如高性能计算或实时计算。

    要启用特定 CPU 上的动态无时钟特性,在内核命令行中用 nohz_full 参数进行设定。在 16 核的系统中,设定 nohz_full = 1-15 可以在 1 到 15 核上启用动态无时钟功能,并将所有的计时移动至唯一未设定的核上(0 号核)。这种特性可以在启动时临时启用,也可以在 /etc/default/grub 文件中永久启用,然后运行 grub2-mkconfig -o /boot/grub2/grub.cfg 指令来保存配置。

    启用动态无时钟特性需要一些手动管理。

    • 当系统启动时,必须手动将 rcu 线程移动至对延迟不敏感的核上,下面情况下为 0 号核。
      # for i in `pgrep rcu[^c]` ; do taskset -pc 0 $i ; done
    • 在内核命令行上使用 isolcpus 参数来将特定的 CPU 与用户空间任务隔离开。
    • 可以选择性地为辅助性 CPU 设置内核回写式 bdi-flush 线程的 CPU 关联:
      echo 1 > /sys/bus/workqueue/devices/writeback/cpumask

    验证动态无时钟配置是否正常运行,执行以下命令,其中 stress 是在 CPU 中运行 1 秒的程序。

    # perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
    

    可用一个脚本替代 stress,该脚本运行类似 while :; do d = 1; done 的程序。

    默认的内核计时器配置在繁忙 CPU 中显示 1000 次滴答:

    # perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
    1000 irq_vectors:local_timer_entry
    

    内核动态无时钟配置下,用户只会看到一次滴答:

    # perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
    1 irq_vectors:local_timer_entry
    

    1.2 设置硬件性能策略

    x86_energy_perf_policy 工具允许管理员定义性能与能效的相对重要性。当处理器在性能与能效间权衡选择时,此信息可用作参考。

    默认情况下,x86_energy_perf_policy 工具适用于所有处在 performance 模式下的处理器。它需要处理器支持该功能且必须在 root 权限下运行。

    x86_energy_perf_policy 由 kernel-tools 数据包提供。如何使用 x86_energy_perf_policy,详情请参见手册页:

    $ man x86_energy_perf_policy
    

    1.3 使用 taskset 设置处理器关联

    Taskset 工具由 util-linux 数据包提供。Taskset 允许管理员解析和设置进程的处理器关联,或通过特定的处理器关联来启动一个进程。

    taskset 不能保证本地内存分配。若需要本地内存分配,推荐使用 numactl 来替代 taskset 。

    1.4 使用 numactl 管理 NUMA 关联

    管理员可以通过特定的调度或内存分配策略来使用 numactl 运行进程。Numactl 也可以为共享内存片段或文件设置永久性策略,并设置进程的处理器关联和内存关联。

    在 NUMA 拓扑系统中,处理器访问内存的速度会由于处理器和存储体之间距离的增加而减慢。因此,要对性能敏感的应用程序进行配置,以便它们能够从最近的存储体分配内存。最好是使用在同一 NUMA 节点的内存和 CPU。

    对性能敏感的多线程应用程序经配置后在特定的 NUMA 节点上运行会比在其他处理器上运行性能更好。但这是否适合则取决于用户系统及应用程序的需求。如果多个应用程序线程访问同一缓存数据,那么对那些线程进行配置,使其在同一处理器上运行是合适的。但是,如果在同一处理器上运行的多线程访问及缓存的是不同数据,那么每个线程可能会收回之前线程访问的缓存数据。这就意味着每个线程会“ 缺失” 缓存,会浪费运行时间来从磁盘中获取数据并在缓存中替代它。

    Numactl 提供大量的选项来管理处理器及内存关联。numactl 数据包包括 libnuma 库。这个库提供了一个内核支持的 NUMA 策略的简单编程接口,比起 numactl 应用程序,它可以用来进行更细致的调节。

    1.5 使用 numad 进行自动化 NUMA 关联管理

    numad 是一种自动化的 NUMA 关联管理后台程序。它对系统中的 NUMA 拓扑及资源用量进行监控,以便动态地改善 NUMA 资源配置及管理。

    numad 也提供预放置建议服务,这一服务可以通过不同的作业管理系统来查询,并为处理器 CPU 的初始绑定及内存资源提供帮助。无论 numad 是以可执行程序运行还是以服务的方式运行,预放置建议都可用。

    1.6 调节调度策略

    Linux 调度器实现了大量的调度策略,用以决定线程运行的位置和时长。调度策略主要有两类:普通策略和实时策略。普通策略用于普通优先级任务,实时策略用于具有时效性且必须无中断完成的任务。

    实时线程不受时间片的控制,这意味着它们将一直运行直至它们阻塞、退出、主动让步或是被更高优先权的线程预抢占。最低优先权的实时线程会先于其他普通策略线程进行调度。

    1.6.1 调度原则

    SCHED_FIFO 静态优先级调度

    SCHED_FIFO (也叫做静态优先级调度)是一项实时策略,定义了每个线程的固定优先级。这一策略可以改进事件响应的时间并减少延迟,建议用于运行时间较短且具有时效性的任务。

    在使用 SCHED_FIFO 时,调度器会按优先级顺序扫描所有的 SCHED_FIFO 线程,并对准备运行的最高优先级线程进行调度。一个 SCHED_FIFO 线程的优先级级别可以是 1 至 99 之间的任何整数,99 是最高优先级。建议一开始使用较小的数字,在确定了延迟问题后再增加优先级。

    由于实时线程不受时间间隔的控制,不推荐设置 99 优先级。这会使你的进程拥有跟迁移线程或看门狗线程相同的优先级,如果进程进入一个循环且进程被阻塞,迁移线程或看门狗线程将无法运行。这种情况下,单处理器系统最终会暂停。

    管理员可以限制 SCHED_FIFO 的带宽以防止实时应用程序独占处理器。

    /proc/sys/kernel/sched_rt_period_us  
    	该参数以微秒为单位来定义时间,是百分之百的处理器带宽。默认值为 1000000 μs, 或1秒。  
    
    /proc/sys/kernel/sched_rt_runtime_us  
    	该参数以微秒为单位来定义时间,用来运行实时线程。默认值为 950000 μs, 或0.95秒。
    
    SCHED_RR 轮循优先级调度

    SCHED_RR 是 SCHED_FIFO 的一个轮循变形。这一策略在多个线程需要运行在同一优先级时很有用。正如 SCHED_FIFO ,SCHED_RR 是一个实时策略,定义了每个线程的固定优先级。调度器会按优先级顺序扫描所有的 SCHED_RR 线程,并对准备运行的最高优先级线程进行调度。但是,和 SCHED_FIFO 不同,相同优先级的线程在一定的时间间隔内是以循环的方式进行调度的。

    用户可以使用 sched_rr_timeslice_ms 内核参数,以毫秒为单位设定这一时间间隔
    (/proc/sys/kernel/sched_rr_timeslice_ms) 。最小值为1毫秒。

    SCHED_OTHER 普通调度

    SCHED_OTHER 是 BCLinux 7 中默认的调度策略。这一策略使用 CFS (完全公平调度器)让处理器能够平等地访问使用此策略的线程。这一策略在有大量线程或数据吞吐量最为有用,因为它能够随着时间而更为有效地调度线程。

    在使用这一策略时,调度器会创建一个动态优先级列表,此列表一部分是基于每个进程线程的进程优先级。管理员可以改变一个进程的进程优先级,但是不能直接改变调度器的动态优先级列表。

    隔离 CPU

    用户可以使用 isolcpus 启动参数隔离一个或多个 CPU,以防止调度器在此 CPU 上调度任何用户空间的线程。

    一旦 CPU 被隔离,用户须手动分配进程至被隔离的 CPU,或使用 CPU 关联系统调用或 numactl 命令。

    将系统中第三和第六至第八 CPU 隔离,添加如下至内核命令行:

    isolcpus=2,5-7
    

    用户也可使用 Tuna 工具来隔离CPU。Tuna 可以随时隔离 CPU,不仅仅局限于启动时。但这种隔离方法与isolcpus 参数略有不同,并且目前尚未实现与 isolcpus 相同的性能提升。

    1.7 设置中断关联

    中断请求有一个关联属性smp_affinity, 它能指定处理中断请求的处理器。若要提高应用程序的性能,就将中断关联和进程关联分配至同一处理器。这可以使特定的中断和应用程序线程共享高速缓存。

    特定中断请求的中断关联值存储在相关的 /proc/irq/irq_number/smp_affinity 文件下。smp_affinity 是存储为十六进制的位掩码来代表系统中所有的处理器。默认值为 f,这意味着一个中断请求可以在系统中任何处理器上处理。如果将这个值设为 1 则意味着只有 0 位处理器可以处理这一中断。

    在超过 32 个处理器的系统中,用户须将 smp_affinity 的值限定为分散的 32 位组。例如,如果一开始只想使用 64 位处理器系统中的 32 位处理器来处理一个中断请求,可以运行:

    # echo 0xffffffff,00000000 > /proc/irq/IRQ_NUMBER/smp_affinity
    

    此外,如果 BIOS 输出 NUMA 拓扑,irqbalance 服务可以使用此信息来处理节点上的中断请求,对请求服务的硬件来说此节点是本地节点。

    如果系统支持中断引导(interrupt steering),修改一个中断请求的 smp_affinity 意味着处理器处理一个中断请求的决策就是硬件级别的,它不会受内核的干扰。

    1.8 使用 Tuna 配置 CPU、线程和中断关联

    Tuna 能够控制 CPU、线程及中断关联,并能通过不同方式控制各类实体。

    要从一个或多个特定的 CPU 中移除所有线程,请运行如下命令,使用想要隔离的 CPU 数量来替换 CPUs。

    # tuna --cpus CPUs --isolate
    

    要在可运行特定线程的 CPU 列表中加入一个 CPU,请运行如下命令,使用想要加入的 CPU 数量来替换
    CPUs。

    # tuna --cpus CPUs --include
    

    要将一个中断请求移动至特定的 CPU,请运行如下命令,用 CPU 数量替换 CPU,用想要移动且使用逗号分隔的中断请求列表替换 IRQs。

    # tuna --irqs IRQs --cpus CPU --move
    

    此外,用户可以使用如下命令来找到所有 sfc1* 模式的中断请求。

    # tuna -q sfc1* -c7 -m -x
    

    要改变一个线程的策略和优先级,请运行如下命令,使用想要改变的线程替换 thread,使用需要的线程调度策略名称替换 policy,用从 0(最低优先级)至 99(最高优先级)间的一个整数替换 level。

    # tuna --threads thread --priority policy:level
    

    2 内存

    内存使用量往往是通过设置一个或多个内核的参数值来进行配置的。这些参数可以通过修改 /proc 文件系统下的文件内容来暂时设置,或是通过设 sysctl 工具来进行永久设置,此工具由 procps-ng 数据包提供。

    例如,要将 overcommit_memory 参数暂时设置为 1,请运行以下指令:

    # echo 1 > /proc/sys/vm/overcommit_memory
    

    要永久设置这个值,请运行以下指令:

    # sysctl vm.overcommit_memory=1
    

    暂时设置一个参数可用于观察此参数对系统的影响。用户可以在确定了参数值有预期的效果之后再将其设置为永久值。

    2.1 配置大页面

    大页面依赖于连续的内存区域,因此最好在启动时,也就是在内存变为片段前就定义好大页面。为此,请添加以下参数至内核启动命令行:

    hugepages
    	启动时在内核中定义 2MB 大页面的数量。默认值为 0。只有在系统拥有足够的物理连续空闲页面时才能进行分配(或是收回)大页面。此参数保留的页面不能用于其他目的。
    
    	此值可以在启动后通过修改 /proc/sys/vm/nr_hugepages 文件值来调节。
    
    	更多详情请参阅相关内核文档,默认安装于 /usr/share/doc/kernel-dockernel_version/Documentation/vm/hugetlbpage.txt 中。
    
    /proc/sys/vm/nr_overcommit_hugepages
    	定义系统所能创建和使用的最大数量的额外大页面。在此文件中写入任何非零的值,表示系统包含此数目的大页面,在大页面池耗尽后,这些大页面来自于内核的常规页面池。由于这些额外的大页面是未使用过的,因此它们会释放并返回至内核的常规页面池中。
    

    2.2 配置系统内存容量

    与内存相关的内核参数有助于提高用户系统的内存使用率。基于测试目的,可以通过改变 /proc 文件系统中相应的文件值来暂时设置这些参数。一旦决定了能提供最佳性能的值,就可以使用 sysctl 指令来进行永久设置。

    2.2.1 虚拟内存参数

    以下参数都在 /proc/sys/vm 内,除非另有标明。

    dirty_ratio
    	一个百分比值。当整个系统内存的这一百分比值被修改时,系统会通过运行 pdflush 将改动写入磁盘。默认值为 20 %。
    
    dirty_background_ratio
    	一个百分比值。当整个系统内存的这一百分比值被修改时,系统会在后台将改动写入磁盘。默认值为 10 %。
    
    overcommit_memory
    	定义接受或拒绝一个大内存请求的条件。
    
    	默认值为 0 。默认情况下,内核使用经验内存超量处理的方法,通过估算可用内存大小和失败的请求。但由于内存分配使用的是经验算法而不是精确算法,这一设置可能会导致内存超载。
    
    	当这一参数设置成 1 时,内核不执行内存超量。这增加了内存过载的可能性,但提高了内存密集型任务的性能。
    
    	当这一参数设置成 2 时,如果请求的内存等于或大于总的可用交换空间和 overcommit_ratio 中指定的物理 RAM 的百分比,则内核拒绝该请求。这减少了超量使用内存的风险,但仅在系统交换空间大于物理内存时推荐此设置。
    
    overcommit_ratio
    	当 overcommit_memory 设置为 2 时,设置超量的物理 RAM 的百分比。默认值为 50 。
    
    max_map_count
    	定义一个进程可以使用的最大内存映射区域数量。默认值(65530)适用于大部分情况。如果应用程序需要映射超过此数量的文件,可增加此值。
    
    min_free_kbytes
    	设置系统中空闲内存的最小数量。这是用来给每一个低内存区定义一个合适的值,每一个低内存区都按照其大小比例分配了保留的空闲页面。
    
    	极值会损坏用户的系统。可以将 min_free_kbytes 设置为一个极小的值以防止系统回收内存,回收内存会导致系统锁死,以及 OOM-killing 进程。但是,将 min_free_kbytes 设置过高 (例如,整个系统内存的 5–10% )会使系统立即进入一种内存不足的状态,导致系统花太多时间来回收内存。
    
    oom_adj
    	在系统内存不足,并且 panic_on_oom 参数设置成 0 的情况下,oom_killer 功能会终止进程,直至系统恢复,从最高的 oom_score 进程开始。
    
    	oom_adj 参数有助于确定一个进程的 oom_score。此参数以每一个进程标识符为单位进行设置。值为 -17 时会禁用进程的 oom_killer。其他有效值是从 -16 到 15。由一个调整过的进程而产生的进程会继承该进程的 oom_score。
    
    swappiness
    	一个从 0 到 100 的值可以控制系统换出的程度。高值优先考虑系统效率,并在进程不活跃时主动交换物理内存耗尽的进程。低值优先考虑响应度,并且尽可能久地避免交换物理内存耗尽的进程。默认值为 60 。
    

    2.2.2 文件系统参数

    以下参数都在 /proc/sys/fs 内,除非另有标明。

    aio-max-nr
    	定义在异步输入/输出环境中最大事件数量。默认值为 65536 。修改此值不会预分配或改变任何内核数据结构的大小。
    
    file-max
    	定义内核分配的最大的文件句柄数量。默认值与内核中的 files_stat.max_files 值相匹配,将此值设为最大值 NR_FILE(8192,在 BCLinux 中)或是以下结果:
    		(mempages * (PAGE_SIZE / 1024)) / 10
    	增加此值可以解决由于缺少可用的文件句柄而引起的问题。
    

    2.2.3 内核参数

    以下参数都在 /proc/sys/kernel 内,除非另有标明。

    msgmax
    	以字节为单位,定义信息队列中信息可能的最大值。该值不能超过队列的大小(msgmnb)。默认值为 65536 。
    
    msgmnb
    	以字节为单位,定义信息队列的最大值。默认值为 65536 。
    
    msgmni
    	定义信息队列标识符的最大数量(以及队列的最大数量)。在 64 位架构的系统中,默认值为 1985。
    
    shmall
    	定义共享内存的总量,这些内存是系统可以同时使用的。
    
    shmmax
    	定义内核允许的单个共享内存片段的最大值。
    
    shmmni
    	定义系统范围内最大的共享内存片段数量。在所有系统中的默认值为 4096 。
    
    threads-max
    	定义系统范围内内核能同时使用的最大线程量。默认值与内核参数 max_threads 相同,或为以下结果:
    		mempages / (8 * THREAD_SIZE / PAGESIZE )
    	最小值为 20 。
    

    3 存储和文件系统

    3.1 注意事项

    存储和文件系统性能的合理设置在很大程度上取决于存储目的。 I/O 和文件系统性能会受到下列因素的影响:

    数据写入或读取模式
    数据排列与底层几何分布
    块大小
    文件系统大小
    日记大小和位置
    记录访问次数
    数据可靠性
    预取数据
    预分配磁盘空间
    文件碎片
    资源争用  
    

    3.1.1 文件系统的一般调整注意事项

    格式时间注意事项

    在设备格式化后,文件系统配置的部分不能改变。以下包含格式化存储设备的可用选项。

    大小
    	按照工作负载创建合理大小的文件系统。较小的文件系统的备份次数也较少,且文件系统检查所需时间和内存也更少。然而,如果您的文件系统太小,性能将因大量碎片而降低。
    
    块大小
    	块是文件系统中工作的单位。块大小决定单个块能存储多少数据,因而决定能够同时读写的数据最小量。
    
    	默认块大小适用于大部分用例。然而,如果块大小(或者多个块大小)和通常同时读写的数据数量一样大,或者略大时,文件系统将执行得更好、存储数据更加有效率。小文件仍将使用一个完整的块。文件可以分布在多个块中,但这会造成额外的运行时间开销。另外,一些文件系统受限于一定数量的块,转而限制文件系统最大尺寸。
    
    	使用 mkfs 指令格式化设备时,块大小作为文件系统选项的一部分而被指定。指定块大小的参数随文件系统变化,文件系统的细节,请参见 mkfs 手册页。例如,查看格式化 XFS 文件系统时可用的选项,执行下列命令:
    		$ man mkfs.xfs
    
    几何分布
    	文件系统几何分布与文件系统中数据的分布相关。如果系统使用带状存储器,例如 RAID,可在格式化设备时,通过重新排列数据和底层存储几何分布的元数据提高性能。
    
    	几何分布在使用特定文件系统格式化设备时会被自动设置。如果设备没有导出这些推荐几何分布,或您想要变更推荐设置,那么您在使用 mkfs 格式化设备时,需要手动指定几何分布。
    
    	指定文件系统几何分布的参数随文件系统而变化;文件系统细节请参见 mkfs 手册页。例如,查看格式化 ext4 系统时可用的选项,执行下列命令:
    		$ man mkfs.ext4
    
    外部日记
    	日志文件系统会在执行写操作之前,将写操作期间发生的变化记录到日志文件中。这会降低系统发生故障、电源故障时日志的存储设备损坏的可能性,并加速恢复过程。
    
    	元数据密集工作负载涉及日志的频繁更新。大型日志使用更多内存,但会减少写操作的频繁性。此外,可通过将设备日志置于和主要存储一样快或者更快的专用存储上,提高带有元数据密集工作负载的设备的寻道时间。
    
    	外部日志必须在格式化时便创建,并在挂载期间指定日志设备。
    
    挂载时间注意事项

    以下包含适用于大部分文件系统的调整选项,且可在挂载设备时指定。

    Barrier(屏障)
    	文件系统 barrier 确保文件系统元数据正确写入到永久存储并排序,使用 fsync 传输的数据在断电下得以保存。以前 BCLinux 版本中,启用文件系统 barrier 会明显降低依赖 fsync 的应用程序的运行速度,或者创建和删除很多小文件。
    
    	BCLinux 7 中,文件系统 barrier 性能得到改善,可以使文件系统 barrier 的性能影响变得极小(小于3%)。
    
    访问时间
    	每次读取文件,它的元数据随访问时间(atime)更新。这涉及额外的写入 I/O。在大多数情况下,这样的开销是最小的,因为在默认设置下,BCLinux 7 只有在上次访问时间早于上次修改时间(mtime) 或者状态变化(ctime)才会更新 atime 字段。
    
    	然而,如果更新元数据耗时且对访问时间没有要求,您可以使用 noatime 挂载选项挂载文件系统。读取文件时会禁用元数据的更新。它也会启用 nodiratime 行为,读取目录时,该行为禁用元数据的更新。
    
    预读
    	预读行为通过预取可能立即需要的数据,并且将其加载到比磁盘更快的页面缓存中加速文件访问。预读值越高,系统预取数据越早。
    
    	BCLinux 根据对于文件系统的检测,尝试设置一个合适的预读值。然而,检测不可能总是准确的。例如,如果存储数组将自己作为单一 LUN 展示给系统,系统会检测单一 LUN,但不会为整组设备设置合适的预读值。涉及大量顺序 I/O 的工作负载常常受益于高预读值。BCLinux 7 提高了预读值,但这些调整对于所有工作负载而言并不总是足够的。
    
    	定义预读行为的参数随着文件系统而变化;请参见手册页。
    	$ man mount
    
    维护

    定期丢弃文件系统不用的块是对于固态硬盘和精简配置存储的建议做法。有两种丢弃不使用的块的做法:
    batch discard(批量丢弃)和 online discard(网络丢弃)。

    batch discard(批量丢弃)
    	这种丢弃方式是 fstrim 指令的一部分。它丢弃文件系统中与管理员指定的之外的所有不使用的块。
    
    	BCLinux 7 支持 XFS 和 ext4 格式化设备上的 batch discard,这些设备支持实际丢弃操作(/sys/block/devname/queue/discard_max_bytes 值不为 0 的 HDD 设备,和 /sys/block/sda/queue/discard_granularity 不为 0 的 SSD 设备)。
    
    onlinediscard(网络丢弃)
    	这种方式的丢弃操作在挂载时间使用 discard 选项配置,实时运行不受用户干扰。然而,online discard 只丢弃从使用转换到空闲的块。BCLinux 7 支持 XFS 和 ext4 格式化设备上的 online discard。
    
    	推荐 batch discard,除非要求用 online discard 维持性能,或 batch discard 不适合用于系统工作负载时。
    
    预分配
    	预分配将硬盘空间标记为已经将磁盘空间分配给一个文件,而未将数据写入该空间。这可用于限制数据碎片和较差的读取性能。BCLinux 7 支持挂载时 XFS、ext4 和 GFS2 设备预分配空间。对您文件系统的合适参数,请参见 mount 手册页。应用程序也可通过使用fallocate(2) glibc 调用使用预分配。
    

    3.2 配置

    3.2.1 为存储性能调整配置文件

    Tuned 和 tuned-adm 提供了一些旨在为特定用例提高性能的配置文件。下列配置文件对于提高存储性能尤其有用。

    • 延迟-性能
    • 吞吐量-性能(默认)

    如需配置系统中的配置文件,请运行以下命令,用您想用的配置文件名称替代 name。

    $ tuned-adm profile name
    

    tuned-adm recommend 命令是系统推荐合适的配置文件。在安装时它也会为系统设置默认配置文件,因此可用于返回默认配置文件。

    3.2.2 设置默认 I/O 调度器

    如果设备的挂载选项没有指定调度器,可使用默认 I/O 调度器。

    如需设置默认 I/O 调度器,在重启时通过向内核命令行附加 elevator 参数来指定欲使用的调度器,或通过编辑 /etc/grub2.conf 文件。

    elevator=scheduler_name
    

    3.2.3 为设备配置 I/O 调度器

    如需设置特定存储设备的调度器或调度器优先顺序,编辑 /sys/block/devname/queue/scheduler
    文件,devname 为你想配置的设备名称。

    # echo cfq > /sys/block/hda/queue/scheduler
    

    3.2.4 调整最后期限调度器

    使用 deadline 时,排队的 I/O 请求将分为读批处理或者写批处理,然后按照 LBA 递增的执行顺序调度。默认设置下,读批处理比写批处理优先处理,这是因为在读 I/O 上应用程序易被阻止。在批处理被处理后,deadline 调度器会检查写操作因等待处理器而处于“ 饥饿” 状态的时间,并合理调度下一个读或者写批处理。

    下列参数影响 deadline 调度器行为:

    fifo_batch
    	单个批处理中读操作或写操作发出的数量。默认值为 16 。值越高,吞吐量也会更多,但也会增加延迟。
    
    front_merges
    	如果您的工作负载从不产生前端合并,可设置为 0 。然而,除非您已经测试了该检查的开销,推荐默认值 1。
    
    read_expire
    	应为服务调度读请求的期限时间,单位毫秒。默认值为 500(0.5秒)。
    
    write_expire
    	应为服务调度写请求的期限时间,单位毫秒。默认值为 5000(5秒)。
    
    writes_starved
    	先于写批处理而处理的读批处理数量。该值越高,给读批处理的优先权就更多。
    

    3.2.5 调整 cfq 调度器

    使用 cfq 时,进程被分为三类:实时、尽其所能和空闲。在尽其所能进程之前调度所有实时进程,空闲进程之前调度尽其所能进程。默认设置下,进程归类为尽其所能。可使用 ionice 命令手动调整进程类别。

    通过使用下列参数进一步调整 cfq 调度器的行为。这些参数在 /sys/block/devname/queue/iosched 目录下。

    back_seek_max
    	cfq 执行向后搜寻的最大距离。默认值是 16 KB。 向后搜寻通常会损害性能,因此不推荐大的值。
    
    back_seek_penalty
    	磁头在决定向前还是向后移动时向后搜寻的倍数。默认值为 2。如果磁头位置是1024 KB,并且在系统中有等距的请求(例如:1008 KB 和 1040 KB),back_seek_penalty 作用于向后搜寻距离,磁盘将向前移动。
    
    fifo_expire_async
    	异步(缓冲写入)请求可以持续无服务的时间长度,单位是毫秒。在这个时间过期之后,一个 “饥饿” 的异步请求移动至配送列表。默认值为 250 毫秒。
    
    fifo_expire_sync
    	同步(读取或者 O_DIRECT 写入)请求可以持续无服务的时间长度,单位是毫秒。在这个时期过期后,一个 “饥饿” 的同步请求被移动到配送列表。默认值为 125 毫秒。
    
    group_idle
    	默认设置下,参数设为 0 (禁用)。设置为 1(禁用)时,cfq 调度器在控制组中最后发出I/O的进程上保持空闲。当使用比例权重 I/O 控制组,或 slice_idle 设置为 0 (在快速存储上)这会很有帮助。
    
    group_isolation
    	默认设置下,该参数设置为 0 (禁用)。设置为 1(启用)时,它提供组之间更强的隔离,但是吞吐量会减少,这是因为公平性被用于随机和顺序工作负载。group_isolation 禁用时(设置为0),公平性只提供给顺序工作负载。更多信息,请参见安装文件 /usr/share/doc/kernel-doc-version/Documentation/cgroups/blkio-controller.txt。
    
    low_latency
    	默认设置下,设置参数为 1 (启用)。启用后,为设备上发出 I/O 的每个进程提供最大为 300 ms 的等待时间,这时 cfq 更注重公平性而非吞吐量。设置参数为 0 时(禁用),目标延迟被忽略,每个进程接受完整时间片。
    
    quantum
    	该参数定义 cfq 一次发送给一个设备的 I/O 请求的数量,实质上是限制队列深度。默认值为 8 个请求。使用的设备可能支持更大的队列深度,但增加该值也会导致延迟增加,尤其是大的顺序写工作负载。
    
    slice_async
    	该参数定义分配给每个发出异步 I/O 请求的进程的时间片(以毫秒计算)长度。默认值为 40 毫秒。
    
    slice_idle
    	该参数指定等待下一步请求时 cfq 空闲时间长度,单位是毫秒。默认值为 0 (队列无空闲或者service tree level)。默认值对于外部 raid 存储器上的吞吐量是理想的,但是由于增加了搜寻操作的整体数量,内部 non-RAID 存储器的吞吐量可能会降低。
    
    slice_sync
    	该参数定义分配给每个发出同步 I/O 请求的进程的时间片长度(以毫秒计算)。默认值为 100 ms。
    

    为快速存储调整 cfq

    不建议无法遭受大的搜寻 penalty(惩罚)的硬件使用 cfq 调度器,例如快速外部存储数列或者固态硬盘。如果您需要在此存储上使用 cfq,需要编辑下列配置文件:

    • 设置 /sys/block/devname/queue/ionice/slice_idle 为 0
    • 设置 /sys/block/devname/queue/ionice/quantum 为 64
    • 设置 /sys/block/devname/queue/ionice/group_idle 为 1

    3.2.6 调整 noop 调度器

    noop I/O 调度器主要对使用快速存储的 cpu 受限的系统有用。请求在块层合并,可以通过编辑
    /sys/block/sdX/queue/ 目录中的文件中块层参数修改 noop 行为。

    add_random
    	一些 I/O 事件会影响 /dev/random 的熵池。如果这些影响的负荷变得可观,该参数可设置为 0 。
    
    max_sectors_kb
    	指定 I/O 请求的最大尺寸(以千字节计算),默认值为 512 KB。该参数的最小值是由存储设备的逻辑块大小决定的。该参数的最大值是由 max_hw_sectors_kb 值决定的。
    
    	I/O 请求大于内部擦除块大小时,一些固态硬盘会表现不佳。在这种情况下,推荐将 max_hw_sectors_kb 减少至内部擦除块大小。
    
    nomerges
    	大多数工作负载受益于请求合并。然而,禁用合并对调试有帮助。可设置参数为 0 禁用合并。默认设置下为启用(设置为 1)。
    
    nr_requests
    	限定同一时间排队的读和写请求的最大数量。默认值为 128, 即在下一个请求读或者写操作的进程进入睡眠模式前可以有 128 个读请求和 128 个写请求排队。
    
    	对于延迟敏感的应用程序,可以降低该参数值并限制存储上的命令队列深度,这样回写 I/O 便无法填充写请求到设备队列。设备队列填满时,其他尝试执行 I/O 操作的进程会进入睡眠模式,直到有可用队列空间。随后请求会以 round-robin fashion(循环方式)分配,以防止一个进程占用整个队列。
    
    optimal_io_size
    	一些存储设备用此参数报告最佳 I/O 大小。如果报告该值,建议您尽可能将应用程序发出 I/O 与最佳 I/O 大小对齐,并是最佳 I/O 大小的倍数。
    
    read_ahead_kb
    	定义操作系统在顺序读取操作阶段将预先读取的字节数量,以便将可能马上需要的信息存储在页面缓存中。设备映射程序经常受益于高的 read_ahead_kb 值;推荐使用 128 KB。  
    
    rotational  
    	一些固态硬盘不能正确汇报其固态硬盘状态,并且会如传统旋转磁盘挂载。如果您的固态硬盘不能将它自动设置它为 0 ,那么请您手动设置,禁用调度器不必要的搜寻减少逻辑。
    
    rq_affinity
    	默认设置下,I/O 处理能在不同处理器上进行,而不限定在发出 I/O 请求的处理器上。将 rq_affinity 设置为 1 以禁用此能力,并只在发出 I/O 请求的处理器上执行处理。这能提高处理器数据缓存的有效性。
    

    3.2.7 为性能配置文件系统

    此章节包含 BCLinux 7 支持的每个文件系统的调整参数。参数分为用户格式化存储设备参数和挂载设备参数。

    如果文件碎片或者资源争用引起性能损失,性能通常可通过重新配置文件系统而提高性能。然而,在有些用例中,可能需要更改应用程序。

    3.2.7.1 调整 XFS

    XFS 默认格式化和挂载设置适用于大多数工作负载。建议只在更改特定配置会对您的工作负载有益时对它们进行更改。

    格式化选项

    目录块大小
    	目录块大小影响通过 I/O 操作可检索或修改的目录信息数量。目录块大小最小值即文件系统块大小(默认设置下为 4KB)。目录块大小最大值为 64 KB。
    
    	对于指定的目录块大小来说,大的目录比小的目录需要更多 I/O。因为和小目录块系统相比,大目录块系统的 I/O 操作会使用更多的处理能力。因此,根据工作负载,推荐使用尽可能小的目录和目录块大小。
    
    	推荐使用以下目录块大小。
    
    	目录块大小	最大项(大量读操作)	最大项(大量写操作)   
    	4KB	100000–200000	1000000–2000000  
    	16KB	100000–1000000	1000000–10000000  
    	64KB	>1000000	>10000000   
    
    	在不同大小文件系统中,目录块大小对读和写工作负载的影响的情况请参见 XFS 文件。
    	使用 mkfs.xfs -l 选项配置目录块大小。请参见 mkfs.xfs 手册页。
    
    分配组
    	分配组是独立的结构,用来索引空闲空间并在文件系统中分配 inodes。只要并发操作影响的是不同的分配组,每个分配组就能被独立修改,这样 XFS 可以并发执行分配和反分配操作。因此文件系统中执行的并发操作数量和分配组数量相等。然而,由于执行并发操作的能力受到能够执行并发操作的处理器数量的限制,建议分配组数量应多于或者等于系统中处理器的数量。
    
    	多个分配组无法同时修改单个目录。因此,推荐大量创建和移除文件的应用程序不要在单个目录中存储所有文件。
    
    	使用 mkfs.xfs -d 选项配置分配组,更多信息参见 mkfs.xfs 手册页。
    
    增长约束
    	如您在格式化之后(通过增加更多硬件或通过自动精简配置),需要增加文件系统的大小,由于分配组大小在完成格式化之后不能更改,请务必仔细考虑初始文件布局。
    
    	必须根据文件系统最终能力,而非根据初始能力调节分配组大小。占据所有使用空间的文件系统中分配组数量不应超过数百,除非分配组处于最大尺寸 (1TB)。因此,对大部分文件系统推荐最大增长,允许文件系统是初始大小的十倍。
    
    	增长 RAID 数组的文件系统时,务必考虑额外护理,由于设备大小必须与固定多个分配组大小对齐,以便新分配组表头在新增加的存储中正确对齐。由于几何在格式化之后不能被更改,因此新存储也必须与已有的存储几何一致,因此,在同一个块设备上,不能优化不同几何的存储。
    
    Inode 大小和内联属性
    	如果 inode 有足够可用空间,XFS 能直接将属性名称和值写入 inode。由于不需要额外的 I/O,这些内联属性能够被获取和修改,达到比获取单独的属性块更快的量级。
    
    	默认 inode 大小为 256 bytes。其中只有约 100 bytes 大小可用于属性存储,取决于 inode 上存储的数据范围指针数量。格式化文件系统时,增加 inode 大小能增加存储属性可用的空间数量。
    
    	属性名称和属性值两者都受到最大尺寸 254 bytes 的限制。如果名称或者值超过 254 bytes 长度,该属性会被推送到单独的属性快,而非存储在内联中。
    
    	使用 mkfs.xfs -i 选项配置 inode 参数,更多信息请参见 mkfs.xfs 手册页。
    
    RAID
    	如果使用软件 RAID,mkfs.xfs 会使用合适的带状单元和宽度自动配置底层的硬件。然而,如果使用硬件 RAID, 带状单元和宽度可能需要手动配置,这是因为不是所有硬件 RAID 设备输出此信息。使用 mkfs.xfs -d 选项配置带状单元和宽度。更多信息请参见 mkfs.xfs 手册页。
    
    日志大小
    	直到同步事件被触发,待定的更改在内存中累计,这个时候它们会被写入日志。日志大小决定同时处于进行中的修改数量。它也决定在内存中能够累计的最大更改数量,因此决定记录的数据写入磁盘的频率。与大日志相比,小日志促使数据更频繁地回写入磁盘。然而,大日志使用更多内存来记录待定的修改,因此有限定内存的系统将不会从大日志获益。
    
    	日志与底层带状单元对齐时,日志表现更佳;换言之,它们起止于带状单元边界。使用 mkfs.xfs -d 选项将日志对齐带状单元,更多信息请参见 mkfs.xfs 手册页。
    
    	使用下列 mkfs. xfs 选项配置日志大小,用日志大小替换 logsize :
    		# mkfs.xfs -l size=logsize
    	更多详细信息参见 mkfs.xfs 手册页:
    		$ man mkfs.xfs
    
    日志带状单元
    	日志写操作起止于带状边界时(与底层带状单元对齐),存储设备上使用 RAID 5 或 RAID 6 布局的日志写操作可能会表现更佳。mkfs.xfs 尝试自动设置合适的日志带状单元,但这取决于输出该信息的 RAID 设备。
    
    	如果您的工作负载过于频繁地触发同步事件,设置大日志带状单元会降低性能。这是因为小的写操作需要填充至日志带状单元,而这会增加延迟。如果您的工作负载受到日志写操作延迟的约束,推荐将日志带状单元设置为 1 个块,从而尽可能地触发非对齐日志写操作。
    
    	支持的最大日志带状单元为最大日志缓存的大小(256 KB)。因此底层存储器可能拥有更大的带状单元,且该带状单元能在日志中配置。在这种情况下,mkfs.xfs 会发出警告,并设置一个大小为32 KB 的日志带状单元。
    
    	使用以下选项之一配置日志带状单元,其中 N 是被用于带状单元的块的数量,size 是以 KB 为单位的带状单元的大小。
    		mkfs.xfs -l sunit=Nb
    		mkfs.xfs -l su=size
    	更多详细信息参见 mkfs.xfs 手册页:
    		$ man mkfs.xfs  
    

    挂载选项

    Inode 分配
    	强烈推荐文件系统大于 1TB。inode64 参数配置 XFS,从而在文件系统中分配 inode 和数据。这样能保证 inode 不会被大量分配到文件系统的起始位置,数据也不会被大量分配到文件系统的结束位置,从而提高大文件系统的性能表现。
    
    日志缓存和数量
    	日志缓存越大,将所有变更写入日志的 I/O 操作越少 。大日志缓存能提高有大量 I/O 密集型工作负载的系统性能,而该工作负载没有非易变的写缓存。
    
    	通过 logbsize 挂载选项配置日志缓存大小,并确定日志缓存中信息存储的最大数量。如果未设置日志带状单元,缓存写操作可小于最大值,因此不需要减少大量同步工作负载中的日志缓存大小。默认的日志缓存大小为 32 KB。最大值为 256 KB, 也支持 64 KB、128 KB 或以 2 的倍数为幂的介于 32 KB 和 256 KB 之间的日志带状单元。
    
    	日志缓存的数量是由 logbufs 挂载选项确定的。日志缓存的默认值为 8 (最大值),但能配置的日志缓存最小值为2。通常不需要减少日志缓存的数量,除非内存受限的系统不能为额外的日志缓存分配内存。减少日志缓存的数量会降低日志的性能,尤其在工作负载对 I/O 延迟敏感的时候。
    
    延迟变更日志
    	内存的变更写入日志前,XFS 的选项能聚合这些改变。delaylog 参数允许将频繁更改的元数据周期性地写入日志,而非每次改变都要记录到日志中。此选项会增加故障中操作丢失的潜在数量,也会增加用于跟踪元数据的内存大小。但是,它能通过按量级排序增加元数据的更改速度和可扩展性,为确保数据和元数据写入硬盘而使用 fsync、fdatasync 或sync 时,此选项不能减少数据或元数据的完整性。
    
    3.2.7.2 调整 ext4

    本章节涵盖格式化和挂载时 ext4 文件系统可用的一些调整参数。

    格式化选项

    inode 表初始化
    	在很大的文件系统上初始化文件系统中所有 inode 会耗时很久。默认设置下会推迟初始化过程(启用延迟 inode 表初始化)。但是,如果您的系统没有 ext4 驱动,默认设置下会禁用延迟 inode 表初始化。可通过设置 lazy_itable_init 为 1 启用。那么内核进程会在挂载后继续初始化文件系统。
    

    本章节仅描述了在格式化时可用的一些选项。更多格式化参数,参见mkfs.ext4 手册页:

    $ man mkfs.ext4
    

    挂载选项

    inode表初始化率
    	启用延迟 inode 表初始化时,您可通过指定 init_itable 参数值控制初始化发生的速率。执行后台初始化的时间约等于 1 除以该参数值。默认值为 10 。
    
    自动文件同步
    	对现有文件重命名、截断或重写后,一些应用程序无法正确执行 fsync。默认设置下,执行这些操作之后,ext4 会自动同步文件。但这样会比较耗时。
    
    	如果不需要此级别的同步,您可在挂载时通过指定 noauto_da_alloc 选项禁用该行为。如果 noauto_da_alloc 已设置,应用程序必须明确使用 fsync 以确保数据的持久化。
    
    日志 I/O 优先级
    	默认设置下日志 I/O 优先级为 3,该值比常规 I/O 的优先级略高。您可在挂载时使用 journal_ioprio 参数控制日志 I/O 的优先级。journal_ioprio 的有效值范围为从 0 到 7,其中 0 表示具有最高优先级的 I/O。
    
    3.2.7.3 调整 GFS2

    本章节涵盖 GFS2 文件系统在格式化和挂载时可用的调整参数。

    目录间距
    	GFS2 挂载点下的顶层目录中创建的所有目录都是自动间隔,以减少目录中的碎片并提高写速度。为了像顶层目录一样间隔其他目录,用 T 属性标注该目录,如下所示,用您想间隔该目录的路径替代 dirname。
    		# chattr +T dirname
    	chattr 作为 e2fsprogs 软件包中的一部分提供给用户。
    
    减少争用
    	GFS2 使用全域锁机制,该机制需要簇中节点之间的通信。多节点之间的文件和目录争用会降低性能。通过最小化多节点间共享的文件系统区域,您可将缓存失效的风险最小化。
    

    4 网络

    网络子系统由很多不同的部分构成,BCLinux 7 的网络旨在为大多数工作负载提供最佳性能,并且自动优化其性能。因此,不需要时常手动调节网络性能。本章探讨了可以对网络系统做的进一步优化。

    网络性能问题有时是硬件故障或基础结构层故障造成的。解决这些问题超出了本文的范畴。

    4.1 注意事项

    要想调优,用户需要对 BCLinux 包的接收有充分的认识。本章节解释了如何接收和处理网络数据包,以及潜在瓶颈会出现的地方。

    发送到 BCLinux 系统的数据包是由 NIC(网络接口卡)接收的,数据包置于硬件缓冲区或是循环缓冲区中。之后 NIC 会发送一个硬件中断请求,一个软件中断操作会被调用处理该中断请求。

    作为软件中断操作的一部分,数据包会由缓冲区转移到网络堆栈。根据数据包及用户的网络配置,数据包之后会被转发、删除或转移到一个应用程序的 socket 接收队列,并将从网络堆栈中删除。这一过程会持续进行,直到 NIC 硬件缓冲区中没有数据包或一定数量的数据包(在 /proc/sys/net/core/dev_weight 中指定)被传输。

    4.1.1 调节前

    网络性能问题最常见的是由硬件故障或基础结构层故障造成的。建议在开始调节网络堆栈前核实硬件及基础结构层是否在按预期运行。

    4.1.2 数据包接收瓶颈

    虽然网络堆栈基本上是自我优化的,但是在网络堆栈处理过程中有很多导致瓶颈且降低性能的问题。

    NIC 硬件缓冲区或循环缓冲区
    	如果大量的数据包被弃置,硬件缓冲区就会成为瓶颈。
    
    硬件或软件中断队列
    	中断会增加延迟,争用处理器。
    
    应用程序的 socket 接收队列
    	应用程序接收队列的瓶颈是大量的数据包没有复制到请求应用程序中,或是 UDP 输入错误(InErrors)增加,此错误在 /proc/net/snmp 中。
    

    4.2 配置

    BCLinux 提供大量工具来协助管理员配置系统。本章概述了可用的工具并举例说明如何使用它们来解决在 BCLinux 7 中与网络相关的性能问题。

    但要记住的重要的一点是,网络性能问题有时是硬件故障或基础结构层故障造成的。建议在开始调节网络堆栈前先核实硬件及基础结构层在按预期运作。

    此外,比起重新配置网络子系统来说,改变应用程序配置更容易解决一些网络性能问题。通常,配置应用程序运行频繁的 posix 调用是个好办法,即使这意味着在应用程序空间整理数据,因为这使得数据存储更灵活且能按需要换入或换出内存。

    4.2.1 网络性能 Tuned-adm 配置文件

    tuned-adm 对很多特定用例提供了大量不同的配置文件以提高性能。以下配置文件有助于提高网络性能。

    • 延迟性能
    • 网络延迟
    • 网络吞吐量

    4.2.2 配置硬件缓冲区

    如果硬件缓冲区丢弃了大量的数据包,那么有很多可能的解决方法。

    减缓输入流量
    	筛选传入的流量,减少多播组数量或减少广播流量,以降低队列填充率。
    
    调整硬件缓冲队列
    	通过增加队列的大小以减少丢弃的数据包数量,使其不易溢出。用户可以使用 ethtool 指令来更改网络设备的 rx/tx 参数:
    	# ethtool --set-ring devname value
    
    改变队列的排出率
    	设备权重是指设备一次可以接收的数据包数量(单个调度处理器访问)。用户可以通过提高设备权重以增加队列的排出比率,这由 dev_weight 参数控制。此参数可以通过改变 /proc/sys/net/core/dev_weight 文件的内容来做临时更改,或使用 sysctl 进行永久更改,sysctl 由 procps-ng 数据包提供。
    

    改变队列排出率通常是缓解不良网络性能最简单的方法。但是,增加设备一次可以接收的数据包数量会消耗处理器额外的时间,在此期间不可调度其他进程,因此可能会导致其他性能问题。

    4.2.3 配置中断队列

    如果经过分析显示高延迟,系统可能更适合基于轮询的包接收,而不是基于中断的包接收。

    配置繁忙轮询

    繁忙轮询通过使 socket 层代码查询网络设备的接收队列并禁用网络中断,有助于减少网络接收路径中的延迟,这可以消除中断和上下文切换所造成的延误。但是,它会增加 CPU 的使用率。繁忙轮询可以防止 CPU 进入睡眠状态,睡眠状态会造成额外的功耗。

    繁忙轮询是默认禁用的。要在特定 socket 中启用繁忙轮询,请按以下指示:

    • 将 sysctl.net.core.busy_poll 设置为除 0 以外的值。这一参数控制的是 socket 轮询和选择等待设备队列中数据包的微秒数。推荐值为 50 。
    • 添加 SO_BUSY_POLL socket 选项至 socket。

    要全局启用繁忙轮询,须将 sysctl.net.core.busy_read 设置为除了 0 以外的值。这一参数控制了
    socket 读取设备队列中数据包而等待的微秒数,且设置了 SO_BUSY_POLL 选项的默认值。推荐在 socket 数量少时将值设置为 50,socket 数量多时将值设置为 100 。对于 socket 数量极大时(超过几百),请使用 epoll 。

    以下驱动程序均支持繁忙轮询。BCLinux 7 也支持这些驱动程序。

    • bnx2x
    • be2net
    • ixgbe
    • mlx4
    • myri10ge

    4.2.4 配置 socket 接收队列

    如果分析数据显示,数据包由于 socket 队列排出率太慢而被丢弃,有几种方法来解决由此产生的性能问题。

    减少传入流量的速度
    	减少队列填充速率可以通过筛选或丢弃进入队列前的数据包,或是减少设备权重。
    
    增加应用程序的 socket 队列深度
    	如果一个 socket 队列接收数量有限的涌入流量,增加 socket 的队列深度与涌入的流量大小相配,可防止数据包被丢弃。
    

    减少传入流量的速度

    筛选传入流量或降低网络接口卡的设备权重来减少传入的流量。

    设备权重是指设备一次可以接收的数据包数量(单个调度处理器访问)。用户可以通过提高设备权重以增加队列的排出比率,这由 dev_weight 参数控制。此参数可以通过改变 /proc/sys/net/core/dev_weight 文件的内容来做临时更改,或使用 sysctl 进行永久更改,sysctl 由 procps-ng 数据包提供。

    增加队列深度

    增加应用程序的 socket 队列深度往往是提高 socket 队列排出率最简单的方法,但不可能是一个长期的解决方法。

    要增加队列深度就要增加 socket 接收缓冲区的大小,可以做如下变化:

    增加 /proc/sys/net/core/rmem_default 值
    	这一参数控制 socket 使用的接收缓冲区的默认大小,这个值必须小于 /proc/sys/net/core/rmem_max 的值。
    
    使用 setsockopt 配置较大的 SO_RCVBUF 值
    	这一参数控制的是以字节为单位的 socket 接收缓冲区的最大值。使用 getsockopt 系统调用来确定当前缓冲区的值。此参数的更多信息,请见手册页:
    	$ man 7 socket
    

    4.2.5 配置 RSS

    RSS(接收端调整),也叫多队列接收,是把网络接受过程分布到一些基于硬件的接收队列,从而使网络流量可以由多个 CPU 进行处理。RSS 可以用来缓解接收中断进程中由于单个 CPU 过载而出现的瓶颈,并减少网络延迟。

    要确定您的网络接口卡是否支持 RSS,须查看多个中断请求队列是否在 /proc/interrupts 中有相关的接口。例如,如果用户对 p1p1 接口有兴趣:

    # egrep 'CPU|p1p1' /proc/interrupts
    	CPU0 CPU1 CPU2 CPU3 CPU4 CPU5
    89: 40187 0 0 0 0 0 IR-PCI-MSI-edge
    p1p1-0
    90: 0 790 0 0 0 0 IR-PCI-MSI-edge
    p1p1-1
    91: 0 0 959 0 0 0 IR-PCI-MSI-edge
    p1p1-2
    92: 0 0 0 3310 0 0 IR-PCI-MSI-edge
    p1p1-3
    93: 0 0 0 0 622 0 IR-PCI-MSI-edge
    p1p1-4
    94: 0 0 0 0 0 2475 IR-PCI-MSI-edge
    p1p1-5
    

    上面的输出显示 NIC 驱动程序为 p1p1 接口创建了 6 个接收队列(p1p1-0 至 p1p1-5)。也显示出每个队列处理的中断数量以及处理中断的 CPU。在这种情况下,有 6 个队列,因为默认 NIC 驱动程序会为每个 CPU 创建一个队列,这个系统一共有 6 个 CPU。这是 NIC 驱动程序中很常见的模式。

    或者用户可以在网络驱动程序加载后查看 ls -1 /sys/devices///device_pci_address/msi_irqs 的输出。例如,如果用户对 PCI 地址为 0000:01:00.0 的设备感兴趣,可以通过以下指令来列出该设备中断请求队列:

    # ls -1 /sys/devices/*/*/0000:01:00.0/msi_irqs
    101
    102
    103
    104
    105
    106
    107
    108
    109
    

    RSS 是默认启用的。RSS 的队列数(或是需要运行网络活动的 CPU )会由适当的网络驱动程序来进行配置。 bnx2x 驱动程序是在 num_queues 中进行配置。sfc 驱动程序是用 rss_cpus 参数进行配置。通常,这都是在 /sys/class/net/device/queues/rx-queue/ 中进行配置,其中 device 是网络设备的名称(比如 eth1),rx-queue 是适当的接收队列名称。

    配置 RSS 时,建议限制每一个物理 CPU 的队列数量。超线程在分析工具中通常代表独立的核,但是所有核的配置队列,包括如超线程这样的逻辑核尚未被证实对网络性能有益。

    启用时,基于每个队列的 CPU 进程数量,RSS 在 CPU 间平等地分配网络处理操作。用户也可以使用 ethtool --show-rxfh-indir 和 --set-rxfh-indir 参数来更改网络活动的分配方式,并权衡哪种类型的网络活动更为重要。

    irqbalance 后台程序可与 RSS 相结合,以减少跨节点内存及高速缓存行反弹的可能性。这降低了处理网络数据包的延迟。

    4.2.6 配置 RPS

    RPS(接收端包控制)与 RSS类似,用于将数据包指派至特定的 CPU 进行处理。但是,RPS 是在软件级别上执行的,这有助于防止单个网络接口卡的硬件队列成为网络流量中的瓶颈。

    较之于基于硬件的 RSS ,RPS 有几个优点:

    • RPS 可以用于任何网络接口卡。
    • 易于添加软件过滤器至 RPS 来处理新的协议。
    • RPS 不会增加网络设备的硬件中断率。但是会引起处理器间的中断。

    每个网络设备和接收队列都要配置 RPS,在 /sys/class/net/device/queues/rxqueue/rps_cpus 文件中,device 是网络设备的名称(比如 eth0 ),rx-queue 是接收队列名称(例如 rx-0)。

    rps_cpus 文件的默认值为 0 。这会禁用 RPS,处理网络中断的 CPU 也处理数据包。

    要启用 RPS,配置 rps_cpus 文件以及处理特定网络设备和接收队列数据包的 CPU 。

    rps_cpus 文件使用以逗号隔开的 CPU 位图。因此,要让 CPU 为一个接口的接收队列处理中断,请将它们在位图里的位置值设为 1。例如,用 CPU 0、1、2 和 3 处理中断,将 rps_cpus 的值设为 00001111(1+2+4+8),或 f(十六进制的值为 15)。

    对于单一传输队列的网络设备,配置 RPS 以在同一内存区使用 CPU 可获得最佳性能。在非 NUMA 的系统中,这意味着可以使用所有空闲的 CPU。如果网络中断率极高,排除处理网络中断的 CPU 也可以提高性能。

    对于多队列的网络设备,同时配置 RPS 和 RSS 通常都不会有好处,因为 RSS 配置是默认将 CPU 映射至每个接收队列。但是,如果硬件队列比 CPU 少,并且配置 RPS 来在同一内存区使用 CPU,RPS依然有用。

    4.2.7 配置 RFS

    RFS(接收端流的控制)扩展了 RPS 的性能以增加 CPU 缓存命中率,以此减少网络延迟。RPS 是基于队列长度来转发数据包,RFS 使用 RPS 后端预测最合适的 CPU,之后会根据应用程序处理数据的位置来转发数据包。这增加了 CPU 的缓存效率。

    RFS 是默认禁用的。要启用 RFS,用户须编辑两个文件:

    /proc/sys/net/core/rps_sock_flow_entries
    	设置为并发活跃连接数的最大值。对于中等服务器负载,推荐值为 32768 。所有输入的值四舍五入至最接近的2的幂。
    
    /sys/class/net/device/queues/rx-queue/rps_flow_cnt
    	将 device 改为想要配置的网络设备名称(例如,eth0 ),将 rx-queue 改为想要配置的接收队列名称(例如,rx-0 )。
    
    	将此文件的值设为 rps_sock_flow_entries 除以 N,其中 N 是设备中接收队列的数量。例如,如果 rps_flow_entries 设为 32768,并且有 16 个接收队列,那么rps_flow_cnt 就应设为 2048。对于单一队列的设备,rps_flow_cnt 的值和rps_sock_flow_entries 的值是一样的。
    

    从单个发送程序接收的数据不会发送至多个 CPU。如果从单个发送程序接收的数据多过单个 CPU 可以处理的数量,须配置更大的帧数以减少中断数量,并以此减少 CPU 的处理工作量。或是考虑 NIC 卸载选项,或使用更快的 CPU。

    考虑使用 numactl 或 taskset 与 RFS 相结合,以将应用程序固定至特定的内核、socket 或 NUMA 节点。这可以有助于防止数据处理紊乱。

    4.2.8 配置加速 RFS

    加速 RFS 是通过添加硬件协助来增加 RFS 的处理速度。跟 RFS 一样,数据转发是基于应用程序处理数据包的位置。但不同于传统 RFS 的是,数据是直接发送至处理数据线程的本地 CPU:即运行应用程序的 CPU,或是对于在缓存层次结构中的 CPU 来说的一个本地 CPU。

    加速 RFS 只有满足以下条件才可以使用:

    • 网络接口卡须支持加速 RFS。加速 RFS 是由输出 ndo_rx_flow_steer() netdevice 函数的接口卡支持。
    • ntuple 筛选必须启用。

    一旦满足了这些条件,CPU 到队列的映射就会基于传统 RFS 配置自动推导出来。即 CPU 到队列的映射会基于由接收队列的驱动程序配置的 IRQ 关联性而自动推导出来。

    建议在可以使用 RFS 以及网络接口卡支持硬件加速时使用加速 RFS 。


登录后回复
 

与 BC-LINUX 的连接断开,我们正在尝试重连,请耐心等待