Fork me on GitHub

cpu 内存磁盘 io 过高问题处理

CPU 占用过高分析

可以用 top 命令查看哪一个进程占用 cpu 高 或者哪一个占用内存大

top - 13:55:32 up 59 days, 19:18,  2 users,  load average: 0.00, 0.04, 0.09
Tasks: 161 total,   1 running, 160 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.7 us,  0.3 sy,  0.0 ni, 96.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16267564 total,   271608 free,  9033932 used,  6962024 buff/cache
KiB Swap:  8388604 total,  8364736 free,23868 used.  5913400 avail Mem 

  PID USER  PR  NIVIRTRESSHR S  %CPU %MEM TIME+ COMMAND  
29433 wuuser20   0 7805852 1.132g  19216 S   0.7  7.3   6:07.13 java 
29355 wuuser20   0 6909304 1.093g  17248 S   0.3  7.0   2:29.96 java 
29558 wuuser20   0 7763476 974788  15860 S   0.3  6.0   1:54.47 java 
29945 wuuser20   0 7793536 1.202g  21344 S   0.3  7.7   4:31.02 java

可以看到占用最高的是 29433 进程

top -H -p pid 命令查看进程内各个线程占用的 CPU 百分比 ( top -Hp 29433)cpu 消耗情况

 top -H -p 29433
top - 13:58:57 up 59 days, 19:22,  2 users,  load average: 0.04, 0.07, 0.10
Threads: 132 total,   0 running, 132 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.0 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16267564 total,   271024 free,  9034476 used,  6962064 buff/cache
KiB Swap:  8388604 total,  8364736 free,23868 used.  5913044 avail Mem 
  PID USER  PR  NIVIRTRESSHR S %CPU %MEM TIME+ COMMAND   
29433 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.00 java  
29436 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:08.91 java  
29437 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.34 java  
29438 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.35 java  
29439 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.34 java  
29440 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.34 java  
29441 wuuser20   0 7805852 1.132g  19216 S  0.0  7.3   0:00.34 java

上面看到线程 29436 占用高时长多

接着 使用 printf "%x\n" 线程号 将异常线程号转化为 16 进制

printf "%x\n" 29436
72fc

接着使用jstack 29433|grep 72fc -A90 来定位出现异常的代码

 jstack 29433|grep 72fc -A90
"main" prio=10 tid=0x00007f16fc00e000 nid=0x72fc in Object.wait() [0x00007f17056d9000]
   java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000778044670> (a java.lang.Class for com.wu.mortgage.service.OrderServiceStartup)
at java.lang.Object.wait(Object.java:503)
at com.wu.mortgage.service.OrderServiceStartup.main(OrderServiceStartup.java:47)
- locked <0x0000000778044670> (a java.lang.Class for com.wu.mortgage.service.OrderServiceStartup)

"VM Thread" prio=10 tid=0x00007f16fc14a000 nid=0x7309 runnable 

"Gang worker#0 (Parallel GC Threads)" prio=10 tid=0x00007f16fc01f800 nid=0x72fd runnable 

"Gang worker#1 (Parallel GC Threads)" prio=10 tid=0x00007f16fc021800 nid=0x72fe runnable 

"Gang worker#2 (Parallel GC Threads)" prio=10 tid=0x00007f16fc023000 nid=0x72ff runnable 

"Gang worker#3 (Parallel GC Threads)" prio=10 tid=0x00007f16fc025000 nid=0x7300 runnable 

"Gang worker#4 (Parallel GC Threads)" prio=10 tid=0x00007f16fc027000 nid=0x7301 runnable 

"Gang worker#5 (Parallel GC Threads)" prio=10 tid=0x00007f16fc029000 nid=0x7302 runnable 

"Gang worker#6 (Parallel GC Threads)" prio=10 tid=0x00007f16fc02b000 nid=0x7303 runnable 

"Gang worker#7 (Parallel GC Threads)" prio=10 tid=0x00007f16fc02d000 nid=0x7304 runnable 

"Concurrent Mark-Sweep GC Thread" prio=10 tid=0x00007f16fc106800 nid=0x7307 runnable 
"Gang worker#0 (Parallel CMS Threads)" prio=10 tid=0x00007f16fc102000 nid=0x7305 runnable 

