12.Linux进程管理

12.Linux进程管理

1.进程基本概述

1.1 程序与进程

  • 什么是程序:开发编写的源代码,封装为产品,比如
    (微信、钉钉、等等)都称为程序(硬盘);
  • 什么是进程:程序运行的过程,我们称为进程,它主
    要是用来控制计算机硬件运行我们的程序;
  • 程序与进程区别:
    • 程序:程序是数据+指令的集合,是一个静态的概
      念,同时程序可以长期存在系统中;
    • 进程:进程是程序运行的过程,是一个动态的概
      念,在进程运行的过程中,系统会有各种指标来表
      示当前运行的状态,同时进程会随着程序的终止而
      销毁,不会永久存在系统中;

1.2 进程与线程

  • 假设需要运行”360安全卫士“程序,会进行资源申请,
    首先系统申请一块内存空间、然后从硬盘中将代码读
    取到内存、最后进行其他资源的申请,这个申请资源
    的过程,我们称为进程(资源单位);

  • 当运行该进程中的"病毒扫描、漏洞查找、垃圾清
    理"等功能,通常我们会将该功能称为进程中的线程,
    线程是运行代码的过程,它是一个(执行单位),是
    进程中的更细的单位,如果该进程有多个线程,线程

    与线程之间互相不受影响,同时多线程之间可以实现
    数据共享;

    工厂流水线例子:工厂(操作系统)-->进程(车
    间)-->线程(流水线作业)

1.3 并发与并行

  • 并发:多个任务看起来是同时运行,这是一种假并行(CPU在任务中来回切换);
  • 并行:多个任务是真正的同时运行(并行必须有多核CPU才可以实现);

1.4 进程运行的状态

  • 一般来说,进程有三个状态,即就绪状态,运行状态,阻塞状态;
  • 运行态:进程占用 CPU ,并在 CPU 上运行;
  • 就绪态:进程已经具备运行条件,但需要等待 CPU 的调度才可运行;
  • 阻塞态:进程因等待某件事发生而暂时不能运行;

上述三种状态之间转换分为如下几种情况;

  • 运行-->阻塞:进程发生 I/O 操作,需等待事件,而继
    续无法执行,则进程由运行状态变为阻塞状态;
  • 阻塞-->就绪:进程所等待的事件已经完成,但没办法
    直接运行,需要进入就绪队列,等待调度;
  • 就绪-->运行:运行的进程时间片已经用完, CPU 会从
    就绪队列中选择合适的进程分配 CPU
  • 运行-->就绪:
    • 1、进程占用 CPU 的时间过长,而系统分配给该进
      程占用 CPU 的时间是有限的;
    • 2、当有更高优先级的进程要运行时,该进程需要
      让出 CPU ,由运行状态转变为就绪状态;
  • 就绪态-x->阻塞: 已经就绪了,跟阻塞毫无关系;
  • 阻塞-->运行:阻塞状态结束,它必须进入就绪队列中,然后等待cpu从队列中挑选进程分配资源;

1.5 进程的生命周期

  • 生命周期就是指一个对象的生老病死。用处很广

当父进程接收到任务调度时,会通过fock派生子进程来
处理,那么子进程会继承父进程属性。
1.子进程在处理任务代码时,父进程其实不会进入等
待,其运行过程是由linux系统进行调度的。
2.子进程在处理任务代码后,会执行退出,然后唤醒父
进程来回收子进程的资源。
3.如果子进程在处理任务代码过程中异常退出,而父进
程却没有回收子进程资源,会导致子进程虽然运行实体
已经消失,但仍然在内核的进程表中占据一条记录,长
期下去对于系统资源是一个浪费。(僵尸进程)
4.如果子进程在处理任务过程中,父进程退出了,子进
程没有退出,那么这些子进程就没有父进程来管理了,
由系统的system进程管理。(孤儿进程)
PS: 每个进程都父进程的PPID,子进程则叫PID。

2. 进程运行状态监控

  • 程序在运行后,我们需要了解进程的运行状态。查看进程的状态分为:
    • 静态查看
    • 动态查看

2.1 静态监控进程

  • ps -aux 常用组合,查看进程 用户、PID、占用cpu百
    分比、占用内存百分比、状态、执行的命令等

