前言
在系统的日常运维中,最令人头疼的莫过于各种应用程序或者操作系统hung住不响应的问题。对于处在用户态的程序相对来说还比较容易排查,而一旦程序hung在内核态或者操作系统本身hung住,kill信号甚至硬件中断都无法响应,此时我们能做的就只有重启了。然而重启并不能解决根本问题,更麻烦的是这种情况下我们几乎拿不到任何有用的信息,后续原因的分析和排查更是步履维艰。好在Linux内核早已提供了一系列的机制来帮助我们分析此类问题。下面我们就来看下如何配置使用这些机制以及它们的实现原理。
不可中断睡眠
■概念
第一种比较常见的现象是:进程长时间处于D(不可中断睡眠)状态。依赖于它的进程也会因为等待它而阻塞。那么什么是D状态呢?顾名思义:首先它是一种睡眠状态,也就意味着处于此状态的进程不会消耗CPU。其次睡眠的原因是因为等待某些资源(比如锁或者磁盘IO),这也是我们看到非常多D状态的进程都处在处理IO操作的原因。最后一点就是它不能被中断,这个要区别于“硬件中断”的中断,是指不希望在其获取到资源或者超时前被终止。因此他不会被信号唤醒,也就不会响应kill -9这类信号。这也是它跟S(可中断睡眠)状态的区别。
进程进入D状态发生在内核代码或者底层驱动代码中,典型的场景是与硬件进行通信。通常情况下我们可以通过top命令观察到进程快速的的进入退出D状态,但当硬件故障或者驱动bug出现时就会导致进程长时间处于D状态无法退出,依赖或等待它的其他进程都被阻塞卡死。
-
处于D状态的进程
■机制
内核通常会创建一个khungtaskd的守护进程,它会周期性的检查所有进程的状态和上下文切换,进而判断是否有进程长时间处于D状态。我们可以通过配置如下内核参数来控制检测的超时时间、告警打印,以及是否触发panic,以帮助问题的后续分析。
# 超时时间
kernel.hung_task_timeout_secs = 120
# 告警打印的次数
kernel.hung_task_warnings = 10
# 是否触发系统panic
kernel.hung_task_panic = 0
# 检测的最大进程数,系统中进程数超过此值时会忽略超出的部分
kernel.hung_task_check_count = 4194304
-
进程处于D状态的超时打印