Prozessstatus
Über den oberen Befehl können wir den Status des Prozesses sehen (S-Spalte).
top
top - 19:27:57 up 365 days, 25 min, 0 users, load average: 0.06, 0.05, 0.01
Tasks: 134 total, 1 running, 90 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.5 sy, 0.0 ni, 99.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3514764 total, 137136 free, 1193824 used, 2183804 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1965284 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11399 root 20 0 1114904 150016 19564 S 1.0 4.3 537:19.31 YDService
9951 ubuntu 20 0 1142180 261916 36424 S 0.7 7.5 0:44.05 node
15178 ubuntu 20 0 41144 3700 3032 R 0.3 0.1 0:00.06 top
30256 root 20 0 64552 11232 3632 S 0.3 0.3 41:52.93 barad_agent
30257 root 20 0 588648 20356 4840 S 0.3 0.6 316:58.21 barad_agent
1 root 20 0 225544 7596 4920 S 0.0 0.2 19:35.77 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:13.93 kthreadd
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H
Der Status des Prozesses ist wie folgt:
-
R ist die Abkürzung für Running oder Runnable, was bedeutet, dass der Prozess ausgeführt wird oder in der Bereitschaftswarteschlange der CPU auf die Ausführung wartet.
-
D ist die Abkürzung für Disk Sleep, also ununterbrochener Ruhezustand (Uninterruptible Sleep), was im Allgemeinen bedeutet, dass der Prozess mit der Hardware interagiert und der Interaktionsprozess nicht durch andere Prozesse oder Interrupts unterbrochen werden darf.
-
Z ist die Abkürzung für Zombie, also den Zombie-Zustand. Der Prozess ist tatsächlich beendet, aber der übergeordnete Prozess hat seine Ressourcen (z. B. Prozessdeskriptor, PID usw.) nicht zurückgefordert.
-
S ist die Abkürzung für Interruptible Sleep, also unterbrechbaren Zustandsschlaf, was bedeutet, dass der Prozess vom System angehalten wird, weil es auf ein Ereignis wartet. Wenn das Ereignis eintritt, auf das der Prozess wartet, wacht er auf und wechselt in den R-Zustand.
-
I ist die Abkürzung für Idle, also den Ruhezustand, der für Kernel-Threads verwendet wird, die den Ruhezustand nicht unterbrechen können. Wie oben erwähnt, wird der durch Hardware-Interaktion verursachte unterbrechungsfreie Prozess durch D dargestellt, aber für einige Kernel-Threads sind sie möglicherweise nicht wirklich ausgelastet, und Leerlauf wird zur Unterscheidung dieser Situation verwendet. Beachten Sie, dass Prozesse im D-Zustand den Lastdurchschnitt erhöhen, Prozesse im I-Zustand jedoch nicht.
-
T oder t, die Abkürzung für Stopped oder Traced, bedeutet, dass sich der Prozess in einem angehaltenen oder verfolgten Zustand befindet. Senden Sie ein SIGSTOP-Signal an einen Prozess, und er wird als Reaktion auf dieses Signal angehalten (gestoppt). Senden Sie ein SIGCONT-Signal an ihn, und der Prozess wird wieder ausgeführt. Und wenn Sie einen Debugger (z. B. GDB) zum Debuggen eines Prozesses verwenden, wechselt der Prozess nach der Verwendung eines Haltepunkts zum Unterbrechen des Prozesses in einen Ablaufverfolgungszustand, der eigentlich ein spezieller Pausenzustand ist, aber Sie können den Debugger zum Verfolgen verwenden Und Steuern Sie den Ablauf des Prozesses nach Bedarf.
-
X, kurz für Dead, bedeutet, dass der Prozess tot ist, sodass Sie ihn nicht in den Befehlen top oder ps sehen.
unterbrechungsfreier Zustand
Schauen Sie sich zunächst den unterbrechungsfreien Zustand an, der eigentlich sicherstellen soll, dass die Prozessdaten mit dem Hardware-Zustand übereinstimmen. Unter normalen Umständen endet der unterbrechungsfreie Zustand in kurzer Zeit. Daher können wir den kurzfristigen unterbrechungsfreien Zustandsprozess im Allgemeinen ignorieren.
但如果系统或硬件发生了故障,进程可能会在不可中断状态保持很久,甚至导致系统中出现大量不可中断进程。这时,你就得注意下,系统是不是出现了 I/O 等性能问题。
僵尸进程
僵尸进程,这是多进程应用很容易碰到的问题。正常情况下,当一个进程创建了子进程后,它应该通过系统调用 wait() 或者 waitpid() 等待子进程结束,回收子进程的资源;而子进程在结束时,会向它的父进程发送 SIGCHLD 信号,所以,父进程还可以注册 SIGCHLD 信号的处理函数,异步回收资源。
如果父进程没这么做,或是子进程执行太快,父进程还没来得及处理子进程状态,子进程就已经提前退出,那这时的子进程就会变成僵尸进程。
通常,僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡;或者在父进程退出后,由 init 进程回收后也会消亡。一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。
大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建,所以这种情况一定要避免。
iowait 分析
我们先用dstat分析一下数据
# 间隔1秒输出10组数据
dstat 1 10
You did not select any stats, using -cdngy by default.
--total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai stl| read writ| recv send| in out | int csw
0 0 99 0 0|3880B 47k| 0 0 | 0 0 | 379 1240
1 2 98 0 0| 0 0 |1332B 2039B| 0 0 | 884 1683
2 3 95 0 0| 0 0 |1158B 3065B| 0 0 |1066 2113
2 1 96 1 0| 0 384k|2548B 3323B| 0 0 |1018 1991
0 0 100 0 0| 0 0 | 364B 380B| 0 0 | 616 1166
1 0 99 0 0| 0 0 | 986B 1016B| 0 0 | 739 1432
1 1 98 0 0| 0 0 |1304B 5305B| 0 0 | 775 1659
1 1 98 0 0| 0 0 |1950B 909B| 0 0 | 764 1450
1 1 98 0 0| 0 68k|2898B 4832B| 0 0 | 799 1423
1 1 98 0 0| 0 0 | 856B 1088B| 0 0 | 667 1382
pidstat 查看IO
# -d 展示 I/O 统计数据,-p 指定进程号,间隔 1 秒输出 10 组数据
pidstat -d -p 9951 1 10
Linux 4.15.0-180-generic (VM-0-11-ubuntu) 08/04/2023 _x86_64_ (2 CPU)
07:40:23 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
07:40:24 PM 500 9951 0.00 0.00 0.00 0 node
07:40:25 PM 500 9951 0.00 0.00 0.00 0 node
07:40:26 PM 500 9951 0.00 0.00 0.00 0 node
07:40:27 PM 500 9951 0.00 0.00 0.00 0 node
07:40:28 PM 500 9951 0.00 0.00 0.00 0 node
07:40:29 PM 500 9951 0.00 0.00 0.00 0 node
07:40:30 PM 500 9951 0.00 0.00 0.00 0 node
07:40:31 PM 500 9951 0.00 0.00 0.00 0 node
07:40:32 PM 500 9951 0.00 0.00 0.00 0 node
07:40:33 PM 500 9951 0.00 0.00 0.00 0 node
Average: 500 9951 0.00 0.00 0.00 0 node
如果无法定位,可以去掉进程号看所有的进程,观察现象
# 间隔 1 秒输出多组数据 (这里是 20 组)
pidstat -d 1 20
通过 strace 进行跟踪
上一步拿到 pid 后可以用 strace 进行跟踪
sudo strace -p 11399
strace: Process 11399 attached
epoll_wait(11, [{EPOLLIN, {u32=40982992, u64=40982992}}], 16, 120000) = 1
read(13, ".\0\0\0(\0\0\0X\10\20\20\1j 1a44f465a3554d4f9"..., 262144) = 138
read(13, 0x7fff7523a380, 262144) = -1 EAGAIN (Resource temporarily unavailable)
nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0
epoll_wait(11, [{EPOLLIN, {u32=40982992, u64=40982992}}], 16, 120000) = 1
read(13, ".\0\0\0(\0\0\0X\10\20\20\1j 2b7e857880da41f8b"..., 262144) = 138
read(13, 0x7fff7523a380, 262144) = -1 EAGAIN (Resource temporarily unavailable)
nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0
epoll_wait(11,
ps检查进程状态
ps aux | grep 11399
root 11399 0.7 4.2 1114904 149348 ? Sl Jun13 537:27 /usr/local/qcloud/YunJing/YDEyes/YDService
ubuntu 23898 0.0 0.0 13776 1104 pts/4 S+ 19:46 0:00 grep --color=auto 11399
如果以上方案都不行,就要用基于事件记录的动态追踪工具。
perf top 或 perf record
pref top -g
pref record -g
pref report
处理僵尸进程
找僵尸进程父进程
# -a 表示输出命令行选项
# p表PID
# s表示指定进程的父进程
pstree -aps 11399
systemd,1 --switched-root --system --deserialize 32
└─YDLive,7059
└─YDService,11399
├─sh,11521 -c sleep 100
│ ├─{sh},11523
│ ├─{sh},11524
│ ├─{sh},11525
│ ├─{sh},11526
│ ├─{sh},11527
│ ├─{sh},11528
│ ├─{sh},11530
│ └─{sh},9989
├─{YDService},11400
├─{YDService},11401
├─{YDService},11402
├─{YDService},11403
├─{YDService},11404
├─{YDService},11405
├─{YDService},11406
├─{YDService},11407
├─{YDService},11408
├─{YDService},11428
├─{YDService},11434
├─{YDService},11450
├─{YDService},11451
├─{YDService},11455
├─{YDService},11456
├─{YDService},11457
├─{YDService},11466
├─{YDService},11467
├─{YDService},11468
├─{YDService},11483
├─{YDService},11485
├─{YDService},11522
└─{YDService},4319
再处理父进程就可以了。
小结
iowait 高不一定代表 I/O 有性能瓶颈。当系统中只有 I/O 类型的进程在运行时,iowait 也会很高,但实际上,磁盘的读写远没有达到性能瓶颈的程度。
因此,碰到 iowait 升高时,需要先用 dstat、pidstat 等工具,确认是不是磁盘 I/O 的问题,然后再找是哪些进程导致了 I/O。
等待 I/O 的进程一般是不可中断状态,所以用 ps 命令找到的 D 状态(即不可中断状态)的进程,多为可疑进程。有时在 I/O 操作后,进程又变成了僵尸进程,所以不能用 strace 直接分析这个进程的系统调用。这种情况下,需要用 perf 工具,来分析系统的 CPU 时钟事件,最终发现是直接 I/O 导致的问题。这时,再检查源码中对应位置的问题,就很轻松了。而僵尸进程的问题相对容易排查,使用 pstree 找出父进程后,去查看父进程的代码,检查 wait() / waitpid() 的调用,或是 SIGCHLD 信号处理函数的注册就行了。