0
点赞
收藏
分享

微信扫一扫

面试官:生产环境发生问题,你一般怎么排查?(Linux工具篇)


面试官:生产环境发生问题,你一般怎么排查?(Linux工具篇)_运维

CPU篇

平均负载

本篇文章是我看了极客时间《Linux性能优化实战》《趣谈网络协议》专栏做的一个总结

当系统变慢时,我们经常用uptime或者top命令来查看系统的负载情况,如下命令所示

[root@VM-0-14-centos ~]# uptime
15:30:04 up 108 days, 23:29, 1 user, load average: 0.07, 0.05, 0.05


含义

15:30:04

当前时间

up 108 days, 23:29

系统运行时间

1 user

正在登陆用户数

load average: 0.07, 0.05, 0.05

过去1分钟, 5分钟,15分钟的平均负载

什么是平均负载?

平均负载是指单位时间内,系统处于可运行状态不可中断状态的平均进程数

可运行状态:正在使用CPU或者等待CPU的进程,即处于Running或Runnable状态
不可中断状态:进程不能被中断,例如进程向磁盘读写数据时,为了维护数据的一致性。在得到磁盘的回复之前,它是不能被打断的(会释放cpu,但是不会响应kill命令等)

CPU的理想状态就是每个CPU上都刚好运行着一个进程,这样可以让CPU得到更充分的利用

当平均负载为2时,对CPU意味着什么呢?

  1. 在有1个CPU的系统上,意味着有一半进程竞争不到CPU
  2. 在有2个CPU的系统上,意味着所有CPU刚好被利用
  3. 在有4个CPU的系统上,意味着CPU有50%的空闲

所以要评判负载是否合理,需要先知道CPU个数,可以通过如下命令获取

[root@VM-0-14-centos ~]# grep 'model name' /proc/cpuinfo | wc -l
2

平均负载为多少时比较合理呢?
其实并没有一个准确的值,我们需要根据历史的监控数据作出相应的判断,看是否有明显升高的趋势。一般情况下当平均负载高于 CPU 数量 70% 的时候,你就应该分析排查负载高的问题了

CPU上下文切换

Linux操作系统是一个多任务操作系统,它支持远大于CPU数量的任务同时运行。当然这些任务并不是真的在同时运行,只是在很短的时间内,CPU轮流执行这些任务,造成多任务同时运行的错觉。

CPU上下文切换就是把上一个任务运行需要的CPU上下文(寄存器和程序计数器)保存下来,加载新任务的CPU上下文到寄存器和程序计数器,然后跳转到程序计数器执行的代码位置,执行新任务

面试官:生产环境发生问题,你一般怎么排查?(Linux工具篇)_linux_02

频繁的上下文切换,会将CPU都耗费在CPU上下文的保存和恢复上,导致任务运行的时间变短,最终影响系统的性能

CPU的上下文切换主要分为如下三种

  1. 进程上下文切换
  2. 线程上下文切换
  3. 中断上下文切换

进程上下文切换

触发进程上下文切换的几个场景如下

  1. 分给进程的时间片被耗尽
  2. 进程在资源资源不足(比如内存不足),或者等待io完成时
  3. 当有优先级更高的进程运行时,为了保证高优先级的进程运行,当前进程会被挂起
  4. 发生硬件中断时,CPU上的进程会被挂起,转而执行内核中的中断服务程序

线程上下文切换

线程是调度的基本单位,而进程则是资源拥有的基本单位

  1. 当进程只有一个线程时,可以认为进程等于线程
  2. 当进程拥有多个线程时,会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时不需要被更改。因此同进程内的线程切换,比多进程间的切换消耗更少的资源
  3. 线程的私有数据,如栈和寄存器,在进行上下文切换时是需要保存的

中断上下文切换

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行。对同一个 CPU 来说,中断处理比进程拥有更高的优先级

针对频繁上下文切换的问题,我们可以使用vmstat命令来查看,cs一列代表了上下文切换的次数