"Gang worker#1 (Parallel CMS Threads)" prio=10 tid=0x00007f16fc104000 nid=0x7306 runnable 

"VM Periodic Task Thread" prio=10 tid=0x00007f16fcbed800 nid=0x7314 waiting on condition 

JNI global references: 522

CPU 使用率较低但负载较高

问题描述:

Linux 系统没有业务程序运行,通过 top 观察,类似如下图所示,CPU 很空闲,但是 load average 却非常高:

处理办法:

load average 是对 CPU 负载的评估,其值越高,说明其任务队列越长,处于等待执行的任务越多。
出现此种情况时,可能是由于僵死进程导致的。可以通过指令 ps -axjf 查看是否存在 D 状态进程。
D 状态是指不可中断的睡眠状态。该状态的进程无法被 kill,也无法自行退出。只能通过恢复其依赖的资源或者重启系统来解决。

内存占用过高

使用free -h 查看内存使用情况

topm 查看内存可以看到使用率 / 总内存 KiB Mem : 63.6/1626756

 free -h
  totalusedfree  shared  buff/cache   available
Mem:15G8.6G274M854M6.6G5.7G
Swap:  8.0G 23M8.0G

top 按 m 查看内存可以看到使用率 / 总内存

KiB Mem : 63.6/16267564
top - 14:32:12 up 59 days, 19:55,  2 users,  load average: 0.01, 0.06, 0.05
Tasks: 160 total,   1 running, 159 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.8 us,  0.2 sy,  0.0 ni, 98.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 63.6/16267564 [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||]
KiB Swap:  0.3/8388604  []

  PID USER  PR  NIVIRTRESSHR S  %CPU %MEM TIME+ COMMAND  
 1515 wuuser20   0  157716   2288   1536 R   0.7  0.0   0:00.13 top  
10262 root  20   0   0  0  0 S   0.3  0.0   0:00.31 kworker/2:1  
29433 wuuser20   0 7806112 1.133g  19216 S   0.3  7.3   6:23.73 java 
29754 wuuser20   0 6991120 764416  11932 S   0.3  4.7   5:50.32 java 
29945 wuuser20   0 7793536 1.202g  21344 S   0.3  7.7   4:41.44 java 
1 root  20   0  191152   3040   2108 S   0.0  0.0  10:59.88 systemd  
2 root  20   0   0  0  0 S   0.0  0.0   0:01.54 kthreadd 
3 root  20   0   0  0  0 S   0.0  0.0   0:11.69 ksoftirqd/0  
5 root   0 -20   0  0  0 S   0.0  0.0   0:00.00 kworker/0:0H 
7 root  rt   0   0  0  0 S   0.0  0.0   0:04.75 migration/0

cat /proc/meminfo查看内存信息

cat /proc/meminfo
MemTotal:   16267564 kB
MemFree:  279388 kB
MemAvailable:5926640 kB
Buffers:   0 kB
Cached:  6471844 kB
SwapCached:  708 kB
Active: 11110540 kB
Inactive:4181420 kB
Active(anon):8299564 kB
Inactive(anon):  1395416 kB
Active(file):2810976 kB
Inactive(file):  2786004 kB
Unevictable:   0 kB
Mlocked:   0 kB
SwapTotal:   8388604 kB
SwapFree:8364736 kB
Dirty:   192 kB
Writeback: 0 kB
AnonPages:   8819440 kB
Mapped:98168 kB
Shmem:874860 kB
Slab: 495476 kB
SReclaimable: 388612 kB
SUnreclaim:   106864 kB
KernelStack:   16560 kB
PageTables:27572 kB
NFS_Unstable:  0 kB
Bounce:0 kB
WritebackTmp:  0 kB
CommitLimit:16522384 kB
Committed_AS:   27461628 kB
VmallocTotal:   34359738367 kB
VmallocUsed:  179248 kB
VmallocChunk:   34359341052 kB
HardwareCorrupted: 0 kB
AnonHugePages:   7559168 kB
HugePages_Total:   0
HugePages_Free:0
HugePages_Rsvd:0
HugePages_Surp:0
Hugepagesize:   2048 kB
DirectMap4k:   81856 kB
DirectMap2M:16695296 kB

查看占用内存最大的 10 个进程:

ps -aux | sort -k4nr | head -n 10

查看内存占用最大的进程的命令:

