调式记录

1. load average 过高 0.8 wa

wa 是磁盘读写等待
用atop -d(按t刷新)或iotop找出哪些进程正在读写磁盘

语法

top(选项)

选项

-b:以批处理模式操作;
-c:显示完整的治命令;
-d:屏幕刷新间隔时间;
-I:忽略失效过程;
-s:保密模式;
-S:累积模式;
-i<时间>:设置间隔时间;
-u<用户名>:指定用户名;
-p<进程号>:指定进程;
-n<次数>:循环显示的次数。

top交互命令

在top命令执行过程中可以使用的一些交互命令。这些命令都是单字母的,如果在命令行中使用了-s选项, 其中一些命令可能会被屏蔽。
h:显示帮助画面,给出一些简短的命令总结说明;
k:终止一个进程;
i:忽略闲置和僵死进程,这是一个开关式命令;
q:退出程序;
r:重新安排一个进程的优先级别;
S:切换到累计模式;
s:改变两次刷新之间的延迟时间(单位为s),如果有小数,就换算成ms。输入0值则系统将不断刷新,默认值是5s;
f或者F:从当前显示中添加或者删除项目;
o或者O:改变显示项目的顺序;
l:切换显示平均负载和启动时间信息;
m:切换显示内存信息;
t:切换显示进程和CPU状态信息;
c:切换显示命令名称和完整命令行;
M:根据驻留内存大小进行排序;
P:根据CPU使用百分比大小进行排序;
T:根据时间/累计时间进行排序;
w:将当前设置写入~/.toprc文件中。

top 命令 VSZ,RSS,TTY,STAT, VIRT,RES,SHR,DATA的含义

  1. VIRTvirtual memory usage 虚拟内存
  2. 1、进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
  3. 2、假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量
  4. RESresident memory usage 常驻内存
  5. 1、进程当前使用的内存大小,但不包括swap out
  6. 2、包含其他进程的共享
  7. 3、如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
  8. 4、关于库占用内存的情况,它只统计加载的库文件所占内存大小
  9. SHRshared memory 共享内存
  10. 1、除了自身进程的共享内存,也包括其他进程的共享内存
  11. 2、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小
  12. 3、计算某个进程所占的物理内存大小公式:RES SHR
  13. 4swap out后,它将会降下来
  14. DATA
  15. 1、数据占用的内存。如果top没有显示,按f键可以显示出来。
  16. 2、真正的该程序要求的数据空间,是真正在运行中要使用的。
  17. top 运行中可以通过 top 的内部命令对进程的显示方式进行控制。内部命令如下:
  18. s 改变画面更新频率
  19. l 关闭或开启第一部分第一行 top 信息的表示
  20. t 关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示
  21. m 关闭或开启第一部分第四行 Mem 第五行 Swap 信息的表示
  22. N PID 的大小的顺序排列表示进程列表
  23. P CPU 占用率大小的顺序排列进程列表
  24. M 以内存占用率大小的顺序排列进程列表
  25. h 显示帮助
  26. n 设置在进程列表所显示进程的数量
  27. q 退出 top
  28. s 改变画面更新周期
  29. 序号 列名 含义
  30. a PID 进程id
  31. b PPID 父进程id
  32. c RUSER Real user name
  33. d UID 进程所有者的用户id
  34. e USER 进程所有者的用户名
  35. f GROUP 进程所有者的组名
  36. g TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
  37. h PR 优先级
  38. i NI nice值。负值表示高优先级,正值表示低优先级
  39. j P 最后使用的CPU,仅在多CPU环境下有意义
  40. k %CPU 上次更新到现在的CPU时间占用百分比
  41. l TIME 进程使用的CPU时间总计,单位秒
  42. m TIME+ 进程使用的CPU时间总计,单位1/100
  43. n %MEM 进程使用的物理内存百分比
  44. o VIRT 进程使用的虚拟内存总量,单位kbVIRT=SWAP+RES
  45. p SWAP 进程使用的虚拟内存中,被换出的大小,单位kb
  46. q RES 进程使用的、未被换出的物理内存大小,单位kbRES=CODE+DATA
  47. r CODE 可执行代码占用的物理内存大小,单位kb
  48. s DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
  49. t SHR 共享内存大小,单位kb
  50. u nFLT 页面错误次数
  51. v nDRT 最后一次写入到现在,被修改过的页面数。
  52. w S 进程状态。(D=不可中断的睡眠状态,R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程)
  53. x COMMAND 命令名/命令行
  54. y WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
  55. z Flags 任务标志,参考 sched.h
  56. 默认情况下仅显示比较重要的 PIDUSERPRNIVIRTRESSHRS、%CPU、%MEMTIME+、COMMAND 列。可以通过下面的快捷键来更改显示内容。
  57. 通过 f 键可以选择显示的内容。按 f 键之后会显示列的列表,按 a-z 即可显示或隐藏对应的列,最后按回车键确定。
  58. o 键可以改变列的显示顺序。按小写的 a-z 可以将相应的列向右移动,而大写的 A-Z 可以将相应的列向左移动。最后按回车键确定。
  59. 按大写的 F O 键,然后按 a-z 可以将进程按照相应的列进行排序。而大写的 R 键可以将当前的排序倒转。