2.1.1 每列指标详解

  • USER :启动进程的用户
  • PID :进程运行的 ID 号
  • %CPU :进程占用 CPU 百分比
  • %MEM :进程占用内存百分比
  • VSZ :进程占用虚拟内存大小 (单位KB)
  • RSS :进程占用物理内存实际大小 (单位KB)
  • TTY :进程是由哪个终端运行启动的 tty1、pts/0 等? 表示内核程序与终端无关
  • STAT :进程运行过程中的状态 man ps (/STATE)
  • START :进程的启动时间
  • TIME :进程占用 CPU 的总时间(为0表示还没超过秒)
  • COMMAND :程序的运行指令, [ ] 属于内核态的进程。 没有 [ ] 属于用户态进程。

2.1.2 查看进程ppid

ppid 指定的是父进程;

[root@node ~]# ps -ef |grep sshd
root    1425    1  0 7月19 ?   
00:00:00 /usr/sbin/sshd -D
root    32067  1425  0 7月19 ?   
00:00:02 sshd: root@pts/1
root    52604  1425  0 15:53 ?   
00:00:01 sshd: root@pts/0

2.1.3 查看进程树结构

通过 pstree 可以查看进程树状结构

-p :选项指定查看某个进程的树状结构

[root@node ~]# pstree -p 1425
sshd(1425)─┬─sshd(32067)───bash(32069)
    
└─sshd(52604)───bash(52606)─┬─pstree(67809)
                  
├─sleep(67440)
                  
└─sleep(67506)

2.1.4 查看用户进程

1.使用普通用户运行进程

[root@node ~]# su - oldxu -c "sleep 10000" &
[3] 68021

2.使用 pgrep 过滤用户运行进程名称,以及进程ID

[root@node ~]# pgrep -l -u oldxu
68022 sleep
# -a:表示列出进程pid以及详细命令
[root@node ~]# pgrep -a -u oldxu
68022 sleep 10000

2.1.5 STAT运行状态

  • STAT 状态的 S、Ss、S+、R、R+、S+ 等等,都是什么
    意思?

STAT基本状态 描述 STAT状态+符号 描述
R 进程运行 s 进程是控制进程,Ss是父进程
S 就绪状态 < 进程运行在高优先级上S<
T 进程被暂停 N 进程运行在低优先级上SN
D 不可中断进程 + 当前进程运行在前台,R+
Z 僵尸进程 l 进程是多线程的,Sl表示进程是以线程方式运行

2.2 进程状态模拟实践

2.2.1 运行进程状态R

1.编写如下脚本

[root@node ~]# cat > while.sh <<EOF
while true;do ((1+1));done
EOF

2.运行该脚本,检查运行状态是否为 R

[root@node ~]# sh while.sh
[root@node ~]# ps -aux |grep while
root    58784 93.8  0.2 113172  1192
pts/0  R+  13:30  0:08 sh while.sh

2.2.2 暂停进程状态T

1.在终端1上运行 vim

[root@node ~]# vim new_file

2.在终端2上运行 ps 命令查看状态

[root@node ~]# ps aux|grep new_file  # S
表示睡眠模式,+表示前台运行
root    58118  0.4  0.2 151788  5320
pts/1  S+  22:11  0:00 new_file
root    58120  0.0  0.0 112720  996
pts/0  R+  22:12  0:00 grep --
color=auto new_file
# 在终端1上挂起vim命令,按下:ctrl+z

3.回到终端2再次运行 ps 命令查看状态

[root@node ~]# ps aux|grep new_file  # T表示停止状态
root    58118  0.1  0.2 151788  5320
pts/1  T   22:11  0:00 vim new_file

2.2.3 不可中断进程D

1.使用 tar 打包文件时,可以通过终端不断查看状态,
由 S+,R+、D+

[root@node ~]# tar -czf etc.tar.gz /etc/
/usr/ /var/
[root@node ~]# ps aux|grep tar|grep -v
grep
root    58467  5.5  0.2 127924  5456
pts/1  R+  22:22  0:04 tar -czf
etc.tar.gz /etc/
[root@node ~]# ps aux|grep tar|grep -v
grep
root    58467  5.5  0.2 127088  4708
pts/1  S+  22:22  0:03 tar -czf
etc.tar.gz /etc/
[root@node ~]# ps aux|grep tar|grep -v
grep
root    58467  5.6  0.2 127232  4708
pts/1  D+  22:22  0:03 tar -czf
etc.tar.gz /etc/

