Was soll ich tun, wenn es im System eine große Anzahl unterbrechungsfreier Prozesse und Zombie-Prozesse gibt?

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 信号处理函数的注册就行了。

Guess you like

Origin blog.csdn.net/TiktokLiveTool/article/details/132115146