news 2026/6/10 17:59:35

Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟

Linux 性能实战 | 第 8 篇 上下文切换、内核线程与调度延迟 🐢

🔗 上下文切换:CPU 的“换挡”开销

在上一章中,我们探讨了调度器如何通过进程迁移来实现 CPU 负载均衡。我们提到了迁移是有成本的,这个成本的核心就是上下文切换 (Context Switch)

想象一下你正在专注地写一份复杂的代码(执行一个进程),这时突然来了一个紧急电话(中断),你不得不放下手头的工作,记录下当前的思路(保存现场),然后去处理电话(切换到内核态处理中断)。打完电话后,你还需要回忆刚才写到哪里了(恢复现场),才能继续编程。这个“放下-切换-恢复”的过程,就是一次上下文切换。

对 CPU 而言,上下文切换意味着:

  1. 保存当前进程/线程的“快照”:包括 CPU 寄存器(程序计数器、栈指针等)、进程状态、内存管理信息等。
  2. 加载下一个进程/线程的“快照”到 CPU 寄存器中。
  3. 刷新 TLB (Translation Lookaside Buffer):导致虚拟地址到物理地址的缓存失效。
  4. CPU 缓存失效:新进程的代码和数据很可能不在 CPU 的 L1/L2/L3 缓存中,需要从更慢的内存中重新加载。

一句话总结:上下文切换是必要的“恶”。没有它,多任务系统无法工作。但过于频繁的切换,就像一个员工不停地在多个任务间来回切换,大部分时间都浪费在了“切换”本身,而不是真正地“执行”任务,导致系统整体效率大幅下降。


🤔 什么时候会发生上下文切换?

上下文切换主要分为三类:

1. 进程上下文切换 (Process Context Switch)

这是开销最大的一种切换。它不仅涉及到内核态和用户态的切换,还涉及到虚拟内存空间的切换。

  • 时间片用完:CFS 调度器为了“公平”,会中断当前进程,让给vruntime更小的进程。
  • 进程阻塞:当进程需要等待某个资源时,如等待磁盘 I/O、等待网络数据、或者通过sleep主动挂起,它会被置为INTERRUPTIBLEUNINTERRUPTIBLE状态,从而触发调度,让出 CPU。
  • 更高优先级的进程就绪:一个实时进程(如SCHED_RR)变为可运行状态,会立即抢占当前正在运行的普通进程。

2. 线程上下文切换 (Thread Context Switch)

当同一进程内的两个线程之间发生切换时,因为它们共享同一个虚拟内存空间,所以切换时不需要更换页表,TLB 也不会被完全刷新。因此,它的开销比进程上下文切换要小得多。

3. 中断上下文切换 (Interrupt Context Switch)

为了快速响应硬件事件(如网卡收到数据包、硬盘完成读写),CPU 会暂停当前运行的进程,切换到内核态去执行一个中断服务程序 (Interrupt Service Routine, ISR)

中断上下文的切换非常快,因为它只涉及少量内核信息的保存和恢复,不涉及用户进程。但它会打断正常进程的执行,如果中断过于频繁,也会严重影响系统性能。


🛠️ 实战:定位上下文切换元凶

场景:一个高并发的 Web 服务器,在压力测试期间,top显示系统 CPU 使用率并不高(例如,us+sy只有 30%),但load average却异常地高,并且服务响应延迟(RT)剧增。

1. 初步诊断:vmstat

vmstat是快速发现上下文切换问题的利器。

# 每秒输出一次报告vmstat1

输出

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 123456 10240 567890 0 0 0 20 1024 200000 15 15 70 0 0 2 0 0 123450 10240 567892 0 0 0 30 1280 250000 18 17 65 0 0 1 0 0 123440 10240 567898 0 0 0 25 1150 220000 16 16 68 0 0

关注两列:

  • cs(context switch):每秒上下文切换的次数。这个值通常在几千到几万是正常的。但如果飙升到几十万甚至上百万,就表明系统存在严重的调度问题。
  • in(interrupt):每秒中断的次数。

在这个案例中,cs高达 20 多万,显然是问题的根源。CPU 的大部分时间都花在了“换挡”上,而不是在执行应用代码(us)或内核代码(sy)。

2. 深入分析:pidstat

找到了问题,下一步就是定位是哪个进程导致的。pidstatsysstat工具包中的一员,专门用于分析进程级别的统计信息。

# -w: 显示上下文切换信息# -p ALL: 监控所有进程# 1: 每秒输出一次pidstat -w -p ALL1

输出

Linux 5.4.0-100-generic (hostname) 01/31/26 _x86_64_ (8 CPU) 10:30:01 UID PID cswch/s nvcswch/s Command 10:30:02 1000 12345 150000.00 5.00 nginx 10:30:02 0 54321 200.00 10.00 kworker/u16:0 10:30:02 1001 9876 10.00 0.00 redis-server ...

关注两列:

  • cswch/s(voluntary context switches)自愿上下文切换。通常是因为进程等待资源(如 I/O)而主动放弃 CPU。如果这个值很高,说明应用可能存在大量的 I/O 等待或者同步锁竞争。
  • nvcswch/s(non-voluntary context switches)非自愿上下文切换。通常是因为时间片用完,或者被更高优先级的进程抢占。如果这个值很高,说明 CPU 正在被多个活跃进程激烈争抢。