ps aux| grep -v "USER" |sort -n -r -k 4 |awk 'NR==1{print $0}'

io 过高现象

iostat 查看 io 情况

linux 机器 wa% 过高

top
top - 15:35:47 up 265 days, 23:08,  6 users,  load average: 0.03, 0.12, 0.13
Tasks: 203 total,   1 running, 202 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.1 us,  0.2 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 18497460 total,   581076 free,  3876592 used, 14039792 buff/cache
KiB Swap:  4063228 total,  4003928 free,59300 used. 13227728 avail Mem 

  PID USER  PR  NIVIRTRESSHR S  %CPU %MEM TIME+ COMMAND  
12850 root  20   0 9316608 335148  11836 S  11.1  1.8 104:05.35 java 
1 root  20   0   44188   6664   3916 S   0.0  0.0 216:00.79 systemd  
2 root  20   0   0  0  0 S   0.0  0.0   0:24.61 kthreadd 
3 root  20   0   0  0  0 S   0.0  0.0   0:11.27 ksoftirqd/0  
5 root   0 -20   0  0  0 S   0.0  0.0   0:00.00 kworker/0:0H

us:用户态使用的 cpu 时间比

sy:系统态使用的 cpu 时间比

ni:用做 nice 加权的进程分配的用户态 cpu 时间比

id:空闲的 cpu 时间比

wa:cpu 等待磁盘写入完成时间

hi:硬中断消耗时间

si:软中断消耗时间

st:虚拟机偷取时间

如果一台机器看到 wa 特别高,那么一般说明是磁盘 IO 出现问题,可以使用 iostat 等命令继续进行详细分析。

安装 iostat

yum install sysstat

安装后就可以使用 iostat 命令了

iostat -d -k 2

参数 -d 表示,显示设备(磁盘)使用状态;-k某些使用 block 为单位的列强制使用 Kilobytes 为单位;2表示,数据显示每隔 2 秒刷新一次。

iostat -d -k 2
Linux 3.10.0-327.el7.x86_64 (szfyruat01)07/11/2018  _x86_64_(8 CPU)

Device:tpskB_read/skB_wrtn/skB_readkB_wrtn
sda   0.9810.34 9.89  237682005  227295642
sdb   0.64 0.79 9.37   18104315  215368108
dm-0  1.46 1.2419.26   28388124  442501536
dm-1  0.00 0.00 0.01  39692 127628

Device:tpskB_read/skB_wrtn/skB_readkB_wrtn
sda   0.50 4.00 0.00  8  0
sdb   0.00 0.00 0.00  0  0
dm-0  0.50 4.00 0.00  8  0
dm-1  0.00 0.00 0.00  0  0

tps:该设备每秒的传输次数(Indicate the number of transfers per second that were issued to the device.)。”一次传输”意思是”一次 I/O 请求”。多个逻辑请求可能会被合并为”一次 I/O 请求”。”一次传输”请求的大小是未知的。

kB_read/s:每秒从设备(drive expressed)读取的数据量;

kB_wrtn/s:每秒向设备(drive expressed)写入的数据量;

kB_read:读取的总数据量;

kB_wrtn:写入的总数量数据量;这些单位都为 Kilobytes。

指定监控的设备名称为sda,该命令的输出结果和上面命令完全相同

iostat -d sda 2
Linux 3.10.0-327.el7.x86_64 (szfyruat01)07/11/2018  _x86_64_(8 CPU)

Device:tpskB_read/skB_wrtn/skB_readkB_wrtn
sda   0.9810.34 9.89  237685197  227298479

Device:tpskB_read/skB_wrtn/skB_readkB_wrtn
sda   0.00 0.00 0.00  0  0

Device:tpskB_read/skB_wrtn/skB_readkB_wrtn
sda   0.00 0.00 0.00  0  0

iostat还有一个比较常用的选项 -x,该选项将用于显示和 io 相关的扩展数据。

iostat -d -x -k 1 10


iostat -d -x -k 1 10
Linux 3.10.0-327.el7.x86_64 (szfyruat01)07/11/2018  _x86_64_(8 CPU)

