线上问题排查总结

线上问题排查

作为开发人员,不仅需要掌握系统开发技能,更应该具备处理线上问题的能力。本文主要针对线上问题处理的主要步骤和方法展开描述,供大家参考。

业务日志

在系统出问题时,首先应该根据业务日志来排查问题。主要有grep、tail、more、less等命令。

数据库相关

假设出现Could not get JDBC Connection 、接口响应慢、线程打满等。
登录线上库,查看数据库连接情况:show processlist。查看当前数据库的连接情况。确实因为慢查询造成,须要手动kill。

JVM问题

一般通过下面几个工具都能定位出问题。

jps(JVM Process Status Tool)

查看Java进程的具体状态, 包括进程ID,进程启动的路径及启动参数等。

[root@izm5e4dhkm7u54kfwhgz9wz logs]# jps -mv
25481 Jps -mv -Dapplication.home=/usr/java/jdk1.8.0_151 -Xms8m
12489 medusa-server.jar --spring.profiles.active=test-zf -Xms128M -Xmx256M
12235 hk-pay.jar --spring.profiles.active=test -Xms128m -Xmx128m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
21069 intl-pay.jar --spring.profiles.active=test -Xms128M -Xmx256M
13902 converge-pay.jar --spring.profiles.active=test-zf -Xms256M -Xmx256M
jinfo(Configuration Info for Java)

实时的查看和调整虚拟机的参数。

jinfo  pid   输出全部的参数和系统属性
jinfo  -flag  name pid   输出对应名称的参数
jinfo  -flag [+|-]name  pid   开启或者关闭对应名称的参数
jinfo  -flag name=value  pid   设定对应名称的参数
jinfo  -flags  pid   输出全部的参数
jinfo  -sysprops  pid   输出系统属性
jstat(JVM Statistics Monitoring Tool)

监控JVM各种运行状态信息的命令行工具。

[root@izm5e4dhkm7u54kfwhgz9wz logs]# jstat -options
-class           监视类装载、卸载数量、总空间以及类装载所耗费的时间
-compiler  	     输出JIT编译器编译过的方法和耗时等信息
-gc  		     监视Java堆状况,包括Eden区、survior区、old区、永久代等的容量、已用空间、gc时间合计等信息
-gccapacity      监视内容与-gc基本相同,但输出主要关注java堆各个区域使用到的最大、最小空间
-gccause         与-gcutil相同,但额外会输出导致上一次gc产生的原因
-gcmetacapacity  输出metaspace的最大和最小空间
-gcnew           监视新生代gc状况
-gcnewcapacity   监视内容与-gcnew基本相同,但输出主要关注j使用到的最大、最小空间
-gcold  		 监视老年代gc状况
-gcoldcapacity   监视内容与-gcold基本相同,但输出主要关注j使用到的最大、最小空间
-gcutil  		 监视内容与-gc基本相同,但输出主要关注java堆已使用空间占总空间的百分比
-printcompilation  输出已经被JIT编译器编译的方法
jstack(Stack Trace for Java)

生成JVM进程当前时刻的线程的调用堆栈,可以用来定位线程间死锁、锁等待、等待外部资源等。

jstack [option] pid
-F 当正常jstack正常的请求不被响应时,强制输出线程堆栈
-l 输出锁的附加信息
-m 如果调用本地方法,可以输出C/C++堆栈

输出并保存:

[root@izm5e4dhkm7u54kfwhgz9wz logs]# jstack 12235 > jstack.log   

在这里插入图片描述

监视器Monitor:

Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。
每一个对象都有,也仅有一个 monitor。
下面这个图,描述了线程和Monitor之间关系,以及线程的状态转换:
在这里插入图片描述
进入区(Entrt Set):表示线程通过synchronized要求获取对象的锁。如果对象被锁住,则进入拥有者;否则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。
拥有者(The Owner):表示某一线程成功竞争到对象锁。
等待区(Wait Set):表示线程通过对象的object.wait()方法,释放对象的锁,并在等待区等待被唤醒。
从图中可以看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 Active Thread,而其它线程都是 Waiting Thread,分别在两个队列 Entry Set和 Wait Set里面等候。
在 Entry Set中等待的线程动作是 Waiting for monitor entry。
在 Wait Set中等待的线程动作是 in Object.wait()。当一个线程申请进入临界区时,它就进入了 Entry Set队列。
(我们称被 synchronized保护起来的代码段为临界区。当一个线程申请进入临界区时,它就进入了 “Entry Set ”队列)

线程状态:

NEW:未启动的。不会出现在Dump中。
RUNNABLE:在虚拟机内执行的,运行中状态。The Owner区
BLOCKED:受阻塞并等待监视器锁。在Entry Set区等锁。
WATING:无限期等待另一个线程执行特定操作。在Wait Set区等待某个condition或monitor发生,一般停留在wait()等语句里。
TIMED_WATING:有时限的等待另一个线程的特定操作。在Wait Set区和WAITING的区别是wait() 等语句加上了时间限制 wait(timeout)。
TERMINATED:已退出的。

