tuned-adm 性能调优分析
徐小东 (a.k.a toy)
(xxdlhy@gmail.com)
2017.04
性能调优方向
- CPU: governor、energy_perf_bias、min_perf_pct
性能调优方向
- CPU: governor、energy_perf_bias、min_perf_pct
- 内存: transparent_hugepages、vm.{dirty_ratio,dirty_background_ratio,swappiness}
性能调优方向
- CPU: governor、energy_perf_bias、min_perf_pct
- 内存: transparent_hugepages、vm.{dirty_ratio,dirty_background_ratio,swappiness}
- 磁盘: readahead、scheduler、kernel.sched_{min_granularity_ns,wakeup_granularity_ns,migration_cost_ns}
性能调优方向
- CPU: governor、energy_perf_bias、min_perf_pct
- 内存: transparent_hugepages、vm.{dirty_ratio,dirty_background_ratio,swappiness}
- 磁盘: readahead、scheduler、kernel.sched_{min_granularity_ns,wakeup_granularity_ns,migration_cost_ns}
- 文件系统 (ext4): relatime/noatime、barrier/nobarrier、discard/nodiscard
性能调优方向
- CPU: governor、energy_perf_bias、min_perf_pct
- 内存: transparent_hugepages、vm.{dirty_ratio,dirty_background_ratio,swappiness}
- 磁盘: readahead、scheduler、kernel.sched_{min_granularity_ns,wakeup_granularity_ns,migration_cost_ns}
- 文件系统 (ext4): relatime/noatime、barrier/nobarrier、discard/nodiscard
- 网络: net.ipv4.{tcp_rmem,tcp_wmem,udp_mem}、net.core.busy_{read,poll}、net.ipv4.tcp_fastopen
性能调优场景
- throughput-performance (侧重于吞吐量)
性能调优场景
- throughput-performance (侧重于吞吐量)
- latency-performance (侧重于低延迟)
性能调优场景
- throughput-performance (侧重于吞吐量)
- latency-performance (侧重于低延迟)
- network-throughput (侧重于网络吞吐量)
性能调优场景
- throughput-performance (侧重于吞吐量)
- latency-performance (侧重于低延迟)
- network-throughput (侧重于网络吞吐量)
- network-latency (侧重于更低的网络延迟)
性能调优场景
- throughput-performance (侧重于吞吐量)
- latency-performance (侧重于低延迟)
- network-throughput (侧重于网络吞吐量)
- network-latency (侧重于更低的网络延迟)
- virtual-host (侧重于优化虚拟主机)
性能调优场景
- throughput-performance (侧重于吞吐量)
- latency-performance (侧重于低延迟)
- network-throughput (侧重于网络吞吐量)
- network-latency (侧重于更低的网络延迟)
- virtual-host (侧重于优化虚拟主机)
- virtual-guest (侧重于优化虚拟客户机)
CPU: governor
CPU 时钟频率的管理模式
- performance (性能):强制 CPU 尽可能使用最高的时钟频率
CPU: governor
CPU 时钟频率的管理模式
- performance (性能):强制 CPU 尽可能使用最高的时钟频率
- powersave (省电):强制 CPU 尽可能使用最低的时钟频率
CPU: governor
CPU 时钟频率的管理模式
- performance (性能):强制 CPU 尽可能使用最高的时钟频率
- powersave (省电):强制 CPU 尽可能使用最低的时钟频率
- ondemand (按需):系统负载高时,CPU 使用最高的时钟频率;系统空闲时,CPU 使用最低的时钟频率
CPU: governor
CPU 时钟频率的管理模式
- performance (性能):强制 CPU 尽可能使用最高的时钟频率
- powersave (省电):强制 CPU 尽可能使用最低的时钟频率
- ondemand (按需):系统负载高时,CPU 使用最高的时钟频率;系统空闲时,CPU 使用最低的时钟频率
- userspace (用户态):允许用户或用户态程序自行设置时钟频率
CPU: governor
CPU 时钟频率的管理模式
- performance (性能):强制 CPU 尽可能使用最高的时钟频率
- powersave (省电):强制 CPU 尽可能使用最低的时钟频率
- ondemand (按需):系统负载高时,CPU 使用最高的时钟频率;系统空闲时,CPU 使用最低的时钟频率
- userspace (用户态):允许用户或用户态程序自行设置时钟频率
- conservative (保守):类似 ondemand,区别是它根据是否适合负载来调整时钟频率,而不是简单的在最高和最低之间选择
查询 governor (目前支持)
$ cpupower --cpu all frequency-info --governors analyzing CPU 0: available cpufreq governors: performance powersave analyzing CPU 1: available cpufreq governors: performance powersave analyzing CPU 2: available cpufreq governors: performance powersave analyzing CPU 3: available cpufreq governors: performance powersave
查询 governor (正在使用)
$ cpupower --cpu all frequency-info --policy analyzing CPU 0: current policy: frequency should be within 400 MHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. analyzing CPU 1: current policy: frequency should be within 400 MHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. analyzing CPU 2: current policy: frequency should be within 400 MHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. analyzing CPU 3: current policy: frequency should be within 400 MHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range.
设置 governor
方法一:
$ sudo cpupower frequency-set --governor performance
方法二:
/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_governors /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
CPU: energy_perf_bias
Energy Performance Bias(能耗/性能偏差)
- performance(性能):处理器不为了节省能源而牺牲性能
CPU: energy_perf_bias
Energy Performance Bias(能耗/性能偏差)
- performance(性能):处理器不为了节省能源而牺牲性能
- normal(正常):处理器为了可能明显的节省能源而容许牺牲较小的性能
CPU: energy_perf_bias
Energy Performance Bias(能耗/性能偏差)
- performance(性能):处理器不为了节省能源而牺牲性能
- normal(正常):处理器为了可能明显的节省能源而容许牺牲较小的性能
- powersave(省电):处理器为了最有效率的节省能源而接受可能明显的性能减少
查询 energy_perf_bias
$ sudo x86_energy_perf_policy -r cpu0: 0x0000000000000006 # 代表 normal cpu1: 0x0000000000000006 cpu2: 0x0000000000000006 cpu3: 0x0000000000000006 NOTE: {kernel-source}/tools/power/x86/x86_energy_perf_policy
设置 energy_perf_bias
$ sudo x86_energy_perf_policy performance cpu0 msr0x1b0 0x0000000000000006 -> 0x0000000000000000 cpu1 msr0x1b0 0x0000000000000006 -> 0x0000000000000000 cpu2 msr0x1b0 0x0000000000000006 -> 0x0000000000000000 cpu3 msr0x1b0 0x0000000000000006 -> 0x0000000000000000
CPU: min_perf_pct
Intel 处理器 P-State(Performance States,性能状态) 的最小值,指最大化性能级别的百分比
- max_perf_pct:P-State 的最大值,指可用性能的百分比
- num_pstates:硬件支持的 P-State 数
查询 min_perf_pct
/sys/devices/system/cpu/intel_pstate
内存: transparent_hugepages
Transparent Huge Pages (透明巨页),内核自动分配巨页给进程
- always:尝试为任意进程分配巨页
内存: transparent_hugepages
Transparent Huge Pages (透明巨页),内核自动分配巨页给进程
- always:尝试为任意进程分配巨页
- madvise:利用 madvise() 系统调用只为个别进程分配巨页
内存: transparent_hugepages
Transparent Huge Pages (透明巨页),内核自动分配巨页给进程
- always:尝试为任意进程分配巨页
- madvise:利用 madvise() 系统调用只为个别进程分配巨页
- never:禁用透明巨页
查询/设置 transparent_hugepages
cat /sys/kernel/mm/transparent_hugepage/enabled # 查看 echo "always" > /sys/kernel/mm/transparent_hugepage/enabled # 设置
内存: vm.*
- vm.dirty_background_ratio: 设置 dirty pages 开始后台回写时的百分比
- vm.dirty_ratio: 设置 dirty pages 开始回写时的百分比
- vm.swappiness: 控制从物理内存换出到交换空间的相对权重,取值为 0 到 100。更低的值导致避免交换,而更高的值导致尝试使用交换空间
磁盘: readahead
读取文件列表的内容到内存,以便当实际需要时可从缓存读取
/sys/block/sda/queue/read_ahead_kb NOTE: 替换块设备 sda
磁盘: scheduler
I/O 调度器
- cfq:Completely Fair Queueing(完全公平队列)调度器,它将进程分为实时、尽其所能和空闲三个独立的类别。实时类别的进程先于尽其所能类别的进程执行,而尽其所能类别的进程总是在空闲类别的进程之前执行。默认情况下分配到尽其所能类别的进程
- deadline:尝试为 I/O 请求提供有保障的延迟。适用于大多数情况,尤其是读取操作比写入操作更频繁的请求
- noop:执行简单的 FIFO(先进先出)调度算法,并实现请求合并。适合使用快速存储的 CPU 计算密集型系统
- blk-mq:即 Multi-Queue Block IO Queuing Mechanism(多队列块 IO 队列机制),它利用具有多核的 CPU 来映射 I/O 队列到多队列。与传统的 I/O 调度器相比,通过多线程及多个 CPU 核心来分发任务,从而能够加速读写操作。该调度器适合高性能的闪存设备(如 PCIe SSD)
查看/设置 scheduler
cat /sys/block/sda/queue/scheduler # 查看当前使用的 I/O 调度器 echo "deadline" > /sys/block/sda/queue/scheduler # 临时将 I/O 调度器设为 deadline 追加 elevator=deadline 内核参数 # 永久设置 scsi_mod.use_blk_mq=y dm_mod.use_blk_mq=y # 注意启用 blk-mq 后,将禁用所有别的 I/O 调度器 NOTE: 替换块设备 sda
kernel.sched_*
- kernel.sched_min_granularity_ns: 针对 CPU 计算密集型任务设置调度器的最小抢占粒度
- kernel.sched_wakeup_granularity_ns: 设置调度器的唤醒粒度,这将延迟抢占效应,并减少过度调度
- kernel.sched_migration_cost_ns: 调度器认为迁移的进程“cache hot”因而更少可能被重新迁移的总时间
文件系统 (ext4)
挂载参数
- relatime/noatime: 对于如何更新 inode 访问时间的策略
- barrier=<0|1>(barrier/nobarrier): 该选项开启或禁用在 jbd 代码中使用写入 barrier
- discard/nodiscard: 控制是否执行 discard/TRIM 命令,对 SSD 设备有用
网络: net.ipv4.{tcp_rmem,tcp_wmem,udp_mem}
- tcp_rmem:用于 autotuning 函数,设置 TCP 接收缓冲的最小、默认及最大字节数
- tcp_wmen:用于 autotuning 函数,设置 TCP 发送缓冲的最小、默认及最大字节数
- udp_mem:设置 UDP 队列的页数
网络: net.core.busy_{read,poll}
- net.core.busy_read: 针对 socket 读取设置低延迟 busy poll 超时
- net.core.busy_poll: 针对 poll 和 select 设置低延迟 busy poll 超时
- net.ipv4.tcp_fastopen: TCP 快速打开(TFO)
common
governor=performance energy_perf_bias=performance min_perf_pct=100 transparent_hugepages=always * readahead=>4096 scheduler=deadline * * 视情况而定
throughput-performance
kernel.sched_min_granularity_ns = 10000000 kernel.sched_wakeup_granularity_ns = 15000000 vm.dirty_ratio = 40 vm.dirty_background_ratio = 10 vm.swappiness = 10
latency-performance
kernel.sched_min_granularity_ns = 10000000 kernel.sched_migration_cost_ns = 5000000 vm.dirty_ratio = 10 vm.dirty_background_ratio = 3 vm.swappiness = 10
network-throughput
在 throughput-performance 基础上增加网络调优
kernel.sched_min_granularity_ns = 10000000 kernel.sched_wakeup_granularity_ns = 15000000 vm.dirty_ratio = 40 vm.dirty_background_ratio = 10 vm.swappiness = 10 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 16384 16777216 net.ipv4.udp_mem = 3145728 4194304 16777216
network-latency
在 latency-performance 基础上增加网络调优
transparent_hugepages=never kernel.sched_min_granularity_ns = 10000000 kernel.sched_migration_cost_ns = 5000000 vm.dirty_ratio = 10 vm.dirty_background_ratio = 3 vm.swappiness = 10 net.core.busy_read = 50 net.core.busy_poll = 50 net.ipv4.tcp_fastopen = 3
virtual-host
kernel.sched_min_granularity_ns = 10000000 kernel.sched_wakeup_granularity_ns = 15000000 kernel.sched_migration_cost_ns = 5000000 vm.dirty_ratio = 40 vm.dirty_background_ratio = 5 vm.swappiness = 10
virtual-guest
kernel.sched_min_granularity_ns = 10000000 kernel.sched_wakeup_granularity_ns = 15000000 vm.dirty_ratio = 30 vm.dirty_background_ratio = 10 vm.swappiness = 30
总结
- scheduler: 相比 cfq 的表现,deadline 无论在读还是在写上都更有优势。对于具有固态存储设备的场景而言,blk-mq 值得一试
- kernel.sched_min_granularity_ns: 比默认值调得更大一些,推荐设为 10000000(1 毫秒),从而稍微延迟抢占,具有更好的性能表现。该参数值适合上述所有场景
- kernel.sched_wakeup_granularity_ns: 比默认值调大,从而避免过度调度,推荐设为 15000000(1.5 毫秒)。仅在注重吞吐量的情况下设置该参数,低延迟的情况不要设置
- kernel.sched_migration_cost_ns: 比默认值调大,从而减少任务的重新迁移,推荐设为 5000000(0.5 毫秒)。仅在注重低延迟的情况下设置该参数,高吞吐量的情况不要设置
总结 (续)
- vm.dirty_ratio: 高吞吐量的情况一般设置为 40,低延迟的情况通常设置为 10
- vm.dirty_background_ratio: 高吞吐量的情况可设为 10,低延迟的情况可设为 3
- vm.swappiness: 一般设为 10,从而避免过多 swap 交换。仅在作为虚拟客户机的情况下可设高一些(30)
总结 (续)
毫无疑问 noatime 应该作为默认挂载参数,nobarrier 在写上的性能优势十分明显,discard 适合 SSD 的场合
noatime nobarrier discard
总结 (续)
仅在注重网络吞吐量的情况下调节
net.ipv4.tcp_rmem net.ipv4.tcp_wmem net.ipv4.udp_mem
仅在注重网络低延迟的情况下调节
net.core.busy_read net.core.busy_poll net.ipv4.tcp_fastopen