了解 top 的界面 - the summary area

第一小节中 top 的输出界面,我们可以比较明显的看到被分成了两个部分,这个小节中我们将关注在上半部分信息,这部分一般被称之为:summary area

系统时间、正常运行时间和用户会话

  • 系统时间:当前系统的时间(21:07:28)
  • 正常运行:系统运行时长(21 days, 4:31)
  • 活动用户会话个数:1 个
    top - 21:07:28 up 21 days,  4:31,  1 user,
    
    活动用户会话包括 TTYPTY 两种。实际上,如果您通过桌面环境登录到 Linux 系统,然后启动终端模拟器,您将发现将有两个活动会话。

    TTY: 通过命令行或桌面环境在系统上物理地运行 PTY: 终端模拟器窗口或通过 SSH

如果我们期望得到更多关于活动用户会话的信息,可以通过 who 命令来得到,如下:

$ who
admin    pts/0        2020-10-31 17:15 (xx.xx.xx.xx)

w 显示所有连接
剔除用户连接命令
pkill -kill -t pst/1

内存使用情况

Memory 部分显示的是关于系统内存使用情况的信息,如下:

KiB Mem : 33554432 total, 31188208 free,   513488 used,  1852736 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used. 31188208 avail Mem
复制代码

MemSwap 分别显示的是 RAMswap 空间信息;当 RAM 使用率接近满时,RAM 中不经常使用的区域将被写入 Swap 空间,以便稍后需要时检索。但是,由于访问磁盘的速度很慢,过分依赖 Swap 可能会损害系统性能。

关于 Swap

  • 物理内存就是计算机的实际内存大小,由RAM芯片组成的。虚拟内存则是虚拟出来的、使用磁盘代替内存。虚拟内存的出现,让机器内存不够的情况得到部分解决。当程序运行起来由操作系统做具体虚拟内存到物理内存的替换和加载(相应的页与段的虚拟内存管理)。这里的虚拟内存即所谓的 swap;
  • 当用户提交程序,然后产生进程,在机器上运行。机器会判断当前物理内存是否还有空闲允许进程调入内存运行,如果有那么则直接调入内存进行运行;如果没有,那么会根据优先级选择一个进程挂起,把该进程交换到swap中等待,然后把新的进程调入到内存中运行。根据这种换入和换出,实现了内存的循环利用,让用户感觉不到内存的限制。从这也可以看出swap扮演了一个非常重要的角色,就是暂存被换出的进程。
  • 内存与swap之间是按照内存页为单位来交换数据的,一般Linux中页的大小设置为4kb。而内存与磁盘则是按照块来交换数据的

totalfreeused 就是这些单词含义所描述的一样,分别是当前对应空间的总大小、空闲大小、已使用大小。avail mem 值指的是可以分配给进程而不会导致更多的交换的内存量。
Linux 内核层面上总是以不同的方式来尝试减少访问磁盘的次数;它在RAM中维护一个“磁盘缓存(disk cache)”,存储磁盘中经常使用的区域,另外,磁盘写被存储到一个“磁盘缓冲区(disk buffer)”,内核最终将它们写到磁盘上。它们消耗的总内存是 buff/cache 值。这看起来像是一件坏事,但实际上不是,原因是缓存使用的内存将在需要时分配给进程。