调用修饰

表示线程在方法调用时,额外的重要的操作。修饰上方的方法调用。
locked <地址> 目标:使用synchronized申请对象锁成功,监视器的拥有者。The Owner区。
waiting to lock <地址> 目标:使用synchronized申请对象锁未成功,在Entry Set区等锁。线程状态为Blocked
waiting on <地址> 目标:使用synchronized申请对象锁成功后,释放锁,在Wait Set区等锁。线程状态为WAITING或TIMED_WATING
parking to wait for <地址> 目标:调用了park(),在Wait Set区,等待许可。
(park是基本的线程阻塞原语,不通过监视器在对象上阻塞。
  park: 进入WAITING状态,对比wait不需要获得锁就可以让线程WAITING,通过unpark唤醒)

线程动作

线程状态产生的原因。
runnable:The Owner区,状态RUNNABLE
in Object.wait():调用wait(),Wait Set区,状态为WAITING或TIMED_WAITING,修饰waiting on
waiting for monitor entry:等锁,Entry Set区,状态BLOCKED,修饰waiting to lock
waiting on condition:因某种条件被park,Wait Set区,状态为parking to wait for
sleeping:休眠的线程,调用了Thread.sleep()

总结
  • 查看线程dump,先看线程状态/线程动作(比较直观),可以确定线程目前处于哪个阶段。然后看调用修饰及锁情况,基本就可以确定此线程是否有问题;
  • 可以短时间(可能有问题的时间段)内多次打印线程快照,然后查看可能有问题的某一线程在这几次的情况,可以有效查找问题。
jmap(Memory Map for Java)

生成堆转储快照dump文件,除了这种方式还可以通过
-XX:HeapDumpOnOutOfMemoryError参数,可以在虚拟机发生OOM的时候自动生成堆的dump文件。jmap除了生成堆的dump文件 也可以查看查看堆的信息,查询finalize执行队列等。

[root@izm5e4dhkm7u54kfwhgz9wz logs]# jmap -dump:format=b,file=heap201906121146.bin 12235
Dumping heap to /opt/converge-pay/logs/heap201906121146.bin ...
Heap dump file created

-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 
-finalizerinfo 打印正等候回收的对象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. 
-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. 
-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 
-h | -help 打印辅助信息 
-J 传递参数给jmap启动的jvm. 

服务环境

CPU
  1. top
    主要关注cpu的load,以及比較耗cpu的进程。
    因为如今server都是虚拟机,还要关注st(st 的全称是 Steal Time 。是分配给执行在其他虚拟机上的任务的实际 CPU 时间)
    请参考另一篇文章:top命令详解
内存
  1. free
[root@izm5e4dhkm7u54kfwhgz9wz ~]# free -m -c10 -s1
              total        used        free      shared  buff/cache   available
Mem:           3790        1994         153        1209        1642         135
Swap:             0           0           0

-m:以MB为单位显示。其它的有-k -g -b
-s: 间隔多少秒持续观察内存使用状况
-c:观察多少次
  1. vmstat
[root@izm5e4dhkm7u54kfwhgz9wz ~]# vmstat 1 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 5  0      0 145864   5780 1680672    0    0    23    14    0    0  1  1 97  0  0
 0  0      0 145660   5788 1680700    0    0     0    72 7158 11437  4 16 80  0  0
 
1表示每隔1s输出一次,10 表示输出10次
两个參数须要关注
r: 执行队列中进程数量,这个值也能够推断是否须要添加CPU。(长期大于1)
b: 等待IO的进程数量。
IO
  1. iostat
[root@izm5e4dhkm7u54kfwhgz9wz ~]# iostat -m 1 10
Linux 3.10.0-693.2.2.el7.x86_64 (izm5e4dhkm7u54kfwhgz9wz) 	06/12/2019 	_x86_64_	(2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.46    0.00    1.13    0.08    0.00   97.33

Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
vda               3.61         0.04         0.03    2140135    1302884

-m:某些使用block为单位的列强制使用MB为单位
1 10:数据显示每隔1秒刷新一次。共显示10次
网络
  1. netstat
netstat -antp 
-a (all)显示全部选项。默认不显示LISTEN相关
-t (tcp)仅显示tcp相关选项
-u (udp)仅显示udp相关选项
-n 拒绝显示别名,能显示数字的所有转化成数字。
-l 仅列出有在 Listen (监听) 的服服务状态
-p 显示建立相关链接的程序名

显示tcp各个状态数量:

[root@izm5e4dhkm7u54kfwhgz9wz ~]#  netstat -ant |awk '{print $6}'|sort|uniq -c
     26 CLOSE_WAIT
      1 established)
     75 ESTABLISHED
      1 Foreign
     25 LISTEN
      1 SYN_SENT
     14 TIME_WAIT

查看连接某服务port最多的的IP地址

[root@izm5e4dhkm7u54kfwhgz9wz ~]# netstat -nat | grep "127.0.0.1:8060" |awk '{print $5}'|awk -F: '{print $4}'|sort|uniq -c|sort -nr|head -10
      6 
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值