CPU问题场景分析
进程的状态
通过top命令可以看到各个进程的状态,这些状态有:
-
R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
-
D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
-
Z 是 Zombie 的缩写,它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
-
S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
-
I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
- T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。
- X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。
向某个进程发送SIGSTOP信号,进程会响应这个信号编程Stop状态。再发送SIGCONT信号,进程会恢复运行。
系统中出现大量僵尸进程
什么情况下会出现僵尸进程?
首先,子进程由父进程fork而来,父进程fork子进程后,会通过两种方式回收子进程的资源。
- 一种是注册SIGCHLD信号处理函数,在子进程退出时会发送SIGCHLD信号给父进程,父进程收到信号后执行钩子函数回收子进程的资源。
- 一种是在fork子进程后,调用wait()或waitpid()等待子进程执行完毕,子进程执行完毕后回收子进程的资源。
如果父进程没有通过以上两种方式处理,或者子进程执行得非常快导致父进程还没来得及调用wait()或者waitpid()函数,子进程就结束了,就会产生僵尸进程。
如果系统出现大量僵尸进程,可以用pstree命令查看进程树,找出是什么进程fork的子进程。进而使用perf对进程的运行进行采样,看看是什么地方fork的子进程,再结合代码分析,找出没有父进程没有回收子进程的原因进行修复。
iowait过高
什么情况下会出现iowait过高?
一种是应用是属于IO密集型应用,本身会频繁进行数据读写,对于此类应用我们需要性能较高的IO设备。如果IO设备本身没有问题,我们需要分析应用什么问题导致了iowait过高。首先通过dstat命令检查下磁盘读写,是不是真的有大量的磁盘IO。
如果有,则需要找出进行IO读写的进程,进而使用perf 或者 strace进行分析。
CPU软中断过高
Linux 将中断处理过程分成了两个阶段,也就是上半部和下半部:
-
上半部由硬件触发,直接处理硬件请求,它在中断屏蔽模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
-
下半部是由内核触发,用来延迟处理上半部未完成的工作,通常以内核线程的方式运行。
上半部分即为硬中断或者硬件中断,下半部分为软中断。上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”,比如说, 0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0。proc 文件系统中记录了中断情况:
-
/proc/softirqs 提供了软中断的运行情况;
-
/proc/interrupts 提供了硬中断的运行情况。
通过如下命令可以查看CPU软中断的变化:
watch -d "cat /proc/softirqs | awk 'NR == 1{printf \"%-15s %-15s %-15s %-15s %-15s\n\",\" \",\$1,\$2,\$3,\$4}; NR > 1{printf \"%-15s %-15s %-15s %-15s %-15s\n\",\$1,\$2,\$3,\$4,\$5}'"
进而观察
浙公网安备 33010602011771号