任务-Tasks

Tasks 部分显示的是有关系统上运行的进程的统计信息

Tasks:  33 total,   1 running,  31 sleeping,   0 stopped,   1 zombie
复制代码

total 比较好理解,它表示的就是当前系统正在运行的进程总数。但是对于其他几个状态相关的数字,我们需要了解一点 Linux 内核如何处理进程的背景知识。
进程执行是 I/O 限制的工作(如读取磁盘)和 cpu 限制的工作(如执行算术操作)的混合模式。当一个进程执行 I/O 时,CPU 是空闲的,所以 os 在这段时间切换到执行其他进程。此外,该操作系统允许一个给定的进程执行非常短的时间,然后它切换到另一个进程。这就是操作系统“多任务处理”的表现。做所有这些需要我们跟踪流程的“状态”。在 Linux 中,进程可能处于以下状态:

  • 1、Runnable (R): 处于这种状态的进程要么在 CPU 上执行,要么存在于运行队列中,准备执行。
  • 2、Interruptible sleep(S): 处于这种状态的进程在等待事件完成。
  • 3、Uninterruptible sleep (D): 在这种情况下,一个进程正在等待一个 I/O 操作完成。
  • 4、Stopped (T): 这些进程已经被一个作业控制信号(如按 Ctrl+Z)停止,或者因为它们正在被跟踪。
  • 5、Zombie (Z): 僵尸进程

一个进程可以创建许多子进程,当父进程仍然存在时,这些子进程是可以退出的,但是,这些数据结构必须保留下来,直到父进程获得子进程的状态。这种数据结构仍然存在的终止进程称为僵尸进程。D 和 S 状态都是在 top 信息中体现为 sleeping,T 状态体现为 stoppedZ 状态体现为 zombie

CPU 使用情况

CPU 使用情况,显示了在各种任务上花费的 CPU 时间的百分比。

%Cpu(s):  0.3 us,  0.4 sy,  0.0 ni, 90.3 id,  0.0 wa,  0.0 hi,  0.0 si,  9.0 st
复制代码

us指的是 CPU 在用户空间中执行进程所花费的时间。类似地,sy指的就是运行内核空间进程所花费的时间。Linux 中使用 nice 值来表示进程的优先级,值越高,优先级越低,后面我们会了解到,默认的 nice 值是可以被修改的。在手动设置 nice 的情况下,执行进程所花费的时间显示为 ni 值。ni 后面是 id,它是CPU 保持空闲的时间,大多数操作系统在 CPU 空闲时将其设置为“省电模式”。接下来是 wa值,它是 CPU 等待 I/O 完成所花费的时间。
中断(Interrupt)是向处理器发出的有关需要立即关注的事件的信号;外设通常使用硬件中断来告知系统有关事件的信息,例如键盘上的按键。另一方面,软件中断是由于处理器上执行的特定指令而产生的。在这两种情况下,操作系统都将处理它们,处理硬件中断和软件中断所花费的时间分别由hisi给出。
在虚拟化环境中,会将一部分 CPU 资源分配给每个虚拟机(VM)。操作系统会检测到何时有工作要做,如果检测到他需要执行但是由于 CPU 在其他 VM 上繁忙而无法执行时,以这种方式浪费的时间就是“窃取”时间,显示为st

平均负载-Load average

load average 部分表示的是在最近 1、5 和 15 分钟内的系统平均“负载”。

load average: 0.11, 0.07, 0.07
复制代码

负载是对系统执行的计算工作量的度量。在Linux上,负载是在任何给定时刻处于 RD 状态的进程数。load average值为您提供了必须等待多长时间才能完成任务的相对度量。这里有几个小例子,我们来直观的理解下这两个概念。

  • 1、在单核心系统上,load average 为 0.4 意味着系统只完成了它能完成的 40% 的工作。load average为 1 意味着系统正好处于满负荷状态——即使添加一点点额外的工作,系统也会过载。一个 load average 为 2.12 的系统意味着它超载了 112% 的工作,超出了它的处理能力。
  • 2、在多核系统上,应该首先用 load average 除以 CPU 核数,以得到类似的度量。