Device: rrqm/s   wrqm/s r/s w/srkB/swkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda   0.00 0.070.310.6810.34 9.8941.10 0.004.251.365.55   0.90   0.09
sdb   0.00 0.130.100.54 0.79 9.3731.86 0.005.820.556.77   1.55   0.10
dm-0  0.00 0.000.051.42 1.2419.2628.02 0.016.201.836.35   0.96   0.14
dm-1  0.00 0.000.000.00 0.00 0.01 8.04 0.009.084.77   10.39   0.69   0.00

Device: rrqm/s   wrqm/s r/s w/srkB/swkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda   0.00 0.000.000.00 0.00 0.00 0.00 0.000.000.000.00   0.00   0.00
sdb   0.00 0.000.000.00 0.00 0.00 0.00 0.000.000.000.00   0.00   0.00
dm-0  0.00 0.000.000.00 0.00 0.00 0.00 0.000.000.000.00   0.00   0.00
dm-1  0.00 0.000.000.00 0.00 0.00 0.00 0.000.000.000.00   0.00   0.00

rrqm/s:每秒这个设备相关的读取请求有多少被 Merge 了(当系统调用需要读取数据的时候,VFS 将请求发到各个 FS,如果 FS 发现不同的读取请求读取的是相同 Block 的数据,FS 会将这个请求合并 Merge);

wrqm/s:每秒这个设备相关的写入请求有多少被 Merge 了。

rsec/s:每秒读取的扇区数;

wsec/:每秒写入的扇区数。

rKB/s:The number of read requests that were issued to the device per second;

wKB/s:The number of write requests that were issued to the device per second;

avgrq-sz 平均请求扇区的大小

avgqu-sz 是平均请求队列的长度。毫无疑问,队列长度越短越好。

await: 每一个 IO 请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为 IO 的响应时间,一般地系统 IO 响应时间应该低于 5ms,如果大于 10ms 就比较大了。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await 大于 svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。

svctm 表示平均每次设备 I/O 操作的服务时间(以毫秒为单位)。如果 svctm 的值与 await 很接近,表示几乎没有 I/O 等待,磁盘性能很好,如果 await 的值远高于 svctm 的值,则表示 I/O 队列等待太长,系统上运行的应用程序将变慢。