[root@VM-0-14-centos ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 212380 136000 1543228 0 0 0 16 1 2 1 1 99 0 0

system

含义

in

每秒中断的次数

cs

每秒上下文切换次数

如果我们希望对特定的进程进行监控,可以使用pidstat -w命令

pidstat是sysstat工具的一个命令,用于监控全部或指定进程的cpu、内存、线程、设备IO等系统资源的占用情况

pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息

# 每隔3s输出一次数据
[root@VM-0-14-centos ~]# pidstat -w 3
Linux 3.10.0-1127.19.1.el7.x86_64 (VM-0-14-centos) 10/10/2021 _x86_64_ (2 CPU)

08:13:38 PM UID PID cswch/s nvcswch/s Command
08:13:41 PM 0 6 1.66 0.00 ksoftirqd/0
08:13:41 PM 0 7 0.33 0.00 migration/0
08:13:41 PM 0 9 20.27 0.00

结果中的cswch和nvcswch是我们需要重点关注的对象

cswch(自愿上下文切换):进程无法获取所需要的资源,导致的上下文切换。例如IO,内存等系统资源不足时,就会发生自愿上下文切换
nvcswch(非自愿上下文切换):进程由于时间片已到等愿意,被系统强制调度,进而发生的上下文切换。比如,当大量进程都在争抢CPU时,就容易发生非自愿上下文切换

线上CPU飙高如何排查

  1. 先执行top,找到CPU占用比较高的进程
  2. jstack 进程id > show.txt
  3. 找到进程中CPU占用比较高的线程,获取到线程id(执行top -p 高进程pid -H),线程id转为16进制(printf “%x” 高进程pid)
  4. 到show.txt文件中根据线程id查看线程的具体状态即可

分享一个我们使用PageHelper导致死循环的例子

我们有个项目每天晚上定时从数据库获取数据做操作,用PageHelper做了分页,逻辑也很简单

int pageIndex = 0;
while (true) {
// 分页获取数据
int count = getData(pageIndex, pageSize);
if (count == 0) {
break;
}
pageIndex++;
}

这个项目运行了一段时间后,CPU占用越来越高,最终定位到是这段代码死循环了。

死循环原因如下:PageHelper有个属性reasonable,当reasonable = true,offset大于总记录数时,会默认返回最后一页数据,结果就一直能获取数据,造成了死循环

CPU使用率低但是负载高

当系统负载高时,并不意味着CPU资源不足,只是意味着运行的任务过多,这些任务有可能在等待或者使用cpu,也有可能等待IO完成

当系统负载高,并且CPU使用率也比较高时,一般意味着CPU资源不足

而当系统负载高,而CPU使用率比较低时,一般有如下两种情况

  1. CPU频繁的进行上下文切换(比如应用中开启了太多的线程),导致任务执行的时间比较短(利用vmstat命令查看,如果cs列或in列的值很大,说明就是这种情况)
  2. IO任务太多,导致大量进程处于不可中断状态(利用top命令查看,cpu使用百分比中,wa状态(cpu等待io完成)的使用百分比很高时,说明就是这种情况)

CPU问题排查套路

  1. 先top查看系统的负载情况
  2. 如果负载高,CPU高,一般意味着CPU资源不足(也有可能发生死循环之类的)
  3. 如果负载高,CPU低,需要接着排查
    3.1 执行vmstat,查看in列(每秒中断的次数)和cs列(每秒上下文切换次数)比较高,则表明CPU频繁的进行上下文切换
    3.2 top发现cpu的iowait比较高(wa列的值),则利用I/0问题排查套路接着排查

I/O问题排查套路,后面会详细分析

当发现应用频繁的进行上下文切换时,用pidstat -w确定哪个进程频繁的进行上下文切换,接着用pstree pid查看进程开启的线程数量,查看线程数量是否合理

[root@VM-0-14-centos ~]# pstree 31528
java───169*[{java}]

也可以执行如下命令查看Threads列

[root@VM-0-14-centos ~]# cat /proc/31528/status

面试官:生产环境发生问题,你一般怎么排查?(Linux工具篇)_centos_03

内存篇

我们经常用free命令查看系统中内存的使用情况,默认单位是kb,使用时我们一般指定显示单位,如-m -g

[root@VM-0-14-centos ~]# free 
total used free shared buff/cache available
Mem: 3880316 1979852 236792 3100 1663672 1616760
Swap: 0 0 0

可以看到输出总共有两行,分别是物理内存Mem和交换分区Swap的使用情况


含义

total

总内存大小

used

已使用内存大小,包含了共享内存

free

未使用内存的大小

shared

共享内存的大小

buff/cache

buff/cache 是缓存和缓冲区的大小

available

可用内存大小

[root@VM-0-14-centos ~]# free -m
total used free shared buff/cache available
Mem: 3789 1935 228 3 1625 1576
Swap: 0 0 0

available不仅包含free,还包含了可回收的缓存,所以一般比free更大,当然并不是所有缓存都可以被回收,因为有些缓存可能正在使用中

交换分区Swap是做什么用的?

Swap说白了就是把一块磁盘空间或者一个本地文件,当成内存来使用,这样就可以增大系统的可用内存,生产环境我们一般不使用Swap分区。它包括换入和换出的过程

  1. 换出,将进程暂时不用的内存存储到磁盘中,并释放这些数据占用的内存
  2. 换入,当进程再次访问这些内存的时候,将他们从磁盘读到内存中来

怎么理解内存中的Buffer和Cache?

free命令的输出其他列都比较容易理解,Buffer和Cache分别代表什么呢?

从字面来看,Buffer是缓冲区,而Cache是缓存,两者都是数据在内存中的临时存储。那么这两种临时存储有什么区别吗?

Buffer是对磁盘数据的缓存,而Cache是文件数据的缓存,他们既会用到读请求中,也会用到写请求中

如何排查内存泄漏和内存溢出

因为Java程序都是基于堆来管理和使用内存的,所以当我们排查内存泄漏和内存溢出时,一般使用jdk自带的工具

  1. 使用jmap命令生成heapdump文件
  2. 使用Eclipse Memory Analyzer来分析对象的使用情况

IO篇

磁盘的性能指标

使用率:磁盘处理I/O的时间百分比(%util)
饱和度:磁盘处理I/O的繁忙程度(avgqu-sz,排队请求数越多越繁,和你去超市买东西一个道理)
IOPS(Input/Output Per Second):每秒的I/O请求数(r/s+w/s)
吞吐量:每秒的I/O请求大小(rkB/s+wkB/s)
响应时间:I/O请求从发出到收到响应的间隔时间(r_await+w_await)

[root@VM-0-14-centos ~]# iostat -x 1
Linux 3.10.0-1127.19.1.el7.x86_64 (VM-0-14-centos) 10/12/2021 _x86_64_ (2 CPU)

avg-cpu: %user %nice %system %iowait %steal %idle
0.60 0.00 0.53 0.06 0.00 98.81

Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 2.88 0.01 4.11 0.25 32.02 15.67 0.02 4.56 8.79 4.55 0.29 0.12
scd0 0.00 0.00 0.00 0.00 0.00 0.00 18.65 0.00 0.21 0.21 0.00 0.20 0.00


含义

rrqm/s

每秒合并的读请求数,%rrqm表示合并读请求的百分比

wrqm/s

每秒合并的写请求数,%wrqm表示合并写请求的百分比

r/s

每秒发送给磁盘的读请求数,为合并后的请求数

w/s

每秒发送给磁盘的写请求数,为合并后的请求数

rkB/s

每秒从磁盘读取的数据量,单位为kb

wkB/s

每秒向磁盘写入的数据量,单位为kb

avgrq-sz

每个IO的平均扇区数,即所有请求的平均大小,以扇区(512字节)为单位

avgqu-sz

平均未完成的IO请求数量,即平均意义上的请求队列长度

await

平均每次 I/O 操作的时间,包括队列中的等待时间和设备实际处理的时间,单位为毫秒

r_await

读请求处理完成等待时间,包括队列中的等待时间和设备实际处理的时间,单位为毫秒

w_await

写请求处理完成等待时间,包括队列中的等待时间和设备实际处理的时间,单位为毫秒

svctm

处理I/O请求所需的平均时间(不包括等待时间),单位为毫秒。这是推断的数据,并不保证完全准确

%util

磁盘处理I/O的时间百分比,即使用率,由于可能存在并行I/O,100%并不一定表明磁盘I/O饱和

合并请求怎么理解?

块设备有相应的调度算法。如果两个IO发生在相邻的数据块时,他们可以合并成1个IO。
你可以类比送快递,假如快递员要送的快递在2,16,5,17楼。快递员肯定是先送2,5楼的快递。再送16,17楼的快递。而不是依次送2,16,5,17楼的快递

进程I/O监测

iostat只提供磁盘整体的I/O数据,如果要观察进程的I/O情况,我们可以使用pidstat命令

[root@VM-0-14-centos ~]# pidstat -d
Linux 3.10.0-1127.19.1.el7.x86_64 (VM-0-14-centos) 10/12/2021 _x86_64_ (2 CPU)

02:06:44 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
02:06:44 PM 0 1 0.14 4.00 0.40 systemd
02:06:44 PM 0 35 0.00 0.00 0.00


含义

UID

用户id

PID

进程id

kB_rd/s

每秒读取的数据大小,单位kb

kB_wr/s

每秒发出的写请求数据大小,单位kb

kB_ccwr/s

每秒取消的写请求数据大小,单位kb

查看进程具体读写的文件和内容

我们一般用strace+lsof命令来查看进程具体读写的文件和内容

strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间

lsof(list open files)是一个查看进程打开的文件的工具。在linux系统中,一切皆文件,所以lsof命令不仅可以查看进程打开的文件、目录,还可以查看进程的socket等相关信息

I/O问题排查套路

  1. top发现iowait比较高
  2. 用iostat查看是哪个进程读写比较高
  3. 通过strace+lsof找出进程读取的文件和内容,进而确定I/O出现瓶颈的原因

常用命令汇总

top

面试官:生产环境发生问题,你一般怎么排查?(Linux工具篇)_linux_04

第一行(基本信息)


含义

16:16:26

当前时间

up 109 days, 15 min

系统运行时间,这里表示运行了109天,15分钟

1 user

正在登陆用户数

load average: 0.00, 0.02, 0.05

过去1分钟, 5分钟,15分钟的平均负载

第二行(任务信息)


含义

101 total

进程总数

1 running

正在运行的进程数

100 sleeping

睡眠状态的进程数

0 stopped

停止的进程数

0 zombie

僵尸进程数

第三行(CPU使用情况)


含义

us

User Time,CPU执行用户进程百分比

sy

System Time,CPU在内核运行百分比

ni

Nine Time,调整进程优先级所用百分比

id

Idle Time,系统空闲百分比

wa

Waiting Time,CPU等待IO完成所用百分比

hi

Hard IPQ Time ,硬中断百分比

si

Soft IPQ Time ,软中断百分比

st

Steal Time,虚拟服务占用百分比

第四行(物理内存使用情况)


含义

total

总物理内存

free

空闲的物理内存

used

已经使用的物理内存

buff/cache

缓冲区和缓冲区占用总量

第六行(进程详细信息)


含义

PID

进程ID

USER

进程所有者的用户名

PR

优先级

NI

nice值

VIRT

进程使用的虚拟内存总量,单位kb

RES

进程使用的,未被还出的物理内存大小,单位kb

SHR

共享内存大小,单位kb

S

进程状态

%CPU

CPU时间占用比

%MEM

物理内存占用比

TIME+

进程总计使用的CPU时间

COMMAND

命令名

进程状态的取值有如下几种

  1. D - 不可中断的睡眠态,一般表示进程正在跟硬件交互,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。但是uninterruptible sleep 状态的进程不接受外来的任何信号,因此无法用kill杀掉这些处于D状态的进程,无论是”kill”, “kill -9″还是”kill -15″
  2. R – 运行态,进程在CPU的就绪队列中,正在运行或者等待运行
  3. S – 可中断睡眠态,进程因为等待某个事件而被挂起。当进程等待的事件发生时,会被唤醒并进入R状态
  4. T – 进程处于暂停或者跟踪状态
  5. Z – 僵尸态,表示僵尸进程,进程实际上已经结束了,但是父进程还没有回收它的资源。

交互使用

执行top命令时,可以输入交互命令
1:查看CPU每个核的使用情况
h:显示帮助画面,给出一些简短的命令总结说明
k:终止一个进程
q:退出程序
r:重新安排一个进程的优先级别
m:切换显示内存信息
t:切换显示进程和CPU状态信息
c:切换显示命令名称和完t整命令行
M:根据驻留内存大小进行排序
P:根据CPU使用百分比大小进行排序
T:根据时间/累计时间进行排序

vmstat

[root@VM-0-14-centos ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 212380 136000 1543228 0 0 0 16 1 2 1 1 99 0 0

procs

含义

r

就绪队列的长度,也就是正在运行和等待CPU的进程数

b

不可中断睡眠状态的进程数

memory

含义

swpd

交换分区swap使用的大小

free

未使用内存的大小

buff

buffer缓冲区的大小

cache

cache缓冲区的大小

swap

含义

si

每秒从磁盘读入swap分区的大小,如果这个值不够用了,说明这个物理内存不够用了

so

每秒从swap分区写入磁盘的大小

io

含义

bi

块设备每秒发送的块数量

bo

块设备每秒接收的块数量

system

含义

in

每秒中断的次数

cs

每秒上下文切换次数

cpu

含义

us

User Time,CPU执行用户进程百分比

sy

System Time,CPU在内核运行百分比

id

Idle Time,系统空闲百分比

wa

Waiting Time,CPU等待IO完成所用百分比

st

Steal Time,虚拟服务占用百分比

参考博客

[1]https://fredal.xin/java-error-check#toc_h3_14
使用率低但是负载高
[2]https://zoco.fun/program/cpu%E4%BD%BF%E7%94%A8%E7%8E%87%E4%BD%8E%E8%B4%9F%E8%BD%BD%E9%AB%98%E7%9A%84%E4%B8%80%E4%B8%AAcase/
[2]https://www.jianshu.com/p/347afe9ba9ee
io事务
[3]https://www.heapdump.cn/article/558214
性能优化专栏
[4]https://www.zhihu.com/column/xingnengyouhua
iostat
[5]https://bean-li.github.io/dive-into-iostat/
记一次服务端 IO 瓶颈问题定位
[6]https://testerhome.com/topics/20606
connect reset
包的格式
Connection reset
[9]https://www.jianshu.com/p/6ce9598d61fb
[10]https://tech.kujiale.com/ying-yong-pin-fan-bao-chu-cause-java-net-sockettimeoutexception-read-timed-outzen-yao-ban/


举报

相关推荐

0 条评论