Linux 性能优化实战(倪朋飞)---系统中出现大量不可中断进程和僵尸进程怎么办?

进程状态

可通过 top 或 ps 查看进程状态。

$ top

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND    
 4480 yjp       20   0  663624  34740  27508 S   0.3  1.9   0:01.26 gnome-term+ 
 5518 yjp       20   0   43536   3768   3232 R   0.3  0.2   0:00.08 top  

S 列表示进程的状态。

  • R:Running 或 Runnable,进程在 CPU 的就绪队列中,正在运行或等待运行。
  • D:Disk Sleep,不可中断状态睡眠,一般表示进程正在与硬件交互,并且交互过程不允许被其它进程中断或打断。
  • Z:Zombie,僵尸进程,进程已经结束,但父进程还没有回收其资源,如进程描述符、PID 等。
  • S:Interruptible Sleep,可中断状态睡眠,表示进程因为等待某个事件而被挂起。
  • I:Idle,空闲状态,用在不可中断睡眠的内核线程上。
  • T 或 t:Stoped 或 Traced,表示进程处于暂停或跟踪状态。

案例分析

案例:https://github.com/feiskyer/linux-perf-examples/blob/master/high-iowait-process/README.md

运行案例

docker run --privileged --name=app -itd feisky/app:iowait

确认案例应用启动

$ ps aux | grep /app
root      6051  0.0  0.0   4512  1520 pts/0    Ss+  19:35   0:00 /app
root      6258  3.5  3.6  70052 66068 pts/0    D+   19:39   0:00 /app
root      6259  2.0  3.6  70052 66068 pts/0    D+   19:39   0:00 /app
root      6260  2.0  3.6  70052 66064 pts/0    D+   19:39   0:00 /app
yjp       6262  0.0  0.0  15960   940 pts/4    S+   19:39   0:00 grep --color=auto /app

后面的 s 表示该进程是一个会话的领导进程,+ 表示前台进程组。
进程组标表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员。
会话指共享同一个控制终端的一个或多个进程组。

查看系统资源使用情况

# 按下数字 1 切换到所有 CPU 的使用情况,观察一会儿按 Ctrl+C 结束
$ top

top - 19:41:10 up  2:48,  1 user,  load average: 2.68, 2.26, 1.07
Tasks: 324 total,   1 running, 179 sleeping,   0 stopped, 144 zombie
%Cpu0  :  1.8 us,  3.3 sy,  0.0 ni, 27.6 id, 65.4 wa,  0.0 hi,  1.8 si,  0.0 st
%Cpu1  :  2.1 us,  5.1 sy,  0.0 ni, 35.2 id, 56.4 wa,  0.0 hi,  1.3 si,  0.0 st
KiB Mem :  1789476 total,   479536 free,   732760 used,   577180 buff/cache
KiB Swap:  1533948 total,  1526512 free,     7436 used.   836700 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND     
 6308 root      20   0       0      0      0 Z   7.5  0.0   0:00.31 app         
 4066 yjp       20   0 1247376  81264  47124 S   4.9  4.5   1:27.33 compiz      
 1449 root      20   0  455808  69676  31716 S   4.6  3.9   0:52.98 Xorg        
 6307 root      20   0       0      0      0 Z   2.9  0.0   0:00.21 app         
 6309 yjp       20   0   43668   3972   3432 R   1.6  0.2   0:00.08 top  
 6310 root      20   0   70052  66072    612 D   0.7  3.7   0:00.02 app         
 6311 root      20   0   70052  66072    612 D   0.7  3.7   0:00.02 app 
  • 第一行,平均负载在升高,而 1 分钟的平均负载已超 CPU 个数,说明系统可能有了性能瓶颈。
  • 第二行的 Tasks,有 1 个正在运行的进程,但僵尸进程比较多,且在增加,说明有子进程退出时没被清理。
  • 第三行,用户 CPU 和系统 CPU 都不高,但 iowait 分别是 65.4%,56.4%
  • 有两个进程处于 D 状态,可能在等待 I/O

iowait 分析

# 间隔 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 hiq siq| read  writ| recv  send|  in   out | int   csw 
  8   1  83   8   0   0|  45M   66k|   0     0 |  27B  704B| 352   698 
  1   3  59  38   0   0|  59M    0 |   0   278B|   0     0 | 451   800 
  1   2   0  97   0   0| 104M    0 |  60B   60B|   0     0 | 561   927 
  1   2   0  90   0   7| 636M   48k|   0     0 |   0     0 |1319  1094 
  2   6  11  73   0   8| 548M    0 |   0   107B|   0     0 |1291   777 
  4   8  27  47   0  13| 749M    0 |   0     0 |   0     0 |1938   957 

每当 iowait 升高(wai)时,磁盘的读请求(read)都会很大,可能是磁盘读请求导致。

查找读磁盘的进程

