自助建站程序宁波seo整站优化软件
常见问题 1:CPU 利用率高
问题
CPU 使用率是衡量系统繁忙程度的重要指标,一般情况下单纯的 CPU 高并没有问题,它代表系统正在不断的处理我们的任务,但是如果 CPU 过高,导致任务处理不过来,这个是非常危险需要关注的。
CPU 使用率的安全值没有一个标准值,取决于你的系统是计算密集型还是 IO 密集型,一般计算密集型应用 CPU 使用率偏高 load 偏低,IO 密集型相反。
问题原因:
1、频繁 FullGC/YongGC
如何排查:
- 查看 gc 日志;
jstat -gcutil pid
查看内存使用和 gc 情况。
2 、代码消耗,如死循环,md5 等内存态操作
如何排查:
(1)arthas (已开源)
thread -n 5 查看 CPU 使用率最高的前 5 个线程进行分析
(2)jstack 查找
ps -ef | grep java
找到 Java 进程 id;top -Hp pid
找到使用 CPU 最高的线程;printf ‘0x%x’ tid
将线程 id 转化 16 进制;jstack pid | grep tid
找到线程堆栈;- 备注:输入 “
1
” 可查看每个 CPU 的情况,之前有团队遇到单个 CPU 被中间件绑定导致 CPU 飚高的情况。
常见问题 2:load
高问题
load 指单位时间内活跃进程数
,包含:
- 运行态线程:执行
Thread.start
进入runnable
等待 CPU 调度,如果 CPU 很忙会导致 runnable 进程数增加; - 不可中断态线程:不可中断态主要包含
网络 IO
、磁盘 IO
以及内核态的锁(如 synchronized)
等。
问题原因:
1、 CPU 利用率高,运行态线程数多;
排查方法见常见问题一
2、 iowait,等待 IO
如何排查:
vmstat
查看blocked
进程状况;jstack -l pid | grep BLOCKED
查看阻塞态线程堆栈;
3、等待内核态锁,如 synchronized
如何排查:
jstack -l pid | grep BLOCKED
查看阻塞态线程堆栈;profiler dump
线程栈,分析线程持锁情况;- 分析是否出现死锁。(参考文章:并发编程中的死锁定位排查)
常见问题 3:持续 FullGC
问题
在了解 FullGC 原因之前,简单回顾下 jvm 的内存相关知识:
一、普通对象生命周期:
- 新
new
的对象放在Eden
区,当Eden
区满之后进行一次MinorGC
,并将存活的对象放入S0
; - 当下一次
Eden
区满的时候,再次进行MinorGC
,并将Eden中存活的对象
和S0的对象
放入S1
(S0
和S1
始终有一个是空的); - 依次循环前两个步骤,知道
S0/S1
中对象的年龄满足,移动到old区(老年代)
; - 直到
old 区
快满进行FullGC
。(通常老年代的GC都是伴随FullGc进行的
)。
二、永久代 与 元数据空间
jdk1.7 之前 Java 类信息、常量池、静态变量
存储在 Perm 永久代
,类的原数据
和静态变量
在类加载的时候放入 Perm 区
,类卸载的时候清理;
在 1.8 中,MetaSpace
代替 Perm
区,使用本地内存,常量池和静态变量
放入堆区,一定程度上解决了在运行时生成或加载大量类
造成的 FullGC
,如反射、代理、groovy 等。
三、回收算法
年轻代常用 :复制算法
。
老年代常用 :标记-清除
、标记-压缩
。
四、关键常用参数
CMSInitiatingOccupancyFraction
表示老年代使用率达到多少时进行 FullGC
; UseCMSCompactAtFullCollection
表示在进行 FullGC
之后进行老年代内存整理,避免产生内存碎片。
五、持续 FullGC问题原因
1、prommotion failed
:从 S 区晋升的对象在老年代也放不下导致 FullGC。以下是导致prommotion failed
的原因:
原因1:survivor 区太小,对象过早进入老年代。
如何排查:
- jstat -gcutil pid 1000 观察内存运行情况;
- jinfo pid 查看 SurvivorRatio 参数;
原因2:大对象分配,没有足够的内存。
如何排查:
- 日志查找关键字 “
allocating large
”; profiler
查看内存概况大对象分布;
原因3:old 区存在大量对象。
如何排查:
- 实例数量前十的类:
jmap -histo pid | sort -n -r -k 2 | head -10
; - 实例容量前十的类:
jmap -histo pid | sort -n -r -k 3 | head -10
; - dump 堆,profiler 分析对象占用情况;
2、concurrent mode failed:在 CMS GC 过程中业务线程将对象放入老年代(并发收集的特点)内存不足。原因如下:
原因1:fgc触发比例
过大,导致老年代占用过多
,并发收集时用户线程持续产生对象
导致达到触发 FGC 比例
。
如何排查:
jinfo
查看CMSInitiatingOccupancyFraction
参数,一般70~80
即可 ;
原因2:老年代存在内存碎片。
如何排查:
jinfo
查看UseCMSCompactAtFullCollection
参数,配置成在FullGC
后整理内存。
常见问题 4:线程池满
问题
Java 线程池以有界队列的线程池为例,当新任务提交时,如果运行的线程少于 corePoolSize
,则创建新线程来处理请求。如果正在运行的线程数等于 corePoolSize
时,则新任务被添加到队列中
,直到队列满。当队列满了后,会继续开辟新线程来处理任务,但不超过 maximumPoolSize
。当任务队列满了并且已开辟了最大线程数
,此时又来了新任务,ThreadPoolExecutor
会拒绝服务。
问题原因:
1、下游 响应时间(RT)高,超时时间
不合理导致
如何排查:借助skywalking等三方监控进行监控和调整。
2、数据库慢 sql
或者数据库死锁
导致
如何排查:
- 日志查询关键字 “Deadlock found when trying to get lock” ;
Jstack
查看阻塞态线程;
3、Java 代码死锁
如何排查:
jstack l pid | grep -i E 'BLOCKED | deadlock'
;- dump thread 通过
zprofiler
分析阻塞线程和持锁情况;
常见问题 5:NoSuchMethodException
异常
问题原因
jar 包冲突
如何解决:
mvn dependency:tree
分析报错方法所在的 jar 包版本,留下新的;arthas:sc -d ClassName
XX:+TraceClassLoading
类似问题
- ClassNotFoundException
- NoClassDefFoundError
- ClassCastException
常见问题解决方案
线程池满
rpc框架线程池满:高RT接口进行限流。
CPU 高,load 高
单机置换或重启,可短暂缓解,然后具体看是`业务激增导致`或者`程序内部`导致。
下游RT 高
- 限流
- 降级
数据库死锁
- kill线程
慢SQL
- SQL调优;
- 服务限流;
线上问题的排查是一个积累的过程,只有了解问题背后的原理才能更快速的定位和恢复,除此之外更需要有一些趁手的工具来辅助排查,从而降低整个团队故障恢复的效率。