linux负载高进程,top命令引起系统负载升高
发布日期:2021-06-24 13:22:52 浏览次数:2 分类:技术文章

本文共 3020 字,大约阅读时间需要 10 分钟。

Linux系统环境:CentOS 6.5 x86_64

一、问题表现

系统负载升高,某一个核的cpu资源被top进程耗尽,如下图所示:

913ea8c10338b1843b7269b2b94ca01f.png

二、分析过程

1.通过strace命令打印top进程信息,出现大量重复的系统调用,如下:

cb3c9809838e49ea8610ac7bc66efb20.png

查看top进程的fd信息如下:

b12a0d5c6c087d22cea11cc9c6b080f0.png

通过以上信息推断,top进程的输入输出异常,触发select返回文件描述符,但是文件描述符未处理或处理不当造成select无限触发,陷入死循环,占用一个核的cpu资源。

2.下载procps-3.2.8查看top源码,在第3398行找到了相关调用。如代码所示标准输入被放到了select调用里,因为标准输入错误导致触发select返回fd,无tv时长的等待。

3.

long file_flags;

int rc;

char c;

fd_set fs;

FD_ZERO(&fs);

FD_SET(STDIN_FILENO, &fs);

file_flags = fcntl(STDIN_FILENO, F_GETFL);

if(file_flags==-1) file_flags=0;

fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK|file_flags);

// check 1st, in case tv zeroed (by sig handler) before it got set

rc = chin(0, &c, 1);

if (rc <= 0) {

// EOF is pretty much a "can't happen" except for a kernel bug.

// We should quickly die via SIGHUP, and thus not spin here.

// if (rc == 0) end_pgm(0); /* EOF from terminal */

fcntl(STDIN_FILENO, F_SETFL, file_flags);

select(1, &fs, NULL, NULL, &tv);

fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK|file_flags);

}

if (chin(0, &c, 1) > 0) {

fcntl(STDIN_FILENO, F_SETFL, file_flags);

do_key((unsigned)c);

} else {

fcntl(STDIN_FILENO, F_SETFL, file_flags);

}

4.标准输入的处理代码如下:

static int chin (int ech, char *buf, unsigned cnt)

{

int rc;

fflush(stdout);

if (!ech)

rc = read(STDIN_FILENO, buf, cnt);

else {

tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);

rc = read(STDIN_FILENO, buf, cnt);

tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);

}

// may be the beginning of a lengthy escape sequence

tcflush(STDIN_FILENO, TCIFLUSH);

return rc;                  // note: we do NOT produce a vaid 'string'

}

5.rc为read返回值,分三类返回正的字节数、0(表示到达文件末尾)、返回负值-1(表示出错)。源码中 rc==0的情况被注掉了(如下图)造成标准输入fd未处理,select的超时未生效。

b1d722c0c2f318f35ba4ea356b4392a9.png

6.top在运行时出现标准输入异常这种情况一般是很难发生的,通过ps -fe 打印出了top的进程关系如下:

cf53e67f3672504a4a1ac781200219c3.png

sudo 进程的pid变成1了,通过 ssh -t ‘strace -o sudo.strace sudo -i’  抓取信息如下:

dd562f9b8747895fdd5cc2d809c57628.png

在终端异常关闭(断网)后,并未退出,将父进程设成1继续运行。

7.经测试在ssh -t ‘sudo -i’ 这种方式登陆,sudo的父进程是sshd,当终端异常关闭时sudo会将自己的父进程改为1继续运行。正常登陆后在运行sudo的,sudo的父进程一般为bash(也可能是其他shell),不会出现类似情况。

三、总结

因线上环境很多操作需要切换到root,为了方便在ssh登陆的时候加上了 -t ‘sudo -i’ 的参数,从而导致了悲剧的发生。捷径随好但要小心陷阱,一不小心就可能酿成大错。

注:

1.setsid top 或者其他守护进程调用top,当终端异常退出引起标准输入错误时都会造成top异常。

2.Ubuntu系统不存在此问题,debian修复了此问题。

nicai@bugaosuni:~/procps-3.2.8/debian/patches$ cat top_stdin_eof.patch

Description: Check for stdin eof if term

Author: Samuel Thibault

Bug-Debian: http://bugs.debian.org/458986

Reviewed-by: Craig Small

Index: b/top.c

===================================================================

--- a/top.c    2009-11-24 21:00:34.000000000 +1100

+++ b/top.c    2009-11-24 21:00:35.000000000 +1100

@@ -3408,9 +3408,8 @@

// check 1st, in case tv zeroed (by sig handler) before it got set

rc = chin(0, &c, 1);

if (rc <= 0) {

-            // EOF is pretty much a "can't happen" except for a kernel bug.

-            // We should quickly die via SIGHUP, and thus not spin here.

-            // if (rc == 0) end_pgm(0); /* EOF from terminal */

+            if (rc == 0) end_pgm(0); /* EOF from terminal, may happen if top

+                                      * erroneously gets detached from it. */

fcntl(STDIN_FILENO, F_SETFL, file_flags);

select(1, &fs, NULL, NULL, &tv);

fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK|file_flags);

nicai@bugaosuni:~/procps-3.2.8/debian/patches$

0b1331709591d260c1c78e86d0c51c18.png

转载地址:https://blog.csdn.net/weixin_33102135/article/details/116629428 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:linux dts spiflash分区,dts中修改SPI,如何实现SPI平台数据在dts中的实现?
下一篇:linux用户模式驱动,linux操作系统的单用户模式是什么?

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月14日 11时18分20秒