$ top

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                           
 7563 root      20   0       0      0      0 Z   4.3  0.0   0:00.25 app                               
 7564 root      20   0       0      0      0 Z   4.0  0.0   0:00.16 app                               
   16 root      20   0       0      0      0 S   3.3  0.0   0:17.35 ksoftirqd/1                       
 1449 root      20   0  459928  73636  31716 S   3.0  4.1   1:05.10 Xorg                              
 4066 yjp       20   0 1247376  81800  47236 S   3.0  4.6   1:47.70 compiz                            
 7566 root      20   0   70052  65968    476 D   1.7  3.7   0:00.05 app                               
 7567 root      20   0   70052  65968    476 D   1.3  3.7   0:00.04 app       

有两个 D 状态的进程,PID 分别为 7566 和 7567。

# -d 展示 I/O 统计数据,-p 指定进程号,间隔 1 秒输出 3 组数据
$ pidstat -d -p 7566 1 3
Linux 4.13.0-45-generic (yjp-VirtualBox) 	2019年04月28日 	_x86_64_	(2 CPU)

20时00分53秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
20时00分54秒     0      7566      0.00      0.00      0.00       0  app
20时00分55秒     0      7566      0.00      0.00      0.00       0  app
20时00分56秒     0      7566      0.00      0.00      0.00       0  app
Average:        0      7566      0.00      0.00     0.00       0  app

但发现进程 7566 没有 I/O 读写,进程 7567 同样。

干脆查看所有进程的 I/O 读写:

# 间隔 1 秒输出多组数据 (这里是 20 组)
$ pidstat -d 1 20
...
06:48:46      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:47        0      4615      0.00      0.00      0.00       1  kworker/u4:1
06:48:47        0      6080  32768.00      0.00      0.00     170  app
06:48:47        0      6081  32768.00      0.00      0.00     184  app

06:48:47      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:48        0      6080      0.00      0.00      0.00     110  app

06:48:48      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:49        0      6081      0.00      0.00      0.00     191  app

06:48:49      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command

06:48:50      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:51        0      6082  32768.00      0.00      0.00       0  app
06:48:51        0      6083  32768.00      0.00      0.00       0  app

06:48:51      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:52        0      6082  32768.00      0.00      0.00     184  app
06:48:52        0      6083  32768.00      0.00      0.00     175  app

06:48:52      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:48:53        0      6083      0.00      0.00      0.00     105  app
...

是 app 进行磁盘读写,查看其系统调用:

$ strace -p 6082
strace: attach: ptrace(PTRACE_SEIZE, 6082): Operation not permitted

已经是 root 权限了,可能是进程状态不正常:

$ ps aux | grep 6082
root      6082  0.0  0.0      0     0 pts/0    Z+   13:43   0:00 [app] <defunct>

使用基于事件记录的动态工具:

$ perf record -g
$ perf report

在这里插入图片描述
app 通过 sys_read 读数据,从 new_sync_read 和 blkdev_direct_IO 看出,对磁盘进行直接读,导致 iowait 升高。

查看源码 app.c:

open(disk, O_RDONLY|O_DIRECT|O_LARGEFILE, 0755)

删除 O_DIRECT 即可。

重新运行:

# 首先删除原来的应用
$ docker rm -f app
# 运行新的应用
$ docker run --privileged --name=app -itd feisky/app:iowait-fix1

检查:

$ top
top - 14:59:32 up 19 min,  1 user,  load average: 0.15, 0.07, 0.05
Tasks: 137 total,   1 running,  72 sleeping,   0 stopped,  12 zombie
%Cpu0  :  0.0 us,  1.7 sy,  0.0 ni, 98.0 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  1.3 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
...

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3084 root      20   0       0      0      0 Z   1.3  0.0   0:00.04 app
 3085 root      20   0       0      0      0 Z   1.3  0.0   0:00.04 app
    1 root      20   0  159848   9120   6724 S   0.0  0.1   0:09.03 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.00 kthreadd
    3 root      20   0       0      0      0 I   0.0  0.0   0:00.40 kworker/0:0
...

僵尸进程

僵尸进程是因为父进程没有回收子进程资源导致的,因此需找出父进程。

# -a 表示输出命令行选项
# p 表 PID
# s 表示指定进程的父进程
$ pstree -aps 3084
systemd,1
  └─dockerd,15006 -H fd://
      └─docker-containe,15024 --config /var/run/docker/containerd/containerd.toml
          └─docker-containe,3991 -namespace moby -workdir...
              └─app,4009
                  └─(app,3084)

查看 app.c:

int status = 0;
  for (;;) {
    for (int i = 0; i < 2; i++) {
      if(fork()== 0) {
        sub_process();
      }
    }
    sleep(5);
  }

  while(wait(&status)>0);

将 wait() 放在 for 死循环内即可。

然后重新启动容器,并用 top 进行检查:

# 先停止产生僵尸进程的 app
$ docker rm -f app
# 然后启动新的 app
$ docker run --privileged --name=app -itd feisky/app:iowait-fix2
$ top
top - 15:00:44 up 20 min,  1 user,  load average: 0.05, 0.05, 0.04
Tasks: 125 total,   1 running,  72 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  1.7 sy,  0.0 ni, 98.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  1.3 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
...

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3198 root      20   0    4376    840    780 S   0.3  0.0   0:00.01 app
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.00 kthreadd
    3 root      20   0       0      0      0 I   0.0  0.0   0:00.41 kworker/0:0
...

参考
倪朋飞. Linux 性能优化实战.

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值