此外,load average 实际上并不是我们大多数人所知道的典型的平均负载。它是一个“指数移动平均”,这意味着以前的 load average 的一小部分被考虑到当前的值(关于这个点,可以通过这篇文章来了解更多技术细节)。

了解 top 的界面 - the task area

summury area 相对简单,通过它我们可以快速了解到当前系统运行的一些摘要统计信息。但是一个细节性的信息,我们只能通过 task area 中来得到。

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 52601 root      39  19 1310268  14900   9836 S   0.3  0.0  22:59.21 logagent-collec
     1 root      20   0   45416   5244   3968 S   0.0  0.0   5:35.71 systemd
   340 root      20   0   64700  21336  17684 S   0.0  0.1   8:33.90 systemd-journal
   357 root      20   0  101836   2768   2312 S   0.0  0.0   0:01.13 gssproxy
   384 dbus      20   0   28632   2800   2464 S   0.0  0.0   0:00.04 dbus-daemon
   432 root      20   0   84760   5852   4984 S   0.0  0.0   0:00.01 sshd
   461 agent     20   0   52376   5200   3684 S   0.0  0.0   0:00.01 ilogtail
  1690 agent     20   0 2193388 246304  11264 S   0.0  0.7  23:45.88 java
  2527 admin     20   0  161744   4268   3704 R   0.0  0.0   0:00.72 top
  3245 root      20   0  559140  12412   5860 S   0.0  0.0  64:48.67 logagent
  3420 root      20   0  745052  58464  43820 S   0.0  0.2  11:16.32 metricbeat
  3447 root      20   0  957796  55548  43708 S   0.0  0.2  10:14.47 metricbeat
  5093 root      20   0 1905356 159280   9584 S   0.0  0.5  35:00.14 java
  7458 root      20   0   13700   2564   2356 S   0.0  0.0   0:00.00 bash
  7464 root      20   0   86268   4436   3740 S   0.0  0.0   0:00.00 sudo
复制代码

先来说明下各个列的含义:
PID
这是进程ID,一个惟一的正整数,用于标识进程。
USER
这是启动进程的用户的“有效”用户名(映射到用户ID)。Linux 为进程分配一个真实的用户 ID 和一个有效的用户ID;后者允许进程代表另一个用户进行操作。(例如,非 root 用户可以提升到 root 用户来安装软件)
PR NI“NI” 字段显示进程的 “nice” 值,“PR” 字段是从内核的角度显示了进程的调度优先级,“nice” 值影响的是进程的优先级。
VIRT, RES, SHR and %MEM
VIRTRESSHR 这三个字段都与进程的内存消耗有关。VIRT是一个进程所消耗的内存总量。这包括程序代码、进程在内存中存储的数据,以及已经 swap 到磁盘的任何内存区域。RES是进程在 RAM 中消耗的内存,%MEM 表示这个值占总可用 RAM 的百分比。最后,SHR 是与其他进程共享的内存量。
S表示进程状态
TIME+
TIME+ 列表示的是进程自启动以来所使用的总 CPU 时间,精确到百分之一秒。
COMMAND
COMMAND 列表示的是当前进程的名称。

top 命令的使用示例

到目前为止,我们已经讨论了 top 的界面信息所描述的含义。但是,top 除了显示这个信息之外,它还可以管理进程,并且我们可以控制 top 输出的各个方面。在本节中,我们将举几个例子。(在下面的大多数例子中,你必须在 top 运行时按下一个键。这些按键是区分大小写的,所以如果你在大写锁定状态下按了k,你实际上已经按了一个k,但是这个命令并不会工作)

kill 进程

如果你想杀死一个进程,只要在top运行时按k。这将出现一个提示,它将询问进程的进程ID并按enter

PID to signal/kill [default pid = 384]
复制代码

当然上面的这段输出的后面是可以手动输入进程 ID,下面的 34444444444444 就是手动输入的进程ID

PID to signal/kill [default pid = 384] 34444444444444
复制代码

