如何快速对应用系统做一个 360 度画像诊断?
如何快速对应用系统做一个 360 度的画像诊断?
1. 为什么要诊断?
2. 诊断的策略是什么?
3. 如何快速地完成诊断?
一、为什么要诊断?
企业应用开发过程中,肯定会遇到以下问题:
a.进程消耗 CPU 飙升、内存利用率暴增,如何定位代码?
b.数据库连接数被耗尽怎么办?
c.各类 OOM 如何预防?
d.线程死锁、锁争用、上下文切换太频繁怎么办?
无论多复杂的系统运行在 Linux 之上,其实它就是一个进程。任何东西在操作系统层面,都是以文件的形式来存储的。进程也不例外,所以从操作系统的层面,只需要关注进程和线程即可。
例如:ll /proc/{pid}/ 展示此进程(pid)的文件目录,其中包含日志输出位置、系统加载哪些 JAR 包,以及还可以知道系统跟哪些外部应用在交互(ll /proc/{pid}/fd |grep socket),包括使用的哪些中间件服务,都可以从 socket 找到。
proc 文件夹下包含所有的进程(Process)等信息。
二、诊断的策略是什么?
360 度画像包括以下指标:
a. 资源瓶颈
b. 连接
c. TCP 状态
d. 业务日志
e. OOM
f. JVM
g. CPU 飙升
h. 线程状态
业务系统从性能上看,系统性就关注两件事:一个是吞吐量,一个是系统的响应性。
先谈谈 CPU:
如果 CPU 的利用度不高,但是系统的吞吐量和响应性却不理想,这说明程序并没有忙于计算,可能问题出现在 IO 上。
再谈谈 IO:
IO 和 CPU 利用率一般是呈反比的,CPU 利用率高,则 IO 不大;IO 大,则 CPU 利用率就小。
关于 IO,磁盘 IO、驱动程序 IO 和内存换页率。
再检查网络带宽有没有问题。
如果 CPU、IO 和网络都看完了,并且 CPU 的利用率不高,IO 也不高,内存也不高,网络带宽使用也不高,但是系统性能还是上不去。那么这个程序一定是被阻塞了,可能是 CPU 在等待哪个锁,也可能是某个资源,比如接口返回,连接在等待等,包括上下文的切换。
影响系统性能的瓶颈有:磁盘 I/O、内存、CPU、网络 I/O
(1) IO 谁更快?
L1>L2>>L3>>>....>>>Memory>>>>>>>...>>>>>Disk
CPU IO 内存 磁盘
(2)网络 IO
某些场景下,由于网络环境的不确定性,尤其是互联网上的数据读写,网络操作的速度可能比本地的 IO 要会更慢。
网络 IO 主要延时由: 服务器响应延时 + 带宽限制 + 网络延时 + 跳转路由延时 + 本地接收延时决定。(一般为几十到几千毫秒,受环境干扰极大)
(3)CPU
CPU 资源的争夺,将导致性能问题,主要是锁竞争,锁竞争会导致上下文切换频繁,带来严重的系统开销,表现就是内核态的 CPU 的利用率偏高
(4)内存
最可能是内存不足,对 JAVA 来说,关注 GC 就好
(5)连接
系统对外部依赖的中间件和接口
比如数据库连接,如果数据量过大或者连接超时,都是比较消耗性能的。
(6)异常
JAVA 异常的捕获和处理是非常消耗资源的,如果程序高频率的在异常处理,也会影响系统和性能。
三、如何快速地完成诊断?
(1) 资源诊断
CPU、IO、内存、磁盘、网络
方法:
##CPU 问题定位
先用 TOP 命令查看
其中 load average 最近 1, 5, 15 分钟的系统的平均负载。
系统的平均负载:在特定的时间间隔内,运行队列中,即 CPU 上运行,或者等待运行多少进程的平均进程数。
其中还有用户态的 CPU 和内核态的 CPU 使用占比等。
##再看看内存问题的定位,
pidstat -r -p {pid} 1 2 // 查看某个进程占用的物理内存和虚拟内存
pidstat -d -p {pid} 1 2 //查看某个进程 IO 使用情况
-r: 内存
-d: IO
-u: CPU
## IO 问题定位
vmstat 命令中 swpd 过高,通常是物理内存不够用了,swap 的消耗主要关注它的 IO。
##网络问题的定位
trace 命令可以用来跟踪进程的执行和系统的调用
strace -T 之间的参数可以显示具体的进程系统调用的情况
网络的 IO 也可以通过 cat /proc/interrupts 来查看,网络 IO 消耗需要关注、网卡中断,是否不均衡分配到各个 CPU。JAVA 的程序一般不会引起网络的 IO 消耗严重问题。
##磁盘问题的定位
dstat
(2) 连接诊断
应用往往还需要和外部的服务交互,比如数据库、缓存、消息中间件等
通过 netstat 查看,netstat -anop |grep 3306 查看 mysql 连接
(3) 线程异常
关注两点:线程状态、线程连接数。
应用设计的时候需要考虑资源的限制,才能避免在某些时候因为资源过度消耗而崩溃。
线程数的控制就非常重要,程序无限制创建,最终导致其不可控,特别是隐藏在代码中的创建线程的方法。
当系统的 SY 值过高时,表示 Linux 要花费更多的时间,来进行线程的切换。Java 造成这种现象的主要原因是,创建的线程比较多,这些线程都处于不断的阻塞、锁等待、IO 等待和执行状态的变化过程中,这就产生了大量的上下文切换。Java 应用程序在创建线程时会操作 JVM 堆外的物理内存,太多的线程也会使用过多的物理内存。
如上,线程数太多,导致内存不足,应用已无法在创建新线程。
那通过什么方法查看线程数呢?
cat /proc/{pid}/status
top -bH -d 3 -p {pid}
pstree -p {pid} | wc -l
pstack {pid} | head -l
JAVA 线程状态主要包括以下几种:
Blocked (阻塞状态)
Waiting (无限时等待)
Time_Waiting (有限时等待)
New (初始化状态)
Runnable/Running (可运行 / 运行状态)
Terminated (终止状态)
其中我们最要关注的是 Blocked、Waiting 和 Time_Waiting 这三种状态,特别是 Blocked 状态,在获取不到 CPU 执行时间的时候,此时系统性能就会下降。
(4)CPU 飙升诊断:分析定位程序 CPU 问题和查看线程状态的问题
(5)TCP 状态诊断
重点关注 CLOSE-WAIT 和 TIME-WAIT 状态,CLOSE-WAIT 是被动关闭方,TIME-WAIT 是主动关闭方。
如果客户端的并发量持续很高, 就会出现 TIME-WAIT 很高,有可能是客户端的连接连不上,可以用 netstat 查询定位。
(6) CPU 过载
如何定位你的代码,是哪段导致 CPU 过载呢?
#步骤一:用 top 或者 pidstat 定位具体的进程号
#步骤二:top -p {pid} Shift+H 查看具体线程
#步骤三:将线程号(十进制)转化成十六进制 printf "%x\n" {pid} (线程栈中的线程程序号是以十六进制存储的)
#步骤四:jstack -l {pid } | grep -A 20 {16 进制的线程程序号}
(7) OOM 诊断
a.资源不足:可能内存分配过小
b.申请的资源太多:某一个对象被频繁申请,却没有被释放,内存不断泄露
c.资源耗尽:某一个资源被频繁申请,系统的资源在耗尽,例如不停的创建线程,不断的发起网络连接等
定位方法:
步骤一: 确认内存是否真的分配过小,jmap heap {pid}
步骤二:找到最耗费资源的对象,jmap -histo:live {pid} | more
步骤三:再确认你的资源是否耗尽,通过 pstree 和 netstat 来查看进程创建的线程数以及网络连接数等资源是否被耗尽
内存分析的最简单方式是通过内存的 dump 命令来导出内存栈
(jmap -dump:live,format=b,file=heap001 {pid}),不过会导致一次 JVM 的 Full GC,导出的文件可通过 MAT VisualVM 来查看
(8)JVM GC 问题
GC 会导致系统应用的暂时停顿,如果频繁的 GC,就会产生系统的延迟响应。
开启 GC 日志,可以方便观察定位,应用的停顿原因;也可以通过 jstat 来收集信息
jstat -gccause {pid} 1000
(9)日志诊断
检查日志的异常,Error 等各种数据库异常等,前提是日志栈没被吃掉
比如说监控系统,awk 命令来分析
#Reference
每日一课-360 度的画像诊断
版权声明: 本文为 InfoQ 作者【姜戈】的原创文章。
原文链接:【http://xie.infoq.cn/article/2f50bd0647cadb9dbea9df171】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论