pidstat的输出中,我们一目了然地看到nginx进程(PID 12345)每秒产生了 15 万次自愿上下文切换。这说明nginx的 worker 进程在疯狂地等待某个资源,导致它们不断地被挂起和唤醒。

可能的原因

  • 后端服务瓶颈nginx作为反向代理,后端应用(如 PHP、Java)处理缓慢,导致nginxworker 大量阻塞在网络 I/O 上。
  • 锁竞争:应用代码中存在设计不当的全局锁,导致大量线程在等待同一个锁。
  • 连接数过多nginx配置的worker_connections过高,而系统资源(如文件描述符)不足。

通过这个线索,开发和运维团队就可以进一步深入到nginx的配置和后端应用代码中,找到最终的性能瓶颈。


👽 神秘的内核线程:kworkerksoftirqd

在使用topps时,你经常会看到一些以k开头的、方括号括起来的进程,如kworkerksoftirqd。它们是内核线程 (Kernel Threads),在后台为操作系统执行各种管理任务。

kworker:内核的“临时工”

kworker是内核工作队列(workqueue)的执行者。内核的各个子系统(如磁盘、网络、定时器)会把一些耗时较长、不能在中断上下文中完成的任务,打包成一个“工作项”,扔到工作队列里,然后由kworker线程在未来的某个时刻异步地去执行。

命名格式kworker/u<cpu_id>:<worker_id>kworker/<cpu_id>:<worker_id>

  • u表示这个kworker是非绑定的(unbound),可以在多个 CPU 核心间迁移。
  • <cpu_id>表示它主要在哪个 CPU 上活动。

如果kworker的 CPU 使用率很高,通常意味着内核正在忙于处理某些后台任务。你可以通过perf工具来追踪kworker到底在忙什么。

ksoftirqd:软中断的“清道夫”

当硬件中断(硬中断)发生得过于频繁时,为了避免长时间关中断影响系统响应,内核会将一部分耗时较长的处理工作推迟,变成软中断 (softirq)

ksoftirqd就是专门用来处理软中断的内核线程,每个 CPU 核心都有一个。如果软中断的产生速度超过了处理速度,积压的软中断就会由ksoftirqd来“兜底”处理。

命名格式ksoftirqd/<cpu_id>

如果你在top中看到si(softirq)或者ksoftirqd的 CPU 使用率很高,通常指向以下问题:

  • 网络风暴:网络收发包极其频繁,导致大量的网络软中断。
  • 内核锁竞争:内核中处理软中断的逻辑遇到了锁竞争,导致处理效率下降。

📝 总结与展望

  • 上下文切换是核心成本:过高的cs值是系统“内耗”的明确信号。使用vmstat发现问题,再用pidstat -w定位到具体进程。
  • 区分自愿与非自愿切换cswch/s高通常指向 I/O 或锁等待问题;nvcswch/s高通常指向 CPU 资源不足或争抢激烈。
  • 关注内核线程kworkerksoftirqd的高 CPU 占用率是内核层面存在瓶颈的线索,通常与 I/O 和网络活动密切相关。

下一篇预告

在本章中,我们学会了如何量化和定位上下文切换带来的性能损耗。我们不仅掌握了vmstatpidstat这两个强大的诊断工具,还认识了kworkerksoftirqd这两个重要的内核“打工人”。

在下一章,我们将继续深入 CPU 的世界,专门探讨软中断和硬中断。我们将揭示top命令中hisi的真正含义,并学习如何处理由它们引发的性能问题。敬请期待!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 18:59:07

HBase与Kafka集成:构建实时大数据处理管道

HBase与Kafka集成&#xff1a;构建实时大数据处理管道 关键词&#xff1a;HBase&#xff0c;Kafka&#xff0c;实时大数据处理&#xff0c;数据集成&#xff0c;处理管道 摘要&#xff1a;本文深入探讨了HBase与Kafka集成以构建实时大数据处理管道的相关技术。首先介绍了HBase和…

作者头像 李华
网站建设 2026/6/10 2:04:56

有你!我的git有救了

Git 核心知识点简便手册一、核心概念&#xff08;3 个关键&#xff09;三大区域&#xff1a;工作区&#xff08;本地项目文件夹&#xff09;→ 暂存区&#xff08;git add 后&#xff09;→ 版本库&#xff08;.git 目录&#xff0c;git commit 后&#xff09;&#xff1b;核心…

作者头像 李华
网站建设 2026/6/10 12:28:42

【小程序毕设全套源码+文档】基于Android的电影信息推荐APP的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/9 18:36:22

深入浅出:使用Linux系统函数构建高性能TCP服务器

&#x1f31f; 深入浅出&#xff1a;使用Linux系统函数构建高性能TCP服务器 &#x1f31f;引言&#xff1a;网络编程的艺术一、TCP服务器基础架构1.1 服务器工作流程图1.2 核心系统调用概览二、构建TCP服务器的详细步骤2.1 创建Socket&#xff1a;通信的起点2.2 绑定地址&#…

作者头像 李华
网站建设 2026/6/10 12:32:06

斑马优化算法优化BP神经网络风电功率预测附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

作者头像 李华