性能问题分析过程

原文链接:https://www.cnblogs.com/xiaoxitest/protected/p/9049799.html

一、CPU使用率分析过程

查找是用户进程CPU高还是系统CPU进程高
如果是用户进程CPU高,查找哪个进程高,再查哪个线程,看这个线程执行的方法或请求,(该方法或请求就是导致CPU高的原因)
如果是系统CPU高,看是不是系统调用导致了CPU比较高,看IO繁忙导致的,是否有排队现象
查看磁盘读写操作,读操作多 可能是内存不足导致,内存不足导致磁盘频繁读数据,写操作多, 看操作系统在写什么
如果不是磁盘读写问题,用strace看调用哪个内核,看哪个请求调用这个内核

1、查看占用CPU最多的进程
ps命令查看
linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合:
ps aux | head -1;ps aux | grep -v PID | sort -rn -k +3 | head
在这里插入图片描述
该命令组合实际上是下面两句命令:
ps aux|head -1
ps aux|grep -v PID|sort -rn -k +3|head

top命令查看
top命令查看CPU资源占用最多的进程:
top -c 进入监控状态,按Shift+p按照CPU使用率排序:
在这里插入图片描述
2、查看该进程下占用CPU时间最长的线程:

top命令查看

top -Hp 1584 进入线程监控状态后,按Shift+t 按照CPU使用时间进行排序:
在这里插入图片描述
ps命令查看

ps -mp 1584 -o THREAD,tid,time | sort -rn
在这里插入图片描述
对CPU使用率过高的进程中的所有线程进行排序,命令如下:
ps H -e -opid,tid,pcpu,cmd --sort=pcpu | grep 1584
在这里插入图片描述
3、将线程ID转为为十六进制

linux下转换:printf ‘%x\n’ 1933
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4、jstack查看线程栈状态

jstack 1584 | grep 78d -A 10  (1584为PID,78d为线程id,字母需小写)
在这里插入图片描述
5、把线程栈输出到本地
jstack 1584 > 1.txt
vim 1.txt
查看是否有block 线程死锁
大量waiting线程,等待的资源造成系统瓶颈的原因,如数据库连接池等待

二、内存分析

1、查看内存占用最高的进程

ps命令查看

ps -e -o ‘pid,comm,args,pcpu,rsz,vsz,stime,user,uid’ | grep java | sort -nrk5  #java为你要显示的服务
在这里插入图片描述
其中rsz为实际内存,上例实现按内存排序,由大到小
top命令查看

top -c 进入监控状态,按Shift+m按照内存使用率排序:
在这里插入图片描述
2、查看java堆内存占用,由高到低并输出到文件

jmap -histo pid > 1.txt
在这里插入图片描述
3、监测内存使用情况
每2秒1次,共5次
jstat -gcutil 1584 2000 5
在这里插入图片描述
4、下载堆内存到本地

jmap -dump:live,format=b,file=heap.bin
在这里插入图片描述
5、分析内存使用情况
将下载的堆内存使用MemoryAnalyzer 打开进行分析
在这里插入图片描述
三、查看tcp连接
查看所有tcp连接:
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’在这里插入图片描述
查看指定端口tcp连接:
在这里插入图片描述
统计每个IP的连接数:

netstat -n | awk ‘/^tcp/ {print $5}’ | awk -F: ‘{print $1}’ | sort | uniq -c| sort -rn
在这里插入图片描述
TCP连接状态详解:

发起握手阶段

CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”。

LISTEN :表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。

SYN_RCVD:表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT :这个状态与SYN_RCVD 状态相呼应,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送SYN报文。

ESTABLISHED:表示连接已经建立,这是双方进行正常通信所处的状态。

主动关闭阶段

FIN_WAIT_1 :其实FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET进入到FIN_WAIT_1 状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2 状态。当然在实际的正常情况下,无论对方处于任何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1 状态一般是比较难见到的,而FIN_WAIT_2 状态有时仍可以用netstat看到。

FIN_WAIT_2 :上面已经解释了这种状态的由来,实际上FIN_WAIT_2状态下的SOCKET表示半连接,即有一方调用close()主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2 状态会导致内核crash。

TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,但BSD传统实现采用了30秒,Linux可以cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值),然后即可回到CLOSED 可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(这种情况应该就是四次挥手变成三次挥手的那种情况)

CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接。

被动关闭阶段

CLOSE_WAIT :表示正在等待关闭。怎么理解呢?当对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当你处于CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了。

四、查看I/O使用情况

1、安装iostat命令,如已安装请忽略

yum -y install sysstat
2、iostat -x -k
在这里插入图片描述
以上各列的含义如下:

rrqm/s: 每秒对该设备的读请求被合并次数,文件系统会对读取同块(block)的请求进行合并
wrqm/s: 每秒对该设备的写请求被合并次数
r/s: 每秒完成的读次数
w/s: 每秒完成的写次数
rkB/s: 每秒读数据量(kB为单位)
wkB/s: 每秒写数据量(kB为单位)
avgrq-sz:平均每次IO操作的数据量(扇区数为单位)
avgqu-sz: 平均等待处理的IO请求队列长度
await: 平均每次IO请求等待时间(包括等待时间和处理时间,毫秒为单位)
svctm: 平均每次IO请求的处理时间(毫秒为单位)
%util: 采用周期内用于IO操作的时间比率,即IO队列非空的时间比率

对于以上示例输出,我们可以获取到以下信息:

每秒向磁盘上写3.8k左右数据(wkB/s值)
每秒有0.8次IO操作(r/s+w/s),其中以写操作为主体
平均每次IO请求等待处理的时间为11.87毫秒,处理耗时为4.75毫秒
等待处理的IO请求队列中,平均有0.01个请求驻留

以上各值之间也存在联系,我们可以由一些值计算出其他数值,例如:
util = (r/s+w/s) * (svctm/1000)
对于上面的例子有:util = (0.01+0.79)*(4.75/1000) = 0.0038

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章