如果保留此空白,top 将使用一个SIGTERM,它允许进程优雅地终止。如果您想强制终止进程,您可以在这里输入SIGKILL。你也可以在这里输入信号号,例如,SIGTERM 的数字是 384,而 SIGKILL 的数字是。如果你将进程ID留空并直接按enter`,它将终止列表中最顶端的进程。正如前面提到的,我们也可以使用箭头键滚动,并通过这种方式更改想要终止的进程。

排序进程列表

使用像 top 这样的工具的一个最常见的原因是找出哪个进程消耗的资源最多。我们可以按以下键排序列表:

  • M:用于按内存使用情况排序
  • P:来按CPU使用率排序
  • N:按进程ID排序
  • T:来按运行时间排序

默认情况下,top 按降序显示所有结果,但是我们可以通过按R键切换到升序。还可以使用 -o 开关对列表进行排序。例如,如果想排序进程的CPU使用量,可以这样做:

top -o %CPU
复制代码

显示线程列表而不是进程列表

前面已经介绍过 Linux 如何在进程之间切换。我们知道,进程是不共享内存或其他资源的,这使得这种切换相当慢。和其他操作系统一样,Linux 支持一种“轻量级”的替代方案,称为“线程”。“线程”是进程的一部分,“线程”可以共享内存和其他资源的某些区域,同时它们也可以像进程一样并发运行。默认情况下,top在其输出中显示一个进程列表。如果想列出线程代替进程,按 H 即可,此时 “Tasks” 行将显示的是 “Threads”,显示的是线程的数量,而不是进程的数量。

Threads: 351 total,   2 running, 349 sleeping,   0 stopped,   0 zombie
复制代码

细心的读者可能会发现, summury area 中的 “Tasks” 行已经改变成 “Threads” 的了,但是在 task area 中,对应的列表中的属性却没有任何更改,那既然进程和线程不同,这怎么可能呢? 原因是在 Linux 内核内部,线程和进程使用相同的数据结构进行处理,因此,每个线程都有自己的ID、状态等等。如果我们要切换回进程视图,则再次按 H 即可。此外,也可以使用 top -H 在默认情况下显示线程。

显示进程完整路径

默认情况下,COMMAND 列下的所有进程名显示的都是摘要名,如果我们期望显示当前进程的完成路径,可以通过按 c 来切换视角,或者直接使用 top -c 来启动交互界面。

以树形结构显示父子进程

可以通过在 top 交互中按 V 来切到 forest view 视角,即以以树形结构显示父子进程。

432 root      20   0   84760   5852   4984 S   0.0  0.0   0:00.01  `- /usr/sbin/sshd -D
 98518 root      20   0  118432   6884   5792 S   0.0  0.0   0:00.00      `- sshd: admin [priv]
 98520 admin     20   0  118432   3648   2556 S   0.0  0.0   0:01.32          `- sshd: admin@pts/0
 98521 admin     20   0  120656   4936   3768 S   0.0  0.0   0:00.34              `- -bash
130138 admin     20   0  161748   4208   3624 R   0.0  0.0   0:00.27                  `- top -c
复制代码

列出用户的进程

要列出某个用户的进程,请在top运行时按 u。然后,输入用户名,或者留空以显示所有用户的进程;或者直接通过 top -u xxx 来指定 xxx 用户的所有进程信息。

KiB Swap:  2097148 total,  2097148 free,        0 used. 31179088 avail Mem
Which user (blank for all) root   # waiting for input
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
     1 root      20   0   45416   5244   3968 S   0.0  0.0   5:37.57 /usr/lib/systemd/systemd --system --deserialize 18
   340 root      20   0   72892  30836  27184 S   0.0  0.1   8:36.56 /usr/lib/systemd/systemd-journald
   357 root      20   0  101836   2768   2312 S   0.0  0.0   0:01.14 /usr/sbin/gssproxy -D
   432 root      20   0   84760   5852   4984 S   0.0  0.0   0:00.01 /usr/sbin/sshd -D
复制代码

过滤进程

如果我们需要处理许多进程,那么简单的排序实际上对我们的帮助并不是很大。那么在这种情况下,我们可以按 o 来激活 top 的过滤模式,然后通过输入一个过滤器表达式来过滤到我们的目前进程。过滤器表达式是指定属性和值之间关系的语句,例如:

  • COMMAND=java: 进程名=java 的
  • !COMMAND=java: 进程名 !=java 的
  • %CPU>3.0: CPU > 3.0 的

如果要清除所有过滤条件的话,按 = 即可。