2.使用 dd 命令创建磁盘空间,状态会由 R+、D+

[root@node ~]# dd if=/dev/zero
of=/dev/null bs=1000M count=100
# 观察状态
[root@oldxu ~]# ps -aux |grep "/dev/null"
root 5813 40 71.7 113 344 pts/0 D+ 13:32
0:13 dd if=/dev/zero of=/dev/null bs=1000M
count=100

2.2.4 实践僵尸进程Z

1.编写 Python 脚本,模拟僵尸进程;

[root@node ~]# cat zombie.py
#!/usr/bin/env python
# encoding: utf-8
from multiprocessing import Process
import time
import os
def task():
 print("子进程ID --> %s" % os.getpid())
 time.sleep(10)
if __name__ == "__main__":
  for i in range(3):
    p=Process(target=task)
   p.start()
   print("父进程ID --> %s" % os.getpid())
 time.sleep(100000)

2.运行 python 脚本

[root@node ~]# python zombile.py
父进程ID --> 59220
子进程ID --> 59221
子进程ID --> 59222
子进程ID --> 59223

3.通过 ps aux 查看进程状态;

[root@node ~]# ps -aux |grep python
root    59220  0.0  1.2 151200  5772
pts/0  S+  13:36  0:00 python
zombile.py
root    59221  0.0  0.0    0   0
pts/0  Z+  13:36  0:00 [python]
<defunct>
root    59222  0.0  0.0    0   0
pts/0  Z+  13:36  0:00 [python]
<defunct>
root    59223  0.0  0.0    0   0
pts/0  Z+  13:36  0:00 [python]
<defunct>

4.僵尸进程无法杀死,只能通过杀父进程,从而回收掉
僵尸进程

# kill僵尸进程没有反应,所以直接kill父进程
[root@node ~]# kill -9 59220

2.2.5 实践孤儿进程

1.在窗口1执行如下命令

[root@node ~]# ping www.baidu.com
&>/dev/null &
[1] 52428

2.在窗口2过滤 ping 进程,杀死其父进程

[root@node ~]# ps -ef | grep ping | grep -
v grep
root    52428  52407  0 20:45 pts/0 
 00:00:00 ping www.baidu.com
# 强制杀死父进程
[root@node ~]# kill -9 52407

3.再次查看进程,会发现该进程被系统最高进程 pid 1接管

# 孤儿进程被PID为1的父进程接管
[root@node ~]# ps -ef | grep ping
root    52428    1  0 20:45 ?   
 00:00:00 ping 10.0.0.2
# 直接kill进程即可关闭
[root@node ~]# kill 52428

2.2.6 实践多线程SI

1.使用 python 脚本编写多线程程序

[root@node ~]# cat multi_thread.py
#!/usr/bin/env python
from threading import Thread
import time
import os
def task():
 time.sleep(200)
if __name__  == "__main__":
 print(os.getpid())
  for i in range(10):
    s=Thread(target=task)
   s.start()

2.运行 python 脚本程序

[root@node ~]# python multi_thread.py
59691

3.检查 python 程序状态

# sl表示多线程
[root@node ~]# ps aux|grep python
root    59691  0.0  1.0 740280  5000
pts/1  Sl+  13:43  0:00 python
multi_thread.py
# 通过pstree查看线程
[root@node ~]# pstree -p 59691
python(59691)─┬─{python}(59692)
      ├─{python}(59693)
      ├─{python}(59694)
      ├─{python}(59695)
      ├─{python}(59696)
      ├─{python}(59697)
      ├─{python}(59698)
      ├─{python}(59699)
      ├─{python}(59700)
      └─{python}(59701)

2.2.7 高优先级进程S<

1.执行如下命令,让进程在高优先级下运行

[root@node ~]# nice -n -20 sleep 30000 &
[1] 67440

2.查看进程状态,看是否在高优先级下运行

[root@node ~]# ps -aux |grep sleep
root    67440  0.0  0.0 107948  352
pts/0  S<  20:20  0:00 sleep 30000

