Java线程堆栈

  • Linux jstack命令
jstack 7756(Java进程号) > java.stack
  • Linux kill命令
kill -3 7756(Java进程号)

向JVM发送QUIT信号

Java线程

  • JVM创建线程

线上故障快速定位及恢复_死锁

  • 用户线程
main函数代表主线程
  • 线程堆栈的第一行

线上故障快速定位及恢复_堆栈_02

1、java线程转换LINUX 内核库pthread即本地线程
2、tid 语言层面的id比如Java 线程编号
3、nid(Native Thread)运行在操作系统基础上的本地id
  • 线程调用含义

​堆栈信息其中一行的调用关系​

线上故障快速定位及恢复_java_03

  • pstatck 7756(Java进程号)
nid(16进制) == LWP(10进制)

线上故障快速定位及恢复_死锁_04

​16进制的nid​

线上故障快速定位及恢复_堆栈_05

​10进制的LWP(轻量级进程)​

线上故障快速定位及恢复_堆栈_06

锁是否释放

  • wait() 会释放监视锁

线上故障快速定位及恢复_java_07

  • sleep会占用锁

线上故障快速定位及恢复_堆栈_08

  • 当一个线程占有一个锁时
堆栈会打印 -locked <Oxe7402c48>
  • 当该线程等待别的线程释放该锁
堆栈会打印 -waiting to lock <Oxe7402c48>
  • 如果代码中有wait调用
首先是locked 然后又会打印 waiting on <Oxe7402c48>
这种会导致死锁即死循环 占用了锁等待其他锁

线程死锁

线上故障快速定位及恢复_java_09

0时刻 线程0获取锁0 线程1获取锁1 
2时刻 线程0获取锁1 线程1获取锁0
两个线程各得到锁 都等待对方的锁

Java堆栈直接给出死锁的结果

​死锁报错​

线上故障快速定位及恢复_死锁_10

​死锁详情​

线上故障快速定位及恢复_死锁_11

死锁情况分析导致CPU过高分析

方法1

​步骤​

线上故障快速定位及恢复_堆栈_12

为什么要去掉wait和sleep的线程 因为其不占用cpu资源

​原因​

线上故障快速定位及恢复_java_13

方法2 TOP&堆栈方法(一次命中)

线上故障快速定位及恢复_堆栈_14

JNI是Java Native Interface

线上故障快速定位及恢复_java_15

5578是java的进程号
打印这个进程中所有线程
cpu消耗倒叙排列 shit+h
jstack把线程堆栈打印出来 里面有很多线程 其中有一个就等于cpu消耗最多的那个pid
就可以直接定位到这行代码有问题

不消耗CPU的线程状态

  • JVM的RUNNABLE状态
网络IO不消耗CPU 是同步阻塞的过程
  • TIMED_WAITING(on object monitor)
obj.wait(time)
  • TIMED_WAITING(sleeping)
Thread.sleep(time)
  • TIMED_WAITING(parking)
被挂起
  • WAITING(on object monitor)
obj.wait()
通过notify()唤醒
  • BLOCKED (on object monitor)
等待监视锁
  • WAITING(parking)
被挂起

Java线程堆栈

  • 一次线程堆栈信息

线上故障快速定位及恢复_java_16

  • 多次线程堆栈

线上故障快速定位及恢复_java_17

资源不足导致性能下降原因

大量线程停在同样的调用上下文中

​原因​

线上故障快速定位及恢复_java_18

​未及时释放连接的情况​

线上故障快速定位及恢复_java_19

多个锁导致的锁链分析

很多线程在等待不同的锁 有的锁竞争可能由于另外一个锁对象竞争导致 需要找到根源

​案例分析​

线上故障快速定位及恢复_堆栈_20

WebAPI性能瓶颈

​线上表现​

1、连接阻塞比较多RECQ(接收的队列)
2、超时日志疯狂打印
3、通过重启webapi进程临时缓解压力

解决步骤

线上故障快速定位及恢复_堆栈_21

​线程A​

线上故障快速定位及恢复_java_22

​线程B​

线上故障快速定位及恢复_堆栈_23

线上故障处理方式

  • 保留现场
比如通过jstack保存堆栈快照信息
  • 恢复服务
第一时间恢复服务 比如restart、reboot
  • 排查解决
  • 验证

​常规操作​

  • 重启
  • 回滚
  • 降级
  • 摘机

现象收集&故障定位

线上故障快速定位及恢复_死锁_24

潜在bug被激发的情况重启有效

故障排除&服务恢复

线上故障快速定位及恢复_java_25

确定服务进程排查问题

线上故障快速定位及恢复_死锁_26

​CPU​

top 
shift+p 按pid 进程编号升序
shift+m 按占用内存大小降序

线上故障快速定位及恢复_java_27

​内存​

free -g

线上故障快速定位及恢复_堆栈_28

​内存​

vmstat -n

线上故障快速定位及恢复_死锁_29

​tcp连接数量​

netstat -aonp|grep tcp |wc -l

线上故障快速定位及恢复_堆栈_30

​端口映射​

netstat -natp|sort -m

线上故障快速定位及恢复_java_31

​磁盘情况​

iostat -d 1

线上故障快速定位及恢复_堆栈_32

​文件占用情况​

ls -l /proc/*/fd

线上故障快速定位及恢复_java_33

目标服务内观察

线上故障快速定位及恢复_java_34

问题协查方法论

线上故障快速定位及恢复_java_35

异常处理原则

错误永远无法避免 且发生的角度永远无法预期
在故障发生时尽可能维持系统核心功能的可用性