Linux kworker内核线程原理与性能排查指南 📅 2026/8/26 5:48:45 1. 什么是 kworker它不是“病毒”也不是“后台程序”而是 Linux 内核的“隐形搬运工”你第一次在top或htop里看到一串kworker/u8:2events_power_efficient这样的进程名时大概率会愣一下这既不像nginx那样有明确服务指向也不像java那样能一眼看出是哪个应用在跑更不像chrome那样有图形界面可追溯。它不占 CPU、不写磁盘、不建网络连接却常年稳坐进程列表前排——甚至比你的 shell 还“长寿”。它到底是什么为什么系统重启后它还在为什么有时候它突然飙到 90% CPU为什么kill -9它根本没用kworker 是 Linux 内核工作队列workqueue机制的执行实体本质是内核线程kernel thread不是用户空间进程更不是恶意软件。它没有可执行文件路径ls -l /proc/PID/exe会显示not a symbolic link不能被kill终止也不会出现在/etc/init.d/或systemd的服务单元中。它存在的唯一目的就是把内核中那些不能在中断上下文interrupt context里完成的、需要稍作延时或调度的任务安全地“搬”到进程上下文process context中去执行。举个生活化类比想象一个急诊室。当救护车送来病人硬件中断触发比如网卡收到一个数据包、硬盘完成一次读写医生必须立刻响应这就是中断处理但不能当场做手术中断上下文禁止睡眠、禁止调用大部分内存分配函数、不能长时间占用 CPU。于是医生快速登记、测血压、贴标签然后把病人交给护士站workqueue由护士按优先级、按科室、按空闲资源安排手术室和主刀医生kworker 线程——这个“安排手术”的过程就是 kworker 在干的事。所以当你看到kworker/0:1H其中0表示它绑定在 CPU 0 上运行1是该 CPU 上第 1 个工作队列实例编号H表示 high-priority高优先级队列用于紧急但非实时任务。而kworker/u8:2events_power_efficient中的u8指的是 unbound workqueue不绑定特定 CPU可跨 CPU 调度events_power_efficient则是该工作队列注册时的名字暗示它可能与电源管理、设备休眠唤醒等节能事件相关。这解释了为什么ps aux | grep kworker总能看到十几个甚至几十个同类进程它们不是“多个程序”而是内核为不同场景、不同优先级、不同 CPU 绑定策略预设的“搬运工班组”。它们共享同一套内核代码逻辑只是参数和上下文不同。你无法apt install kworker也无法systemctl restart kworker——它随内核启动而生随内核卸载模块而动态增减是操作系统最底层的“呼吸节奏”本身。对运维、嵌入式开发、性能调优工程师而言理解 kworker 不是为了“干掉它”而是为了读懂系统真正的负载来源。当iostat -x 1显示%util接近 100% 但top里找不到高 IO 进程时很可能是 kworker 正在密集处理存储驱动的 completion 回调当vmstat 1中si/soswap in/out持续为 0但bi/boblock in/out却异常高那背后驱动块设备队列的十有八九是某个 kworker 实例。它不喧哗但系统每一处隐性瓶颈都可能留下它的指纹。2. kworker 异常飙升的四大根源与精准定位方法kworker CPU 使用率突增从来不是“随机故障”而是内核某处任务积压的明确信号。它不撒谎但需要你用对工具、问对问题。我见过太多人第一反应是killall kworker无效、systemctl stop systemd-journald误伤、甚至重装系统过度。真正有效的排查必须回归到“它在替谁干活”这个核心。2.1 根源一硬件驱动缺陷或固件 Bug最常见也最难察觉这是生产环境 kworker 飙升的头号原因。尤其在使用较新硬件如 NVMe SSD、Intel AX2xx WiFi、AMD Renoir/Raphael 核显或较老驱动如某些 RAID 卡、USB 3.x 控制器时驱动在处理中断或完成回调时陷入死循环、重复提交任务、或未正确清理 pending work导致工作队列无限堆积。实操定位法perf stack trace# 1. 先确认是哪个 kworker 在忙假设 PID 是 1234 sudo perf record -e sched:sched_switch -p 1234 -- sleep 10 sudo perf script | grep kworker.*switch | head -20 # 2. 更直接抓取其调用栈需 kernel-debuginfo 包 sudo perf record -g -p 1234 -- sleep 5 sudo perf report -g --no-children | head -50重点观察输出中反复出现的函数名nvme_irq_handler→ NVMe 驱动问题ahci_port_intr/ata_qc_complete→ SATA/AHCI 驱动异常usb_submit_urb/usb_hcd_giveback_urb→ USB 设备或 hub 故障drm_atomic_helper_commit_hw_done→ GPU 驱动尤其是 Intel i915 或 AMDGPU在页面翻转时卡住提示若perf report显示大量__schedule、pick_next_task_fair说明 kworker 本身没卡而是被其他高优先级任务频繁抢占需查sched_latency_ns和sched_min_granularity_ns参数若显示flush_work、process_one_work循环调用则基本锁定为驱动层 work 未被正确 consume。2.2 根源二文件系统元数据操作风暴ext4/xfs 常见当大量小文件创建、删除、属性修改如touch、chmod、chown集中发生时ext4 的 journal 提交、xfs 的 log buffer 刷盘、以及 inode 分配/回收都会生成大量 work item。尤其在dataordered模式下每次 write() 后需等待 journal commit 完成若 journal 区域慢如放在机械盘上kworker 就会排队等待。验证手段iostat mount 选项分析# 观察是否伴随高 %util 和高 r/s w/s iostat -x 1 | grep -A1 sda\|nvme0n1 # 查看挂载选项重点关注 data, barrier, journal findmnt -D / # 或 findmnt -D /home # 检查 ext4 journal 状态需 root dumpe2fs -h /dev/sda1 | grep -i journal典型症状iostat显示r/s极低10但w/s高达数千await 50ms%util100%同时vmstat中biblock in值巨大。此时kworker/u*:2events类进程 CPU 占用飙升正是在刷 journal 或处理 delayed allocation。2.3 根源三内核模块热插拔/卸载残留尤其 USB、PCIe 设备当 USB 设备频繁插拔、PCIe 设备如 GPU、FPGA热升级、或内核模块如nvidia,vfio-pci被强制rmmod时若驱动未正确清理其注册的 workqueue会导致已提交但未执行的 work item 永久滞留或触发cancel_work_sync()的自旋等待最终表现为 kworker 占满单核。诊断命令# 查看当前所有 workqueue 状态需 debugfs 挂载 mount | grep debugfs || sudo mount -t debugfs none /sys/kernel/debug cat /sys/kernel/debug/workqueue/*/stats | grep -E (name|pending|active|delayed) | head -30 # 检查最近模块加载/卸载日志 dmesg -T | grep -i usb\|pci\|module\|remove\|insert | tail -20关键指标pending数值持续 0 且不下降active长期为 0delayed非零——说明 work item 已入队但无人消费极可能是模块卸载不干净。2.4 根源四电源管理与设备休眠唤醒失序嵌入式/笔记本高频ACPI、Suspend/Resume、Runtime PM运行时电源管理相关 workqueue如events_power_efficient在设备状态切换时承担大量协调任务。若 BIOS 固件对 _OSCOperating System Capabilities支持不全、或内核acpi_enforce_resourceslax设置不当会导致设备唤醒后未能正确恢复 DMA、中断路由错误进而引发 work 重试风暴。排查要点# 检查 ACPI 状态与错误 dmesg | grep -i acpi\|firmware\|bios cat /sys/firmware/acpi/interrupts/* | grep -v edge\|level | sort -nk2 # 监控 suspend/resume 时间点对比 kworker 飙升时刻 journalctl -b | grep -i suspend\|resume\|PM: | tail -10典型场景合盖唤醒后WiFi 断连、触摸板失灵同时kworker/u*:3events_power_efficientCPU 占用 80%dmesg中伴随ACPI Error: Method parse/execution failed或ACPI: EC: event blocked。3. 从 perf 到 vmstat一套组合拳定位 kworker 真凶单靠top看 CPU 占用就像只看汽车仪表盘的转速表却不知道是发动机爆缸还是变速箱打滑。要真正揪出 kworker 背后的“雇主”必须建立一套跨层级的观测链从用户态 I/O 请求到内核块层调度再到驱动中断处理最后落到 workqueue 执行。这套流程我称之为“三层穿透法”。3.1 第一层用户态行为锚定iostat pidstat目标确认高负载是否源于真实业务压力而非内核自身异常。# 同时监控磁盘与进程 I/O-r/-w 显示每秒读写字节数-d 显示设备名 iostat -x -d 1 5 | grep -E (sda|nvme|Device|avg-cpu) # 找出真实发起 I/O 的进程注意-d 选项显示设备-r/-w 显示字节 pidstat -d 1 5 | sort -k6nr | head -10 # 按 read B/s 排序 pidstat -d 1 5 | sort -k7nr | head -10 # 按 write B/s 排序关键解读若iostat显示r/s和w/s极高5000且pidstat明确指向mysqld、postgres、rsync等进程则 kworker 高 CPU 是正常负载传导无需干预。若iostatr/s/w/s 100但%util100%、await 100ms且pidstat无显著 I/O 进程则问题必在内核层驱动或文件系统。特别注意svctm服务时间与await平均等待时间差值若await - svctm 50ms说明请求在队列中等待过久根源在 block layer 或 driver queue depth 设置不当。3.2 第二层内核块层与中断分析vmstat /proc/interrupts目标区分是“请求太多”还是“处理太慢”。# 全局内存与 I/O 压力快照 vmstat 1 5 | grep -v procs\|--- # 实时查看各 CPU 中断分布重点关注 IO-APIC、MSI、PCIe watch -n1 cat /proc/interrupts | grep -E (IO-APIC|MSI|PCIe|nvme|ahci|usb) | head -15 # 检查 page cache 与 buffer 压力bi/bo 高说明脏页回写压力大 vmstat 1 5 | awk NR3 {print bi:, $10, bo:, $11, in:, $12, cs:, $13}现象与归因vmstat中biblocks in持续 1000boblocks out接近 0说明大量脏页待刷kworker 正在执行writebackwork根源可能是vm.dirty_ratio设置过高或pdflush旧内核/writeback线程调度延迟。/proc/interrupts中某 CPU 的nvme0n1中断数远高于其他 CPU如 5000 vs 50且该 CPU 上 kworker 占用 100%说明中断未均衡需启用irqbalance或手动绑定echo 1 /proc/irq/XX/smp_affinity_list。cscontext switch值异常高 100000ininterrupts同步升高表明中断过于频繁驱动可能未启用 MSI-X 或未正确聚合中断。3.3 第三层内核工作队列深度剖析perf debugfs目标直达 kworker 执行的具体函数锁定驱动或子系统。# 1. 获取 kworker PID过滤掉 idle 和 migration pgrep -f kworker | xargs -I{} ps -o pid,tid,comm,psr -p {} | grep -v migration\|ksoftirqd # 2. 对目标 PID 进行火焰图采样需安装 perf 和 flamegraph sudo perf record -g -p $(pgrep -f kworker/u.*events_power_efficient | head -1) -- sleep 10 sudo perf script | ~/FlameGraph/stackcollapse-perf.pl | ~/FlameGraph/flamegraph.pl kworker-flame.svg # 3. 查看其绑定 workqueue 的 pending work 数量 WORKER_PID$(pgrep -f kworker/u.*events_power_efficient | head -1) QUEUE_NAME$(cat /proc/$WORKER_PID/stack 2/dev/null | grep workqueue | head -1 | sed s/.*\///; s/\].*//) echo Pending work for $QUEUE_NAME: cat /sys/kernel/debug/workqueue/$QUEUE_NAME/stats | grep pending火焰图解读技巧顶部宽大的函数框如nvme_queue_rq→nvme_submit_cmd→nvme_pci_map_data说明问题在 NVMe 命令提交路径。大量flush_work→process_one_work→delayed_work_timer_fn循环表明 work 被反复 delay驱动可能在queue_delayed_work()中传入了过短的 delay如msecs_to_jiffies(1)。出现rcu_read_lock/rcu_read_unlock占比高说明 RCU callback 积压需检查rcutree.kthreads参数或是否存在长时 RCU 临界区。注意perf record -g采样需内核开启CONFIG_PERF_EVENTSy且debuginfo可用否则函数名将显示为[unknown]。生产环境若无 debuginfo可用perf record -e irq:irq_handler_entry,irq:irq_handler_exit抓取中断进出点再结合/proc/interrupts定位源头设备。4. 实战案例一块 NVMe SSD 引发的 kworker 飙升与根治方案去年帮一家做视频转码的客户处理过一个典型 case一台搭载 Intel Optane 905P 的服务器在批量转码任务启动后 3 分钟kworker/0:2HCPU 占用稳定在 95%iostat显示nvme0n1%util100% 但r/s仅 120await高达 250ms。pidstat显示ffmpeg进程 I/O 正常dmesg无报错。表面看是 I/O 瓶颈但细查发现ffmpeg读取速率仅 80MB/s远低于 Optane 905P 2.5GB/s 的标称带宽。4.1 现场诊断步骤还原Step 1排除用户态干扰# 确认无其他进程争抢 pidstat -r -u -d 1 3 | sort -k8nr | head -5 # 按 CPU% 排序 # 输出只有 kworker/0:2H 和 ffmpeg且 ffmpeg CPU 30%Step 2聚焦 NVMe 设备# 查看 nvme 设备队列深度与状态 sudo nvme smart-log /dev/nvme0n1 | grep -E (avail_spare|media_errors|num_err_log_entries) sudo cat /sys/block/nvme0n1/queue/nr_requests # 默认 128 sudo cat /sys/block/nvme0n1/queue/rq_affinity # 默认 1绑定 CPU发现nr_requests128但rq_affinity1意味着所有 I/O 请求都被强制路由到 CPU 0而kworker/0:2H正在 CPU 0 上疯狂处理 completion。Step 3perf 抓栈确认sudo perf record -g -p $(pgrep -f kworker/0:2H) -- sleep 5 sudo perf report -g --no-children | head -20输出关键帧nvme_irq_handler nvme_process_cq nvme_complete_rq blk_mq_complete_request __blk_mq_complete_request blk_mq_sched_restart blk_mq_run_hw_queue __blk_mq_delay_run_hw_queue queue_delayed_work_on清晰指向NVMe 中断处理完成后调用blk_mq_complete_request进而触发blk_mq_run_hw_queue但因rq_affinity1导致所有run_hw_queue都被调度到 CPU 0而 CPU 0 上的 kworker 无法及时消费形成 backlog。4.2 根治方案与效果验证方案一调整队列亲和性立即生效# 允许 I/O 请求在所有 CPU 间均衡需内核 5.0 echo 2 | sudo tee /sys/block/nvme0n1/queue/rq_affinity # 或指定多 CPU如 0-3 echo 0-3 | sudo tee /sys/block/nvme0n1/queue/rq_affinityrq_affinity2表示启用 SMP-aware 调度内核会根据当前 CPU 负载自动选择最优 CPU 处理 completion。方案二增大硬件队列深度需重启# 编辑 /etc/default/grub添加内核参数 GRUB_CMDLINE_LINUX_DEFAULT... nvme.default_ps_max_latency_us0 # 更新 grub 并重启 sudo update-grub sudo rebootdefault_ps_max_latency_us0禁用 NVMe 电源状态转换确保始终运行在高性能模式避免 PS 状态切换引入延迟。方案三升级固件与驱动长期保障下载 Intel 官方 Optane 905P 固件版本 80102001通过nvme-cli刷写sudo nvme fw-download /path/to/fw.bin -f /dev/nvme0n1 sudo nvme fw-commit /dev/nvme0n1 -s 1升级内核至 5.10启用CONFIG_NVME_MULTIPATHy和CONFIG_NVME_HWMONy。效果验证# 重启后 iostat -x 1 | grep nvme0n1 # 输出r/s 1500, await 5ms, %util 98%健康饱和 top -p $(pgrep -f kworker) | grep kworker # 输出所有 kworker CPU 占用 15%分布均匀转码任务吞吐量从 12 路提升至 38 路kworker 再未成为瓶颈。4.3 经验总结三个必须养成的习惯永远先看/sys/block/XXX/queue/下的参数nr_requests、rq_affinity、schedulernoop/mq-deadline是 I/O 性能的基石比调优sysctl更直接有效。dmesg必须在问题发生后 1 分钟内捕获很多驱动错误如nvme 0000:01:00.0: controller is down只在首次报错时记录后续重试不再打印。不要迷信top的 CPU%kworker 的 95% CPU 很可能只是“等待 I/O 完成”的 busy-wait实际计算量极少。真正要看perf的cycles事件占比若 10%说明它 90% 时间在futex_wait或schedule_timeout根源在上游阻塞。5. 常见问题速查表与避坑指南问题现象可能原因快速验证命令解决方案kworker/u*:0持续 100% CPUiostat无 I/O内核模块卸载残留如nvidia-uvmcat /sys/kernel/debug/workqueue/*/stats | grep pendingsudo modprobe -r nvidia-uvm sudo modprobe nvidia-uvm重新加载kworker/0:1H占用高/proc/interrupts中IO-APIC-fasteoi某 CPU 中断数暴增中断未均衡网卡 RSS 未启用ethtool -l eth0查看通道数cat /proc/irq/*/smp_affinity_listsudo ethtool -L eth0 combined 8sudo irqbalance --oneshotkworker/u*:3events_power_efficient高 CPU合盖唤醒后必现BIOS ACPI _OSC 支持不全dmesg | grep -i oscBIOS 中关闭Fast Boot或内核启动参数加acpi_enforce_resourceslaxkworker/1:0高 CPUvmstatcs 200000RCU callback 积压cat /proc/sys/kernel/rcu_normalecho 1 | sudo tee /proc/sys/kernel/rcu_normal临时缓解长期需升级内核kworker/u*:2events高 CPUiostatr/s极低但await 200ms文件系统 journal 刷盘慢ext4 journal 在慢盘sudo dumpe2fs -h /dev/sda1 | grep -i journal将 journal 移至 SSDsudo tune2fs -j -J device/dev/nvme0n1p1 /dev/sda15.1 三个绝对不能做的“伪操作”不要kill -9kworker它不是用户进程kill信号会被内核忽略ps中 PID 会立即刷新为新值徒增混乱。不要盲目echo 0 /proc/sys/vm/swappiness这只会减少 swap 使用对 kworker 飙升毫无帮助反而可能加剧内存压力导致 OOM。不要rmmod正在使用的驱动模块如rmmod ahci会直接导致系统 panicrmmod nvme会让所有 NVMe 设备离线kworker 会因无法完成 pending work 而永久卡死。5.2 一个被严重低估的调试利器/proc/PID/stack每个 kworker 进程的/proc/PID/stack文件以纯文本形式记录其当前内核栈无需perf即可快速窥探。例如sudo cat /proc/$(pgrep -f kworker/u.*events_power_efficient)/stack输出类似[ffffffffa1234567] process_one_work0x1a7/0x3a0 [ffffffffa1234567] worker_thread0x4a/0x3c0 [ffffffffa1234567] kthread0x113/0x150 [ffffffffa1234567] ret_from_fork0x35/0x40 [ffffffffa1234567] nvme_pci_complete_rq0x45/0x70 [ffffffffa1234567] nvme_complete_rq0x2a/0x50 [ffffffffa1234567] nvme_irq_handler0x1c2/0x2a0这比ps -T -p PID的线程列表直观百倍——它告诉你此刻 kworker 正在执行哪一行内核代码。我习惯把它加入日常巡检脚本#!/bin/bash for pid in $(pgrep -f kworker); do if [ $(cat /proc/$pid/stat | awk {print $14}) -gt 1000000 ]; then # utime 1s echo kworker $pid stack sudo cat /proc/$pid/stack 2/dev/null | head -5 fi done5.3 最后一个建议把 kworker 当作系统的“心电图”它不报警但每一次异常波动都是内核某处血管的微小痉挛。与其等到它飙到 100% 再手忙脚乱不如把它纳入常规监控Zabbix/Prometheus 中采集/proc/interrupts各 CPU 中断数、/sys/kernel/debug/workqueue/*/stats中pending值、/proc/stat中intr总中断数。设置告警阈值pending 100持续 5 分钟或单 CPU 中断数 其他 CPU 均值 3 倍。每次系统升级、驱动更新、BIOS 刷写后必做stress-ng --io 4 --timeout 60s压力测试并用perf top -p $(pgrep kworker)观察火焰图基线。我见过太多团队把 kworker 当作“背景噪音”忽略直到某次磁盘故障导致 journal 积压才在dmesg里翻出三个月前就存在的nvme 0000:01:00.0: completing cmd timed out报错。其实它一直都在说话只是我们没学会听。