2.2.8 低优先级进程SN

1.执行如下命令,让进程在低优先级下运行

[root@node ~]# nice -n 20 sleep 50000 &
[2] 67506

2.查看进程状态,看是否在低优先级下运行

[root@node ~]# ps -aux |grep sleep
root    67506  0.0  0.0 107948  352
pts/0  SN  20:21  0:00 sleep 50000

2.3 动态监控进程top

  • 使用 top 命令查看当前的进程状态(动态)

2.3.1 top命令选项

  • 执行 top 命令时可以指定的命令选项
    • -d :刷新时间
    • -p :指定 pid
    • -u :指定用户
  • 示例用法:
# 仅查看指定进程动态详情
[root@node ~]# top -d 1 -p pid
[root@node ~]# top -d 1 -p $(pgrep nginx)
# 动态查看oldxu运行的进程
[root@node ~]# top -d 1 -u oldxu

2.3.2 top内部选项

  • 执行 top 后可使用的选项
    • c :改变top刷新频率(一般不建议设定)
    • P :按CPU进行排序;
    • M :以内存进行排序;
    • R :对排序后的结果进行倒序;
    • f :自定义显示的字段,比如打印ppid
    • k :指定杀死某个id
    • 1 :显示cpu核心数
    • z :以高亮显示数据
    • b :高亮显示处于R状态的进程

2.3.3 top字段含义

  • top 字段含义
    • Tasks: 129 total :当然进程的总数
    • 1 running :正在运行的进程数量
    • 128 sleeping :睡眠的进程数量
    • 0 stopped :停止的进程数量
    • 0 zombie :僵尸进程数量
  • %Cpu(s) 含义
    • 0.7 us : 系统用户进程使用 CPU 百分比
    • 0.7 sy :内核中的进程占用 CPU 百分比,通常内核是于硬件进行交互
    • 98.7 id :空闲 CPU 的百分比
    • 0.0 wa : CPU 等待IO完成的时间
    • 0.0 hi :硬中断,占的 CPU 百分比
    • 0.0 si :软中断,占的 CPU 百分比
    • 0.0 st :比如虚拟机占用物理 CPU 的时间

2.3.4 如何理解中断

  • 内存计算公式:
  • buffer/cache 是否可以释放: 手动释放:
total: 总内存计算公式:used + free + buffer
+ cache = total
used: 已使用内存计算公式:total - free -
buffers - cache = used(包含share)
free: 未被使用的内存计算公式:total - used -
buffer - cache = free
available: 可获得内存计算公式: free +
(buffer+cache可释放的空间) = available 启
动新的程序能用的内存
buffer: 写缓冲;
cache: 读缓存;
share: 共享内存,属于被分配的内存
需要注意:
free表示的是当前完全没有被程序使用的内存;
而cache在有需要时,是可以被释放出来以供其它
进程使用的;
而available才真正表明系统目前可以提供给应用
程序使用的内存;
# 内存清理 手动释放
sync
echo 3>/proc/sys/vm/drop_caches 改变了文件最后修改时间;

3.管理进程状态

当程序运行为进程,如果需要关闭进程,则需要使用
kill、killall,pkill 等命令对进程ID发送关闭信号

3.1系统支持的信号

  • 使用 kill -l 列出当前系统所支持的信号、虽然支持
    的信号很多,但我们仅以最常用的3个信号为例
    • 1(SIGHUP) :通常用来重新加载配置文件
    • 9(SIGKILL) :强制杀死进程
    • 15(SIGTERM) :终止进程,默认kill信号

3.2 关闭进程kill

1.安装 vsftpd 服务,然后启动;

[root@node ~]# yum -y install vsftpd
[root@node ~]# systemctl start vsftpd

2.修改 vsftpd 的配置文件,然后发送重载信号;

# 改变路径
[root@node ~]# echo "anon_root=/data" >> /etc/vsftpd/vsftpd.conf
# 重载服务
[root@node ~]# kill -1 81379

3.发送停止进程信号

[root@node ~]# kill -15 9160

4.发送强制停止信号,当无法停止服务时,可强制终止信号(慎用.对于'不可中断状态的进程' 强行结束会出问题)

[root@node ~]# kill -9 9160

3.3 关闭进程pkill

