模拟一个不可kill的D状态进程
我们在排查线上故障,有时需要编写脚本或者配置监控 找出 D 进程 ,此时我们可能需要有一个模拟环境来调试程序。那么,怎么在Linux环境下模拟出一个D进程呢?
由于大多数 D
进程都和存储有关,所以模拟出存储故障就能 制造 出 D
进程:
在主机(VM)上挂载NFS,然后 故意 将NFS服务端关闭
在主机(VM)上读写虚拟磁盘,然后将虚拟磁盘移除
但是上述操作磁盘的方法都比较 沉重 ,容易引发不好处理的故障
Simulate an unkillable process in D state 有人提供了一个非常巧妙的方法:
使用 vfork
系统调用: vfork
类似 fork
,但是因为预期 exec
只会丢弃复制的数据,地址空间不会从父进程复制到子进程。这样当 vfork
时,父进程 uninterruptibly
地等待子进程的 exec
或 exit
,就能模拟出 D
状态。
uninterruptible.c
:
模拟D进程的 uninterruptible.c
int main() {
vfork();
sleep(60);
return 0;
}
备注
这里调整源代码 sleep(60)
可以延长模拟 D
状态时间
编译:
gcc -o uninterruptible uninterruptible.c
此时执行进程 uninterruptible
就会 D
住直到60秒睡眠时间结束自动退出,并且这个 D
住的进程实际上是可以 kill
的(另外开一个终端窗口执行如下),不会导致线上故障:
$ ps r -A
PID TTY STAT TIME COMMAND
111138 pts/1 D+ 0:00 ./uninterruptible
111142 pts/5 R+ 0:00 ps r -A
$ kill 111138
$ ps r -A
PID TTY STAT TIME COMMAND
111143 pts/5 R+ 0:00 ps r -A
可以在通过以下方式将 uninterruptible
批量放到后台运行, 就能模拟出大规模的 D
进程:
for i in {0..10};do (./uninterruptible &);done
模拟出load极高的系统故障:
$ ps r -A
PID TTY STAT TIME COMMAND
111261 pts/1 D 0:00 ./uninterruptible
111263 pts/1 D 0:00 ./uninterruptible
111265 pts/1 D 0:00 ./uninterruptible
111267 pts/1 D 0:00 ./uninterruptible
111269 pts/1 D 0:00 ./uninterruptible
111271 pts/1 D 0:00 ./uninterruptible
111273 pts/1 D 0:00 ./uninterruptible
111275 pts/1 D 0:00 ./uninterruptible
111277 pts/1 D 0:00 ./uninterruptible
111279 pts/1 D 0:00 ./uninterruptible
111281 pts/1 D 0:00 ./uninterruptible
111285 pts/1 R+ 0:00 ps r -A
$ uptime
17:46:25 up 17 days, 6:15, 4 users, load average: 7.02, 2.06, 0.73