%util: 在统计时间内所有处理 IO 时间,除以总共统计时间。例如,如果统计间隔 1 秒,该设备有 0.8 秒在处理 IO,而 0.2 秒闲置,那么该设备的 %util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是 100% 表示设备已经接近满负荷运行了(当然如果是多磁盘,即使 %util 是 100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。

常见用法

iostat -d -k 1 10 #查看 TPS 和吞吐量信息(磁盘读写速度单位为 KB)
iostat -d -m 2 #查看 TPS 和吞吐量信息(磁盘读写速度单位为 MB)
iostat -d -x -k 1 10 #查看设备使用率(%util)、响应时间(await) iostat -c 1 10 #查看 cpu 状态

查找引起高 I/O wait 对应的进程

yum -y install iotop

查找引起高I/O wait 对应的进程

[root@localhost ~]# iotop

 iotop
30475 be/4 root2.80 K/s0.00 B/s  0.00 %  0.00 % [cifsd]
Total DISK READ :1915.31 B/s | Total DISK WRITE :  22.44 K/s
Actual DISK READ:   0.00 B/s | Actual DISK WRITE:   0.00 B/s
  TID  PRIO  USER DISK READ  DISK WRITE  SWAPIN IO>COMMAND   
20041 be/4 root0.00 B/s0.00 B/s  0.00 %  0.07 % java -Djava.util.logging.config.file=/home/rizhi/apache-tomcat-7.0.88/conf/logging.pro~pdir=/home/rizhi/apache-tomcat-7.0.88/temp org.apache.catalina.startup.Bootstrap start
12881 be/4 root0.00 B/s   14.96 K/s  0.00 %  0.00 % java -Djava.util.logging.config.file=/home/rizhi/apache-tomcat-7.0.88/conf/logging.pro~pdir=/home/rizhi/apache-tomcat-7.0.88/temp org.apache.catalina.startup.Bootstrap start
13150 be/4 agent   0.00 B/s3.74 K/s  0.00 %  0.00 % falcon-agent -c /open-falcon/agent/config/cfg.json
30475 be/4 root 1915.31 B/s0.00 B/s  0.00 %  0.00 % [cifsd]
20607 be/4 root0.00 B/s3.74 K/s  0.00 %  0.00 % java -Djava.util.logging.config.file=/home/rizhi/apache-tomcat-7.0.88/conf/logging.pro~pdir=/home/rizhi/apache-tomcat-7.0.88/temp org.apache.catalina.startup.Bootstrap start
 4096 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % dockerd --insecure-registry 192.168.16.184:5000 --log-opt max-size=100m --log-opt max-file=3 --insecure-registry 192.168.34.138:5000
1 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % systemd --system --deserialize 26
2 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % [kthreadd]
3 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
 4100 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --met~un/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
5 be/0 root0.00 B/s0.00 B/s  0.00 %  0.00 % [kworker/0:0H]
 4102 be/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --met~un/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
7 rt/4 root0.00 B/s0.00 B/s  0.00 %  0.00 % [migration/0]

iotop 命令简介

iotop 根据 Linux 内核(需要 2.6.20 及以上)来监测 I/O,并且能显示当前进程 / 线程的 I/O 使用率。

Linux 内核 build 的事后哦,需要开启 CONFIG_TASK_DELAY_ACCT 和 CONFIG_TASK_IO_ACCOUNTING 选项,这些选项依赖于 CONFIG_TASKSTATS。在采样周期里,iotop 按列显示每个进程 / 线程的 I/O 读写带宽,同时也显示进程 / 线程做 swap 交换和等待 I/O 所占用的百分比。

每一个进程都会显示 I/O 优先级 (class/level),另外在最上面显示每个采样周期内的读写带宽。
使用左右箭头来改变排序,r 用来改变排序顺序,o 用来触发–only 选项,p 用来触发–processes 选项。
a 用来触发–accumulated 选项,q 用来退出,i 用来改变进程或线程的监测优先级,其它任继健是强制刷新。

选项

--version 显示版本号然后退出
-h, --help 显示帮助然后退出
-o, --only 只显示正在产生 I/O 的进程或线程。除了传参,可以在运行过程中按 o 生效。
-b, --batch 非交互模式,一般用来记录日志
-n NUM, --iter=NUM 设置监测的次数,默认无限。在非交互模式下很有用
-d SEC, --delay=SEC 设置每次监测的间隔,默认 1 秒,接受非×××数据例如 1.1
-p PID, --pid=PID 指定监测的进程 / 线程
-u USER, --user=USER 指定监测某个用户产生的 I/O
-P, --processes 仅显示进程,默认 iotop 显示所有线程
-a, --accumulated 显示累积的 I/O,而不是带宽
-k, --kilobytes 使用 kB 单位,而不是对人友好的单位。在非交互模式下,脚本编程有用。
-t, --time 加上时间戳,非交互非模式。
-q, --quiet 禁止头几行,非交互模式。有三种指定方式。
       -q     只在第一次监测时显示列名
       -qq    永远不显示列名。
       -qqq   永远不显示 I/O 汇总。

只显示有 I/O 行为的进程

iotop -oP
Total DISK READ :  18.12 K/s | Total DISK WRITE :   7.63 K/s
Actual DISK READ:   0.00 B/s | Actual DISK WRITE:   0.00 B/s
  PID  PRIO  USER DISK READ  DISK WRITE  SWAPIN IO>COMMAND   
12850 be/4 root0.00 B/s7.63 K/s  0.00 %  0.01 % java -Djava.util.logging.config.file=/home/rizhi/apache-tomcat-7.0.88/conf/logging.pro~pdir=/home/rizhi/apache-tomcat-7.0.88/temp org.apache.catalina.startup.Bootstrap start
30475 be/4 root   18.12 K/s0.00 B/s  0.00 %  0.00 % [cifsd]

总结

内存过高

查看占用内存最大的 10 个进程:

top 也可以

ps -aux | sort -k4nr | head -n 10

io 过高

首先查看哪些进程的 io 过高

(用 top 查看是否很高,让后用iostat -x -d 1 定哪个设备 IO 负载高)

然后用 iotop -oP 查看哪一个进程的 io 高 也可以用iostat -x -d 1 定哪个设备 IO 负载高

确定的进程 pid 后,可以用ps -ef |grep pid 查看哪一个应用引起的,看看是否需要重启服务 减少 io

也可以用top -H -p pid 查看这个进程中线程消耗资源情况

赞赏是最好的支持与鼓励!
-------------本文结束感谢您的阅读-------------