1.通过 pkill、killall 指定进程服务名称,然后将其进程关闭

[root@node ~]# pkill nginx
[root@node ~]# killall nginx

2.使用 pkill 将远程连接用户 t 下线

[root@node ~]# pkill -9 -t pts/0

4.进程优先级

4.1 什么是进程优先级

  • 优先级指的是优先享受资源,比如排队买票时,军人优先、老人优先。等等
  • 系统优先级:优先使用cpu资源;

4.2 为何需要优先级

  • 举个例子:海底捞火锅正常情况下响应就特别慢,那
    么当节假日时人员突增会导致处理请求特别慢;
    • 那假设我是海底捞VIP客户(最高优先级),无论多么繁忙,我都无需排队,海底捞人员会直接服务于我,满足我的需求。
    • 如果我不是VIP的人员(较低优先级)则进入排队等待状态;

4.3 进程如何配置优先级

  • 在启动进程时,为不同的进程使用不同的调度策略。
  • nice 值越高: 表示优先级越低,例如 +19 ,该进程容易将 CPU 使用量让给其他进程;
  • nice 值越低: 表示优先级越高,例如 -20 ,该进程不倾向于让出 CPU ;

4.4 进程优先级如何查看

1.使用 top 命令查看优先级;

# NI:显示nice值,默认是0。
# PR: 显示nice值,-20映射到0,+19映射到39
PID USER   PR NI  VIRT  RES  SHR
S %CPU %MEM   TIME+ COMMAND
1083 root    20  0  298628  2808  1544
S  0.3  0.1  2:49.28 vmtoolsd
5  root    0 -20    0    0    0
S  0.0  0.0  0:00.00 kworker/0:+

2.使用 ps 命令查看进程优先级;

[root@node ~]# vim
[root@node ~]# ps axo command,nice |grep
vim|grep -v grep
vim 

4.5 指定进程启动优先级nice

1.启动 vim 并且指定程序优先级为 -5

[root@node ~]# nice -n -5 vim &
[1] 98417

2.查看当前 vim 进程的优先级

[root@node ~]# ps axo pid,command,nice
|grep 98417
98417 vim             -5

4.6 修改进程优先级renice

1.查看当前正在运行的 sshd 进程优先级状态

[root@node ~]# ps axo pid,command,nice |grep [s]shd
70840 sshd: root@pts/2        0
98002 /usr/sbin/sshd -D       0

2.调整 sshd 主进程的优先级

[root@node ~]# renice -n -20 98002
98002 (process ID) old priority 0, new
priority -20

3.调整之后需要退出终端,重新打开一个新终端

[root@node ~]# ps axo pid,command,nice
|grep [s]shd
70840 sshd: root@pts/2        0
98002 /usr/sbin/sshd -D      -20
[root@node ~]# exit

4.再次登陆 sshd 服务,会由主进程 fork 子 sshd 进程(那么子进程会继承主进程的优先级)

[root@node ~]# ps axo pid,command,nice
|grep [s]shd
98002 /usr/sbin/sshd -D      -20
98122 sshd: root@pts/0       -20

5. 后台进程管理

5.1 什么是后台进程

通常进程都会在终端前台运行,一旦关闭终端,进程也
会随着结束;
那么此时我们就希望进程能在后台运行,就是将在前台
运行的进程放入后台运行,这样及时我们关闭了终端也
不影响进程的正常运行。

5.2 为什么需要后台运行

比如:我们此前在国内服务器往国外服务器传输大文件
时,由于网络的问题需要传输很久,如果在传输的过程
中出现网络抖动或者不小心关闭了终端则会导致传输失
败,如果能将传输的进程放入后台,是不是就能解决此
类问题了。

5.3 如何将进程转为后台

早期的时候大家都选择使用 nohup + & 符号将进程放入
后台,然后在使用 jobs、bg、fg 等方式查看进程状
态,但太麻烦了 也不直观,所以我们推荐使用
screen

5.3.1 nohup方式

1.使用 nohup 将前台进程转换后台运行

[root@node ~]# nohup sleep 3000 &

2.查看进程运行情况

[root@node ~]# ps aux |grep sleep
root    75118  74766  0 11:10 pts/0 
 00:00:00 sleep 3000

