当前位置:   article > 正文

Linux 进程状态D Disk Sleep_内核state:d

内核state:d

 

Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态


处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。

通过ps命令我们会看到,一般情况下,进程列表中的绝大多数进程都处于TASK_INTERRUPTIBLE状态(除非机器的负载很高)。毕竟CPU就这么一两个,进程动辄几十上百个,如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来。

 

Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态


与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。

绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill -9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么ps命令看到的进程几乎不会出现TASK_UNINTERRUPTIBLE状态,而总是TASK_INTERRUPTIBLE状态。

而TASK_UNINTERRUPTIBLE状态存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。

在进程对某些硬件进行操作时(比如进程调用read系统调用对某个设备文件进行读操作,而read系统调用最终执行到对应设备驱动的代码,并与对应的物理设备进行交互),可能需要使用TASK_UNINTERRUPTIBLE状态对进程进行保护,以避免进程与设备交互的过程被打断,造成设备陷入不可控的状态。这种情况下的TASK_UNINTERRUPTIBLE状态总是非常短暂的,通过ps命令基本上不可能捕捉到。

不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的I/O响应,也就是我们在ps命令中看到的D状态(Uninterruptible Sleep,也称为Disk Sleep)的进程。

比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。

所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。
 

linux系统中也存在容易捕捉的TASK_UNINTERRUPTIBLE状态。执行vfork系统调用后,父进程将进TASK_UNINTERRUPTIBLE状态,直到子进程调用exit或exec 通过下面的代码就能得到处于TASK_UNINTERRUPTIBLE状态的进程:

  1. [root@localhost ~]# cat test.c 
  2. void main() {  
  3. if (!vfork()) sleep(100);  
  4. [root@localhost ~]# gcc -o test  test.c
  5. [root@localhost ~]# ./test 
  6. [root@localhost ~]# ps -aux | grep test
  7. root      19454  0.0  0.0   4212   352 pts/6    D+   10:02   0:00 ./test
  8. root      19455  0.0  0.0   4212   352 pts/6    S+   10:02   0:00 ./test

 

进程为什么会被置于uninterruptible sleep状态呢?


处于uninterruptiblesleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了(由down掉的NFS服务器引起的D状态)。

正是因为得不到IO的相应,进程才进入了uninterruptible sleep状态,所以要想使进程从uninterruptible sleep状态恢复,就得使进程等待的IO恢复,比如如果是因为从远程挂载的NFS卷不可访问导致进程进入uninterruptible sleep状态的,那么可以通过恢复该NFS卷的连接来使进程的IO请求得到满足。

 

D状态,往往是由于 I/O 资源得不到满足,而引发等待


在内核源码 fs/proc/array.c 里,其文字定义为“ "D (disk sleep)", /* 2 */ ”(由此可知 D 原是Disk的打头字母),对应着 include/linux/sched.h 里的“ #define TASK_UNINTERRUPTIBLE 2 ”。举个例子,当 NFS 服务端关闭之时,若未事先 umount 相关目录,在 NFS 客户端执行 df 就会挂住整个登录会话,按 Ctrl+C 、Ctrl+Z 都无济于事。断开连接再登录,执行 ps axf 则看到刚才的 df 进程状态位已变成了 D ,kill -9 无法杀灭。正确的处理方式,是马上恢复 NFS 服务端,再度提供服务,刚才挂起的 df 进程发现了其苦苦等待的资源,便完成任务,自动消亡。若 NFS 服务端无法恢复服务,在 reboot 之前也应将 /etc/mtab 里的相关 NFS mount 项删除,以免 reboot 过程例行调用 netfs stop 时再次发生等待资源,导致系统重启过程挂起。

 

Nginx举例一则,只是举个例子大概看看就行


第二客户端机器我们将运行另一个副本的wrk,但是这个脚本我们使用50的并发连接来请求相同的文件。因为这个文件被经常访问的,它将保持在内存中。在正常情况下,NGINX很快的处理这些请求,但是工作线程如果被其他的请求阻塞性能将会下降。所以我们暂且叫它“加载恒定负载”。

性能将由服务器上ifstat监测的吞吐率(throughput)和从第二台客户端获取的wrk结果来度量。

现在,没有线程池的第一次运行不会给我们带来非常令人兴奋的结果:

  1. % ifstat -bi eth2
  2. eth2
  3. Kbps in Kbps out
  4. 5531.24 1.03e+06
  5. 4855.23 812922.7
  6. 5994.66 1.07e+06
  7. 5476.27 981529.3
  8. 6353.62 1.12e+06
  9. 5166.17 892770.3
  10. 5522.81 978540.8
  11. 6208.10 985466.7
  12. 6370.79 1.12e+06
  13. 6123.33 1.07e+06

如你所见,上述的配置可以产生一共1G的流量,从top命令上我们可以看到所有的工作线程在阻塞io上花费了大量的时间(下图D状态):

  1. top - 10:40:47 up 11 days, 1:32, 1 user, load average: 49.61, 45.77 62.89
  2. Tasks: 375 total, 2 running, 373 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 0.0 us, 0.3 sy, 0.0 ni, 67.7 id, 31.9 wa, 0.0 hi, 0.0 si, 0.0 st
  4. KiB Mem: 49453440 total, 49149308 used, 304132 free, 98780 buffers
  5. KiB Swap: 10474236 total, 20124 used, 10454112 free, 46903412 cached Mem
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 4639 vbart 20 0 47180 28152 496 D 0.7 0.1 0:00.17 nginx
  8. 4632 vbart 20 0 47180 28196 536 D 0.3 0.1 0:00.11 nginx
  9. 4633 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.11 nginx
  10. 4635 vbart 20 0 47180 28136 480 D 0.3 0.1 0:00.12 nginx
  11. 4636 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.14 nginx
  12. 4637 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.10 nginx
  13. 4638 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
  14. 4640 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
  15. 4641 vbart 20 0 47180 28324 540 D 0.3 0.1 0:00.13 nginx
  16. 4642 vbart 20 0 47180 28208 536 D 0.3 0.1 0:00.11 nginx
  17. 4643 vbart 20 0 47180 28276 536 D 0.3 0.1 0:00.29 nginx
  18. 4644 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.11 nginx
  19. 4645 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.17 nginx
  20. 4646 vbart 20 0 47180 28204 536 D 0.3 0.1 0:00.12 nginx
  21. 4647 vbart 20 0 47180 28208 532 D 0.3 0.1 0:00.17 nginx
  22. 4631 vbart 20 0 47180 756 252 S 0.0 0.1 0:00.00 nginx
  23. 4634 vbart 20 0 47180 28208 536 D 0.0 0.1 0:00.11 nginx<
  24. 4648 vbart 20 0 25232 1956 1160 R 0.0 0.0 0:00.08 top
  25. 25921 vbart 20 0 121956 2232 1056 S 0.0 0.0 0:01.97 sshd
  26. 25923 vbart 20 0 40304 4160 2208 S 0.0 0.0 0:00.53 zsh

在这种情况下,吞吐率受限于磁盘子系统,而CPU在大部分时间里是空转状态的。从wrk获得的结果来看也非常低:

  1. Running 1m test @ http://192.0.2.1:8000/1/1/1
  2. 12 threads and 50 connections
  3. Thread Stats Avg Stdev Max +/- Stdev
  4. Latency 7.42s 5.31s 24.41s 74.73%
  5. Req/Sec 0.15 0.36 1.00 84.62%
  6. 488 requests in 1.01m, 2.01GB read
  7. Requests/sec: 8.08
  8. Transfer/sec: 34.07MB

请记住,文件是从内存送达的!第一个客户端的200个连接创建的随机负载,使服务器端的全部的工作进程忙于从磁盘读取文件,因此产生了过大的延迟,并且无法在合适的时间内处理我们的请求。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/535409
推荐阅读
相关标签
  

闽ICP备14008679号