原力注入

Linux 基础知识 - CPU 上下文切换之问题排查

接上文:Linux 基础知识 - CPU 上下文切换

Image

系统上下文切换数量如何判断是否正常?

在 Linux 系统中,CPU 的上下文切换(context switch)数量并没有一个严格的“正常”标准,因为上下文切换的频率与系统的工作负载、应用程序类型和配置密切相关。然而,可以通过以下几点来分析上下文切换是否在合理范围内:

与 CPU 核心数对比

如果上下文切换的数量除以 CPU 核心数得到的平均值比较高(例如,每个核心每秒数万次切换),需要检查是否有过多线程在竞争。

CPU 使用率是否受影响

如果上下文切换数量很高,但 CPU 的用户态和内核态使用率也同时很高,可能说明系统陷入了资源竞争。

系统响应是否正常

如果上下文切换的数量增多伴随着明显的系统卡顿、进程阻塞或服务延迟,则说明系统存在资源竞争。

如何统计系统范围一段时间内,上下文切换比较高的进程?

pidstat 是 sysstat 工具包的一部分,可以按进程统计上下文切换次数(包括自愿和非自愿切换)。

pidstat -w 1 3

示例输出:

Linux 3.10.0-1160.119.1.el7.x86_64 (tdc-55)     11/20/24    _x86_64_    (48 CPU)

 12:44:45      UID       PID   cswch/s nvcswch/s  Command
12:44:46        0         1      0.96      0.00  systemd
12:44:46        0         6      1.92      0.00  ksoftirqd/0
12:44:46        0         9    194.23      0.00  rcu_sched
12:44:46        0        19      0.96      0.00  migration/2
12:44:46        0        25      0.96      0.00  ksoftirqd/3
12:44:46        0        40      0.96      0.00  ksoftirqd/6
12:44:46        0        50      0.96      0.00  ksoftirqd/8
12:44:46        0        59      0.96      0.00  migration/10
12:44:46        0        60      7.69      0.00  ksoftirqd/10

其中字段说明如下:

  • • cswch/s:每秒自愿上下文切换次数。

  • • nvcswch/s:每秒非自愿上下文切换次数。

  • • Command:进程名称。

通过观察 cswch/s 和 nvcswch/s 值,我们可以确定上下文切换较高的进程。

如果对单个进程感兴趣,可以直接查看 /proc/[pid]/status 中的 voluntary_ctxt_switches 和 nonvoluntary_ctxt_switches 字段,例如:

cat /proc/1/status
...
voluntary_ctxt_switches:    7014781
nonvoluntary_ctxt_switches: 173757

如何找出一个进程的 context switch 比较高的原因?

找出一个进程上下文切换(context switch)较高的原因需要结合上下文切换的类型、进程的行为、系统资源状况等多个方面进行分析。以下是具体的排查方法和常见原因:

判断上下文切换类型

grep 'voluntary_ctxt_switches' /proc/<pid>/status
grep 'nonvoluntary_ctxt_switches' /proc/<pid>/status

如果某一类型上下文切换值较高,可以针对该类型进行进一步分析。

分析自愿上下文切换(Voluntary Context Switch)

常见原因

  • • 频繁等待 I/O:进程正在等待磁盘或网络 I/O 完成,主动让出 CPU。

  • • 锁竞争:多线程程序中,线程因获取锁失败而主动阻塞。

  • • 资源不可用:进程等待资源(如信号、管道数据、文件描述符)可用。

排查方法

  • • 使用 strace 分析系统调用:

strace c -p <pid>

查看进程频繁调用的系统调用,是否存在大量 read、write、poll 或 futex 操作。

  • • 使用 iotop 检查 I/O 活动:

iotop -o -p <pid>

查看是否有大量的磁盘 I/O 活动。

  • • 使用 perf 检查锁竞争:

perf record -e sched:sched_switch -p <pid> sleep 5
perf report

查看是否因锁竞争导致频繁的上下文切换。

分析非自愿上下文切换(Non-Voluntary Context Switch)

常见原因

  • • CPU 时间片用尽:进程运行时占用 CPU 时间片,被系统调度器强制切换。

  • • 高优先级进程抢占:系统中其他高优先级进程抢占了 CPU 资源。

  • • 核争用:在多核环境下,进程频繁被调度到不同的 CPU 核上运行。

排查方法

  • • 检查进程的 CPU 使用情况:

使用 top 或 pidstat 查看进程的 CPU 占用是否异常。

pidstat -u 1 -p <pid>
  • • 观察系统负载:

使用 htop 或 uptime 查看是否有高负载进程导致频繁抢占。

  • • 使用 perf sched 分析调度器行为:

perf sched record sleep 5 
perf sched latency

查看调度器是否频繁切换进程,以及其他高优先级进程的抢占行为。

结合应用场景分析

网络相关进程

网络应用通常涉及大量 I/O,可能会有较高的自愿上下文切换。

  • • 使用 ss 或 netstat 检查是否存在大量连接:

ss -s

多线程程序

多线程程序可能因锁竞争导致高上下文切换。我们使用 perf 查看锁竞争情况:

perf lock record -p <pid>
perf lock report

示例输出:

#            Usage          Time          Caller
   contended   total wait   max wait
-------------------------------------------------
1     100      5.678 ms     1.123 ms   mutex_lock+0x12
2      80      4.321 ms     0.954 ms   pthread_mutex_lock+0x21
3      50      3.210 ms     1.002 ms   futex_wait+0x33

内核需要开启 CONFIG_LOCKDEP 和 CONFIG_LOCK_STAT 这两个参数。

大量进程竞争

如果系统中运行了大量的进程,可能导致 CPU 资源不足,进而增加非自愿上下文切换。我们可以使用 ps 或 top 检查系统中运行的进程总数:

ps -e | wc -l

总结和优化思路

分析步骤:

  • • 确认上下文切换类型(自愿/非自愿)。

  • • 排查高 I/O、锁竞争、高负载等可能原因。

  • • 结合应用程序的行为(如 I/O 密集或计算密集)调整代码逻辑或系统配置。

优化上下文切换整体思路

  • • 减少 I/O 阻塞:使用异步 I/O 或优化磁盘性能。

  • • 减少锁竞争:优化多线程代码,使用更高效的锁机制(如 spinlock)。

  • • 优化调度优先级:根据进程重要性设置更高的调度优先级:

renice -n -5 -p <pid>
  • • 降低系统负载:检查并减少无关的高负载进程。