监控和管理Linux进程
进程状态和生命周期
进程的定义
进程是已启动的可执行程序中运行的实例。从进程创建那一刻起,它由以下项目组成:
- 已分配内存的地址空间
- 安全属性,包括所有权凭据和特权
- 程序代码的一个或多个执行线程
- 进程状态
进程的环境是包含以下项目的信息列表:
- 本地和全局变量
- 当前调度上下文
- 分配的系统资源,如文件描述的网络端口
现有的父进程复制自己的地址空间(成为进程分叉)来创建子进程结构。每个新进程分配有一个唯一进程ID(PID),满足跟踪和安全性之需。PID和父进程ID(PPID)是新进程环境的元素。任何进程都可以创建子进行。所有进程都是第一个系统进程的后代,在RedHat Linux中,第一个系统进程是systemd。
通过分叉进程,子进程继承安全性身份、过去和当前的文件描述符、端口和资源特权、环境变量,以及程序代码。随后,子进程可以执行其自己的代码程序。
通常,父进程在子进程运行期间处于睡眠状态,设置一个在子进程完成时发出信号的等待请求。子进程退出后,他会关闭或丢弃其资源和环境,并留下僵停资源,即进程表中的一个条目。父进程在子进程退出时收到信号而被唤醒,清理子进程条目的进程表,由此释放子进程的最后一个资源,然后,父进程继续执行自己的程序代码。
描述进程状态
在多任务处理操作系统中,每个CPU(或CPU核心)在一个时间上处理一个进程。在进程运行时,它对CPU时间和资源分配的直接要求会有变化。进程分配有一个状态,它随着环境要求而改变。
以下图示和表格详细描述了Linux进程状态。
Linux进程状态
名称 | 标志 | 内核定义的状态名称和描述 |
---|---|---|
运行中 | R | TASK_RUNNING:进程正在CPU上执行,或者正在等待运行。处于运行中(或可运行)状态时,进程可能正在执行用户例程或内核例程(系统调用),或者已经排队并就绪。 |
睡眠 | S | TASK_INTERRUPTIBLEl:进程正在等待某一条件:硬件请求、系统资源访问或信号。当事件或信号满足该条件时,该进程将返回运行中。 |
睡眠 | D | TASK_UNINERRUPTIBLE:此进程也正在睡眠,但与S状态不同,不会响应信号。仅在进程终端可能会导致以外设备状态下使用。 |
睡眠 | K | TASK_KILLABLE:与不可中断的D状态相同,但有所修改,允许等待中的任务响应要被中止(彻底退出)的信号。实用程序通常将可中止的进程显示为D状态。 |
睡眠 | I | TASK_REPORT_IDLE:D状态的一个子集。在计算负载平均值时,内核不会统计这些进程。用于内核线程。设置了TASK_UNINTEERRUPTIBLE和TASK_NOLOAD标志。类似于TASK_KILLABLE,也是D状态的一个子集。它接受致命信号。 |
已停止 | T | TASK_STOPPED:进程已被停止(暂停),通常是通过用户或其他进程发出的信号。进程可以通过另一信号返回到运行中状态,继续执行(恢复)。 |
已停止 | T | TASK_TRACED:正在被调试的进程也会临时停止,并且共享同一个T状态标识。 |
僵停 | Z | EXIT_TRACED:子进程在退出时向父进程发送信号。除进程身份(PID)之外的所有资源都已释放。 |
僵停 | X | EXIT_DEAD:当父进程清理(获取)剩余的子进程结构时,进程现在已经彻底释放。次状态无法在进程列出实用程序中看到。 |
进程状态的重要性
在对系统进行故障排除时,了解内核如何于进程通信以及进程如何相互通信非常重要。系统为每个新进程分配一个状态。top命令的S列或ps的STAT列显示每个进程的状态。在单CPU系统上,一次只能运行一个进程。您可以看到多个状态为R的进程。但是,并非所有进程都在连续运行。其中一些处于等待状态。
使用信号来暂停、停止、恢复、终止或中断进程。进程可以捕获来自同一系统上内核、其他进程和其他用户的信号。
列出进程
ps命令用于列出当前进程的详细信息。
- 用户标识符(UID),它确定进程的特权。
- 唯一进程标识符(PID)。
- 已用CPU量和实际时间。
- 分配的内存量。
- 进程stdout位置,称为控制终端。
- 当前的进程状态。
重要:Linux版的ps命令支持以下选项格式:
UNIX(POSIX)选项,可以分组单必须以连字符开头。
BSD选项,可以分组但不可以与短划线同用。
GNU长选项,以爽连字符开头。
例如:ps -aux 命令与ps aux命令不同。
常见的ps命令aux选项显示包括无控制终端的进程在内的所有进程。长列表(lax选项)提供更多详细信息,并且通过避免查询用户名可用加快显示。相似的UNIX语法使用-ef选项来显示所有进程。在以下示例中,调度的内核线程显示在列表顶部,并用方括号括起。
1 | [kiosk@foundation0 ~]$ ps aux | tail -n 10 |
默认情况下,不带选项运行ps命令会选择具有与当前用户相同的有效用户ID(EUID)并与运行命令所处同一终端关联的所有进程。僵停进程使用exiting 或defunct标签列出。
您可以使用ps 命令 –forest 选项以树形格式显示进程,从而查看父进程和子进程之间的关系。
ps 命令的默认输出按进程ID编号排序。输出中似乎使用了时间顺序,但内核重复使用了进程ID,因此其顺序不如看起来那样有序。使用ps 命令-o 或 –sort 选项对输出进行排序。显示顺序与系统进程表的顺序匹配,在进程终止和进程运行时重新使用列表行。
控制作业
描述作业和会话
借助作业控制shell功能,单个shell实例可以运行和管理多个命令。
作业与在shell提示符中输入的每个管道相关联。该管道中的所有进程均是作业的一部分,并且是同一个进程组的成员。最小管道可以被视为在shell提示符处输入的唯一一个命令,创建仅含有一个成员的一个作业。
一次只能有一个作业从特定终端窗口中读取输入和键盘生成的信号。属于改作业的进程是该终端的前台进程。
该控制终端的后台进程是与该终端相关联的任何其他作业。终端的后台进程无法从终端读取输入或接收键盘生成的中断,但可以写入到终端。后台作业可能已停止(暂停),也可能正在运行。如果某个正在运行的后台作业尝试从终端读取内容,则该作业将自动暂停。
每个终端在其自身的会话中运行,并且可以具有一个前台进程和任意数量的后台进程。一个作业仅在属于其控制终端的一个会话中。
ps命令在TTY列中显示控制终端的设备名称。某些进程(如系统守护进行)由系统启动,并不是从控制终端启动的。这些进程不是作业的成员,并且无法转至前台。ps命令在TTY列中针对这些进程显示一个问号(?)。
在后台运行作业
任何命令或管道都可以在后台启动,只需在命令上附加一个&符号即可。Bash Shell显示作业编号(特定于会话的唯一编号)在新建子进程的PID。shell不等待子进程终止,而会显示shell提示符。
1 | [kiosk@foundation0 ~]$ sleep 10000 & |
如果将包含竖线(|)的命令发送到后台,将显示管道中最后一个命令的PID。所有管道进程仍是该作业的成员。
1 | [kiosk@foundation0 ~]$ echo example_command | sort | mail -s "Sort Output" & |
使用jobs命令显示当前shell会话的作业列表
1 | [kiosk@foundation0 ~]$ jobs |
使用fg命令将后台作业置于前台。使用(%jobNumber)格式将进程指定到前台。
1 | [kiosk@foundation0 ~]$ fg %1 |
在上述例子中,sleep命令现在正在控制终端的前台运行。shell本身将睡眠,并等待这一子进程退出。
若要将前台进程发送到后台,请首先在终端中按键盘生成暂停请求(Ctrl+z)。该作业将被置于后台并暂停。
1 | [kiosk@foundation0 ~]$ fg %1 |
ps命令 j选项显示与作业相关的信息。使用ps命令j选项来查找进行和会话信息。
- PID是唯一的进程ID。
- PPID是此进程的父进程(即启动(分叉)此进程的进程)的PID。
- PGID是进程组首进程的PID,通常是作业管道中的第一个进程。
- SID是会话首进程的PID,对于作业而言,这通常是正在其控制终端上运行的交互shell。
以下示例中,sleep命令当前已停止,其状态为T。
1 | [kiosk@foundation0 ~]$ ps j |
使用bg命令和作业ID来启动暂停的进程。
1 | [kiosk@foundation0 ~]$ bg %1 |
如果用户尝试退出带有暂停作业的终端窗口(会话),那么shell会发出警告。如果用户再次尝试立即退出,暂停的作业将会被终止。
注意:在前面示例中,【[1]+ sleep 10000 &】+符号表示此作业是当前的默认作业。如果不带%jobNumber参数使用作业控制命令,则对默认作业执行操作。-符号表示在当前默认作业完成时即将成为下一个默认作业。
中止进程
使用信号控制进程
信号是传递至进程的软件中断。信号向执行中的程序报告事件。生成信号的时间可以是错误或外部事件(I/O请求或定时器过期),或者来自于显示使用信号发送命令或键盘序列。
下表列出了系统管理员常用进程管理的基本信号。请通过短名称(HUP)或全称(SIGHUP)来指代信号。
基本进程信号
信号 | 名称 | 定义 |
---|---|---|
1 | HUP | Hangup:报告终端控制进程的终止。也请求进程重新初始化(重新加载配置)而不终止。 |
2 | INT | Keyboard interrupt:导致程序终止。可以被拦截或处理。通过按INTR(中断)键序列(Ctrl+c)发送 |
3 | QUIT | Keyboard quit:与SIGINT相似;在终止时添加进程转储。通过按QUIT键序列(Ctrl+\)发送。 |
9 | KILL | Kill, unblockable:导致立即终止程序。无法被拦截、忽略或处理;总是致命的。 |
15(默认) | TERM | Terminate:导致程序终止。与SIGKILL不同,可以被拦截、忽略或处理。要求程序以”干净“的方式终止;它允许程序完成基本操作和自我清理后再终止。 |
18 | CONT | Continue:发送至进程使其恢复(若已停止)。无法拦截。即使被处理,也始终恢复进程。 |
19 | STOP | Stop, unblockable:暂停进程。无法被拦截或处理 |
20 | TSTP | Keyboard stop:和SIGSTOP不通,可以被拦截、忽略或处理。通过按暂停键序列(Ctrl+z)发送。 |
注意:信号编号视不通Linux硬件平台而异,但信号名称和含义都是标准的。建议再发送信号时使用信号名称,而不是数字。本章节适用于X86_64架构系统。
每个信号都有一个默认操作,通常是如下操作之一:
Term:立即终止程序(退出)。
Core:保存程序的内存镜像(核心转储),然后终止。
Stop:停止运行中的程序(暂停),再等待继续(恢复)。
程序通过实施处理程序例程来响应预期的事件信号,以忽略、替换或扩展信号的默认操作。
通过显示请求发送信号
您可以想当前的前台进程发送信号,具体操作为案件键盘控制序列以暂停(Ctrl+z)、中止(Ctrl+c)或核心转储(Ctrl+\)该进程。不过,您可以使用信用发送命令向另一会话中的后台进程发送信号。
您可以通过名称(例如 -HUP 或 -SIGHUP)或编号(相关的 -1 选项)来指定信号。用户可以中止自己的进程,但需要root权限才能终止其他人拥有的进程。
kill命令使用PID编号向进程发送信号。芮苒其名为kill,但您可以使用这个命令来发送任何信号,而不仅仅是终止程序的信号。您可以使用kill命令 -l选项列出所有可用信号的名称和编号。
1 | [kiosk@foundation0 ~]$ kill -l |
控制特定进程
使用pkill命令向一个或多个符合选择条件的进程发送信号。选择条件可用是命令名称、特定用户拥有的进程,或所有系统范围进程。
可用逐一向进程和会话发送信号,也可以集体发送。要终止一个用户的所有进程,可使用pkill命令。
由于登录会话中的初始进程(会话首进程)设计为可以处理会话终止请求并忽略不想要的键盘信号,中断某一用户的所有进程和登录shell需要使用SIGKILL信号。
首先,使用pgrep命令来确定要中止的PID编号。此命令的操作与pkill命令类似,大部分选项相同,但是pgrep命令列出进程而不是中止它们。
使用pgrep命令和-l选项列出进程名称和ID。使用任一命令和-u选项来指定拥有进程的用户的ID。
1 | [root@foundation0 home]# pgrep -l -u user03 |
当需要注意的进程在同一登录会话中时,可能不需要中止用户所有的进程。使用w命令来确定会话的控制终端,然后仅中止引用同一中断ID的进程。
除非指定了SIGKILL,否则会话首进程(此处为Bash登录shell)可以成功处理中止请求并继续运行,但所有其他会话进程将被终止。
1 | [root@foundation0 ~]# pgrep -l -u user03 |
重要:管理员通常使用SIGKILL。
由于SIGKILL信号无法被处理或忽视,它总是致命的。然而,它会强制终止进程,而不允许被中断的进程运行自我清理例程。RedHat Linux建议先发送SIGTERM,然后尝试SIGINT;只有这两个都失败时,在尝试SIGKILL。
您可以借助父进程和子进程关系应用相同的选择性进程终止。使用pstree命令查看系统或单个用户的进程树。使用父进程的PID中止其创建的所有子进程。父进程Bash登录Shell不通被终止,因为信号仅定向至它的子进程。
1 | [root@foundation0 ~]# pstree -p kiosk |
向多个进程发送信号
killall命令可以根据命令名称向多个进程发送信号。
1 | [root@foundation0 ~]# ps aux | grep sleep |
使用kill命令终止特定的作业。在作业编号上添加前缀百分号(%)
1 | [kiosk@foundation0 ~]$ jobs |
以管理员身份注销用户
出于各种原因,您可能需要注销其他用户。一些可能的情景:用户做出了安全违规行为;用户可能过度使用了资源;用户的系统不响应;或者,用户不当访问了资料。在这些情形中,您必须以管理员身份使用信号来终止其会话。
要注销某个用户,首先确定要终止的登录会话。使用w命令列出用户登录和当前运行的进程。记录TTY和FROM列,以确定要关闭的会话。
所有用户登录会话都与某个中断设备(TTY)相关联。如果设备名称为pts/N,说明这时一个与图形终端窗口或远程登录会话相关联的伪终端。如果为ttyN,则说明用户位于一个系统控制台、替代控制台或其他直接连接的终端设备上。
1 | [root@foundation0 ~]# w |
查看会话登录时间,了解用户已登录该系统的时长。对于每个会话,当前作业占用的CPU资源(包括后台任务和子进程)位于JCPU列中。当前的前台进程CPU占用情况列在PCPU中。
监控进程活动
描述负载平均值
负载平均值是Linux内核提供的一种度量,可以表示一段时间内感知的系统负载。它可用来粗略衡量待处理的系统资源请求数量,并确定系统负载的增减。
根据处于可运行和不可中断状态的进程数,内核会每五秒收集一次当前的负载数。通过汇总这些数值,可以得到最近1分钟、5分钟和15分钟内的指数移动平均值。
负载平均值计算
负载平均值代表一段时间内感知的系统负载。通过报告CPU上准备运行的进程数以及等待磁盘或网络I/O完成的进程数,Linux可以确定负载平均值。
- 负载数是准备运行的进程数(进程状态为R)或等待I/O完成的进程数(进程状态为D)的运行平均值。
- 一些UNIX系统仅考虑CPU使用率或运行列长度来指示系统负载。Linux还包含磁盘或网络利用率,因为与CPU负载一样,这些资源使用量较高会对系统性能产生重大影响。如果负载平均值很高但CPU活动很低,请检查磁盘和网络活动。
负载平均值可以粗略衡量在执行其他任何作业之前,有多少进程当前在等待请求完成。请求可能是用于运行进程的CPU时间。或者,请求可能是让关键磁盘I/O操作完成;在其他作业请求完成之前,不能在CPU上运行该进程,即使CPU空闲也不行。无论是哪种方法,都会影响系统负载;系统的运行看起来会变慢,因为有进程正在等待运行。
解读负载平均值
uptime命令是显示当前负载平均值的一种方法。它可显示当前时间、计算机启动时长、运行的用户会话数以及当前的负载平均值。
1 | [root@foundation0 ~]# uptime |
这三个负载平均值代表了最近1、5和15分钟的负载情况。它指出了系统负载似乎在增高还是降低。
如果等待CPU处理的进程是负载平均值的主要贡献因素,则可以计算近似的每个CPU负载值以判断系统是否在遭遇显著的等待。
使用lscpu命令来确定系统上存在的CPU数。
1 | [root@foundation0 ~]# lscpu |
暂时不妨设想,需要CPU时间的进程是负载数的唯一贡献因素。然后您可以用显示的负载平均值除以系统中的逻辑CPU数。值低于1表示资源利用率适当,等待时间较短。值高于1表示资源饱和,而且有一些处理处于延迟。
空闲CPU队列的负载数为0。每个等待CPU处理的进程都会使负载数加1.如果有一个进程在CPU上运行,则负载数为1;虽然资源(CPU)处于使用状态,单没有等待的请求。如果改进程运行了整整一分钟,那么它对这一分钟负载平均值的贡献就是1。
不过,因为磁盘或忘了资源忙碌而等待关键I/O并处于不可中断睡眠状态的进行也包含在该计数内,而且会使负载平均值增大。虽然不能表示CPU使用率,但这些进程也被添加到队列数中,因为它们正在等待资源,并且在获取资源之前无法在CPU上运行。由于资源限制导致无法运行,因此这一指标仍被视为系统负载。
在资源饱和之前,负载平均值将保持在1以下,因为几乎不会在队列中发现等待的认为。只有资源饱和导致请求留在排队状态并且被负载计算例程计数时,负载平均值才会增大。当资源使用率接近100%时,每个增加的请求将开始遭遇服务等待时间。
实时进程监控
top命令显示系统进程的动态视图,以及一个摘要标题,后跟一个进程或线程列表。与静态的ps命令输出不同,top命令以可配置的间隔持续刷新,而且也提供列重新排列、排序和突出显示功能。您可以对top设置进行持久更改。默认的top输出列如下:
- 进程ID(PID)
- 进程所有者用户名(USER)
- 虚拟内存(VIRT)是进程正在使用的所有内存,包括常驻集合、共享库,以及任何映射或交换的内存页。(在ps命令中标题为VSZ)
- 常驻内存(ERS)是进程所使用的物流内存,包括任何驻留2的共享对象(在ps命令中标题为RSS)
- 进程状态(S)可以是以下状态之一:
- D= 不可中断睡眠
- R=运行中可运行
- S=睡眠中
- T=已停止或已跟踪
- Z=僵停
- CPU时间(TIME)是进程启动以来总的处理时间。可以切换为包含所有过去子进程的累计时间。
- 进程命令名称(CMMMAND)。
top命令中的基本击键操作
键 | 用途 |
---|---|
?或h | 交互式击键操作的帮助。 |
l、t、m | 切换到负载、线程和内存标题行。 |
1 | 标题张却换显示单独CPU信息或所有CPU汇总。 |
s | 更改(屏幕)刷新率,以小数点的秒数表示(如0.5、1、5) |
b | 却换反色突出显示Running进程;默认为仅粗体。 |
Sheift+b | 在显示中使用粗体,用于标题以及运行中的进程。 |
Sheift+h | 切换线程;显示进程摘要或单独线程。 |
u、Sheift+u | 过滤任何用户名(有效、真实) |
Sheift+m | 按照内存使用率,以降序方式对进程列表排序。 |
Sheift+p | 按照处理器使用率,以降序方式对进程列表排序。 |
k | 中止进程。如有提示,输入PID,在输入signal。 |
r | 调整进程的nice值。若有提示,输入PID,再输入nice_value。(nice值为-20到19,值越低代表该进程优先级越高) |
Sheift+w | 写入(保存)当前的显示配置,一遍下一次重新启动top时使用 |
q | 退出 |
f | 通过启用或禁用字段的方式来管理列。也可以为top设置排序字段。(d选中或显示列,s切换该列进行排序,q退出设置) |
注意:再安全模式下启动top命令时,s、k和r击键操作不可用。