3.使用 job bg fg 等方式查看后台作业

[root@node ~]# jobs # 查看后台作业
[1]+ Running sleep 3000 &
[root@ansible ~]# fg %1  # 转为前台运行
[root@ansible ~]# bg %1  # 转为后台运行

5.3.2 screen方式

1.安装 screen 工具

[root@web ~]# yum install screen -y

2.开启一个 screen 子窗口,可以通过 -S 为其指定名称

[root@web ~]# screen -S wget_soft

3.在 screen 窗口中执行任务,可以执行前台运行的任务

4.平滑退出 screen ,但不会终止 screen 中的前台任务

# ctrl+a+d

5.查看当前有多少 screen 正在运行

[root@web ~]# screen -list
There is a screen on:
22058.wget_soft (Detached)
1 Socket in /var/run/screen/S-root.

6.可以通过 screen 的id 或 screen 的标签名称进入

[root@web ~]# screen -r wget_soft
[root@web ~]# screen -r 22058
[root@web ~]# exit         # 退出进程,结束screen

6.系统平均负载

  • 每次发现系统变慢时,通常做的第一件事,就是执行
    top 或 uptime 来了解系统的负载情况。
  • 比如像下面这样,我在命令行里输入了 uptime 命
    令,系统也随即给出了结果
[root@node ~]# uptime
04:49:26 up 2 days,  2:33,  2 users, load
average: 0.70, 0.04, 0.05
# 前面几列,它们分别是当前时间、系统运行时间以及正在
登录用户数。
# 而最后三个数字呢,依次则是过去 1 分钟、5 分钟、15
分钟的平均负载(Load Average)

6.1 什么是平均负载

  • 平均负载是单位时间内的 CPU 使用率吗;
    • 上面的 0.70 代表 CPU 使用率是 70% 其实不是;
  • 那如何理解平均负载:
    • 平均负载是指单位时间内,系统处于 可运行状态 和
      不可中断状态 的平均进程数,也就是平均活跃进程
      数;或者理解"平均负载"是"单位时间内的活跃进程数";
    • 平均负载与 CPU 使用率并没有直接关系;

6.1.1 可运行状态

  • 可运行状态进程:
  • 指正在使用 CPU 或者正在等待 CPU 的进程,也就是
    我们 ps 命令看到处于 R,S 状态的进程

6.1.2 不可中断状态

  • 不可中断进程:
  • 系统中最常见的是等待硬件设备的 I/O 响应,通过
    ps 命令中看到 D(Disk Sleep) 的进程。
  • 例如:当一个进程向磁盘读写数据时,为了保证数据
    的一致性,在得到磁盘回复前,它是不能被其他进程
    或者中断打断的,这个时候的进程就处于不可中断状
    态。如果此时的进程被打断了,就容易出现磁盘数据
    与进程数据不一致的问题;
  • 所以,不可中断状态实际上是系统对进程和硬件设备
    的一种保护机制;

6.2 平均负载为多少时合理

  • 理想的状态是每个 CPU 上都刚好运行着一个进程,这
    样每个 CPU 都得到了充分利用。
  • 所以在评判平均负载时,首先你要知道系统有几个
    CPU 通过 top 命令获取,或 /proc/cpuinfo
  • 示例:假设现在在 4、2、1 核的 CPU 上,如果平均负
    载为 2 时,意味着什么;
    • 1.在4个 CPU 的系统上,意味着 CPU 有 50% 的空
      闲;
    • 2.在2个 CPU 的系统上,意味着所有的 CPU 都刚好
      被完全占用;
    • 3.而1个 CPU 的系统上,则意味着有一半的进程竞
      争不到 CPU ;
  • 平均负载有三个数值,我们应该关注哪个呢?
  • 实际上,平均负载中的三个指标我们其实都需要关
    注。(就好比一天的天气要结合起来看;)
  • 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相
    差不大,那就说明系统负载很平稳;
  • 1分钟的值小于15分钟的值,说明系统最近1分钟的负
    载在减少,而过去 15 分钟内却有很大的负载;
  • 如果 1 分钟的值远大于 15 分钟的值,就说明最近 1
    分钟的负载在增加,这种增加有可能只是临时性的,
    也有可能还会持续上升,所以就需要持续观察。
  • 一旦 1 分钟的平均负载接近或超过了 CPU 的个数,
    就意味着系统正在发生过载的问题,这时就得分析问
    题,并要想办法优化了;
  • 例:假设我们在有2个 CPU 系统上看到平均负载为
    2.73,6.90,12.98
    • 那么说明在过去1分钟内,系统有 136% 的超载
      (2.73/2=136%)
    • 而在过去5分钟内,有 345% 的超载
      (6.90/2=345%)
    • 而在过去15分钟内,有 649% 的超载
      (12.98/2=649%)
    • 但从整体趋势来看,系统的负载是在逐步的降低。

6.3 平均负载与CPU使用率

  • 在实际工作中,我们经常容易把平均负载和 CPU 使
    用率混淆,所以在这里,我也做一个区分;
  • 既然平均负载代表的是活跃进程数,那平均负载高
    了,不就意味着 CPU 使用率高吗?
  • 我们回到平均负载的含义上来,平均负载是指单位时
    间内,处于可运行状态和不可中断状态的进程数;
  • 所以,它不仅包括了正在使用 CPU 的进程,还包括等
    待 CPU 和等待 I/O 的进程;
  • 而 CPU 使用率,是单位时间内 CPU 繁忙情况的统计,
    跟平均负载并不一定完全对应。比如:
    • CPU 密集型进程,使用大量 CPU 计算会导致平均负
      载升高,此时这两者是一致的;
    • I/O 密集型进程,等待 I/O 也会导致平均负载升
      高,但 CPU 使用率不一定很高;
    • 大量的 CPU 进程调度也会导致平均负载升高,此时
      的 CPU 使用率也会比较高;

6.4 平均负载案例分析实战

  • 演示这三种常场景,并用 stress、mpstat、
    pidstat 等工具,找出平均负载升高的根源;
  • stress 是 Linux 系统压力测试工具,这里我们用作
    异常进程模拟平均负载升高的场景;
  • mpstat 是多核 CPU 性能分析工具,用来实时查看每
    个 CPU 的性能指标,及所有 CPU 的平均指标;
  • pidstat 是一个常用的进程性能分析工具,用来实时
    查看进程的 CPU、Mem、I/O 等性能指标;
# yum install stress sysstat -y
#如果出现无法使用mpstat、pidstat命令查看%wait指标建议更新下软件包
wget http://pagesperso-orange.fr/sebastien.godard/sysstat-11.7.3-1.x86_64.rpm
rpm -Uvh sysstat-11.7.3-1.x86_64.rpm

6.4.1 场景1-CPU密集型进程

1.第一个终端运行 stress 命令,模拟一个 CPU 使用率
100% 的场景:

[root@node ~]# stress --cpu 1 --timeout
600

2.第二个终端运行 uptime 查看平均负载的变化情况

# 使用watch -d 参数表示高亮显示变化的区域(注意负载会持续升高)
[root@node ~]# watch -d uptime
17:27:44 up 2 days,  3:11,  3 users, load
average: 1.10, 0.30, 0.17

3.在第三个终端运行 mpstat 查看 CPU 使用率的变化情况

# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5秒后输出一组数据
[root@node ~]# mpstat -P ALL 5
Linux 3.10.0-957.1.3.el7.x86_64 (m01)
2019年04月29日 _x86_64_ (1 CPU)
17时32分03秒 CPU  %usr  %nice  %sys
%iowait  %irq  %soft %steal %guest
%gnice  %idle
17时32分08秒 all  99.80   0.00   0.20 
 0.00   0.00   0.00   0.00   0.00 
 0.00   0.00
17时32分08秒   0  99.80   0.00   0.20 
 0.00   0.00   0.00   0.00   0.00 
 0.00   0.00
#单核CPU所以只有一个all和0

4.从终端二中可以看到,1分钟的平均负载会慢慢增加到
1.00 ,而从终端三中还可以看到,正好有一个 CPU 的
使用率为 100% ,但它的 iowait 为0。这说明,平均负
载的升高正是由于 CPU 使用率为 100% 。那么,到底是
哪个进程导致了 CPU 使用率为 100% 呢?可以使用
pidstat 来查询

# 间隔 5 秒后输出一组数据
[root@node ~]# pidstat -u 5 1
Linux 3.10.0-957.1.3.el7.x86_64 (m01)
2019年04月29日 _x86_64_(1 CPU)
17时33分21秒  UID    PID  %usr %system
%guest  %CPU  CPU Command
17时33分26秒   0   110019  98.80   0.00
  0.00  98.80   0 stress
#从这里可以明显看到,stress 进程的 CPU 使用率为
100%。

6.4.2 场景2 -I/O密集型进程

1.在第一个终端运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync

[root@node ~]# stress --io 1 --timeout
600s

2.在第二个终端运行 uptime 查看平均负载的变化情况:

[root@node ~]# watch -d uptime
18:43:51 up 2 days,  4:27,  3 users, load
average: 1.12, 0.65, 0.00

3.最后第三个终端运行 mpstat 查看 CPU 使用率的变化情况:

# 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
[root@node ~]# mpstat -P ALL 5
Linux 3.10.0-693.2.2.el7.x86_64 (bgx.com)
2019年05月07日 _x86_64_ (1 CPU)
14时20分07秒 CPU  %usr  %nice  %sys
%iowait  %irq  %soft %steal %guest
%gnice  %idle
14时20分12秒 all   0.20   0.00  82.45 
17.35   0.00   0.00   0.00   0.00 
 0.00   0.00
14时20分12秒   0   0.20   0.00  82.45 
17.35   0.00   0.00   0.00   0.00 
 0.00   0.00
#会发现cpu的与内核打交道的sys占用非常高

4.导致 iowait 高,我们需要用 pidstat 来查询

# 间隔 5 秒后输出一组数据,-u 表示 CPU 指标
[root@node ~]# pidstat -u 5 1
Linux 3.10.0-957.1.3.el7.x86_64 (m01)
2019年04月29日 _x86_64_(1 CPU)
18时29分37秒  UID    PID  %usr %system
%guest  %wait  %CPU  CPU Command
18时29分42秒   0   127259  32.60   0.20
  0.00  67.20  32.80   0 stress
18时29分42秒   0   127261   4.60  28.20
  0.00  67.20  32.80   0 stress
18时29分42秒   0   127262   4.20  28.60
  0.00  67.20  32.80   0 stress
#可以发现,还是 stress 进程导致的。

6.4.3 场景3-大量的进程

1.在第一个终端使用 stress ,但这次模拟的是 4 个进程

[root@node ~]# stress -c 4 --timeout 600

2.由于系统只有 1 个 CPU ,明显比 4 个进程要少得多,因而,系统的 CPU 处于严重过载状态*

[root@node ~]# watch -d uptime
19:11:07 up 2 days,  4:45,  3 users, load
average: 4.65, 2.65, 4.65

3.最后通过 pidstat 查询进程的情况:可以看出 4 个进程在争抢 1 个 CPU 每个进程等待 CPU 的时间(也就是代码块中的 %wait 列)高达 75% 。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。

# 间隔 5 秒后输出一组数据
[root@node ~]# pidstat -u 5 1
平均时间:  UID    PID  %usr %system
%guest  %wait  %CPU  CPU Command
平均时间:   0   130290  24.55   0.00 
 0.00  75.25  24.55   - stress
平均时间:   0   130291  24.95   0.00 
 0.00  75.25  24.95   - stress
平均时间:   0   130292  24.95   0.00 
 0.00  75.25  24.95   - stress
平均时间:   0   130293  24.75   0.00 
 0.00  74.65  24.75   - stress

6.4.4 总结

  • 分析完这三个案例,我再来归纳一下平均负载与CPU
  • 平均负载提供了一个快速查看系统整体性能的手段,
    反映了整体的负载情况。但只看平均负载本身,我们
    并不能直接发现,到底是哪里出现了瓶颈。所以,在
    理解平均负载时,也要注意:
  • 平均负载高有可能是 CPU 密集型进程导致的;
  • 平均负载高并不一定代表 CPU 使用率高,还有可能
    是 I/O 更繁忙了;
  • 当发现负载高的时候,你可以使用 mpstat、pidstat
    等工具,辅助分析负载的来源
posted @ 2021-08-01 16:26  GaoBeier  阅读(210)  评论(0编辑  收藏  举报