Linux CPU100%+ 高负载问题排查记录

       

     
      今天LN现场售后人员反馈一台服务器上的业务办理出现问题,主要是运行缓慢,附带卡顿现象,没办法救急入救火就远程过去查查原因,本文用于记录排查过程并整理一些相关资料,希望对遇到类似问题的小伙伴们有帮助


排查过程:

第一步

先看看服务器情况,使用top命令可以监控linux的系统状况,主要用户查看显示系统中各个进程的资源占用情况,察看信息后发现CPU 占用高达100%+

 

top命令格式             

格式:top [-] [d delay] [q] [c] [S] [s] [i] [n] [b]

  • d : 改变显示的更新速度,

  • q : 没有任何延迟的显示速度

  • c : 切换显示模式,共有两种模式,一是只显示执行档的名称,另一种是显示完整的路径与名称

  • S : 累积模式,会将己完成或消失的子进程 ( dead child process ) 的 CPU time 累积起来

  • s : 安全模式,将交谈式指令取消, 避免潜在的危机

  • i : 不显示任何闲置 (idle) 或无用 (zombie) 的进程

  • n : 更新的次数,完成后将会退出 top

  • b : 批次档模式,搭配 "n" 参数一起使用,可以用来将 top 的结果输出到档案内

 

top 列含义

列名含义
PID进程id
PR优先级
NInice值。负值表示高优先级,正值表示低优先级
VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
SHR共享内存大小,单位kb
S进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
%CPU 上次更新到现在的CPU时间占用百分比
%MEM 进程使用的物理内存百分比
TIME+进程使用的CPU时间总计,单位1/100秒
COMMAND Command Name/Line命令名/命令行。

 第二步

CPU占比高,此问题多数是JVM 因堆内存不足频繁Full GC引起 。垃圾回收是根据可达性分析算法将不在GC Root根的引用链上的对象回收, 计算时会引发JVM 中的STW事件(stop the world),此事件使Java应用程序暂时停顿,被STW中断的应用程序线程会在完成GC之后恢复,这个停顿就让业务出现卡顿现象 ,

所以使用jstat命令查看 Jstat命令查看JVM 信息,出乎我的意料,从信息中发现没有出现频发FGC的情况出现。一般频繁full gc的时候, FGC的次数会很多,GCT的时间会很大, 但我查询信息中FGC的次数并不大,因此这次问题不是 Full GC引起的CPU高负载+卡顿现象

 

jstat 命令格式

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]

jstat 列含义

列名含义
S0C第一个幸存区的大小
S1C第二个幸存区的大小
S0U第一个幸存区的使用大小
S1U第二个幸存区的使用大小
EC伊甸园区的大小
EU伊甸园区的使用大小
OC老年代大小
OU老年代使用大小
YGC年轻代垃圾回收次数
YGCT年轻代垃圾回收消耗时间
FGC老年代垃圾回收次数
FGCT老年代垃圾回收消耗时间
GCT垃圾回收消耗总时间

第三步

不是JVM问题那么就只能查看线程栈了 ,所以使用jstack 查询这个线程到底在干嘛,使用top -Hp 进程号命令找到 CPU 消耗最多的线程号,从中发现正在运行的线程十分可疑,其占用CUP很高,将其转换成16进制 再从jstatck栈日志中查看211e的信息,信息如下显示

printf "0%x\n" PID 

此应用是一个老系统,老系统使用了ehcache当做缓存,从下发的栈信息发现,ehcache 正在执行OverflowDiskWriteTask任务,这个任务是ehcache超过最大缓存数后将缓存内容写入磁盘的操作,然后查看磁盘上的文件大小仍在增长,

所以本问题是由于ehcache在不停的做写操作占用CPU,让CPU飙升

"daoCache.data" daemon prio=10 tid=0x00007f199d281000 nid=0x211e runnable [0x00007f1a01942000]
   java.lang.Thread.State: RUNNABLE
	at java.io.ByteArrayOutputStream.<init>(ByteArrayOutputStream.java:77)
	at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.<init>(MemoryEfficientByteArrayOutputStream.java:50)
	at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:89)
	at net.sf.ehcache.store.compound.factories.DiskStorageFactory.serializeElement(DiskStorageFactory.java:300)
	at net.sf.ehcache.store.compound.factories.DiskStorageFactory.write(DiskStorageFactory.java:280)
	at net.sf.ehcache.store.compound.factories.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:385)
	at net.sf.ehcache.store.compound.factories.DiskOverflowStorageFactory$OverflowDiskWriteTask.call(DiskOverflowStorageFactory.java:246)
	at net.sf.ehcache.store.compound.factories.DiskOverflowStorageFactory$OverflowDiskWriteTask.call(DiskOverflowStorageFactory.java:235)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:744)

jstack 格式

jstack [-l] pid

  • -f 当’jstack [-l] pid’没有相应的时候强制打印栈信息
  • -l 长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
  • -m 打印java和native c/c++框架的所有栈信息.
  • -h 或者 -help 打印帮助信息
  • pid 需要被打印配置信息的java进程id


解决方案:

问题是由于ehcache在不停的做写操作占用CPU,让CPU飙升,系统不能重启, 因此临时处理方案是从JBOSS控制台将其缓存清空,清空后问题解决

问题解决后看了下 ehcache.xml中的缓存配置, 配置中缓存的闲置时间timeToIdleSeconds时间为4小时,缓存个数是5W。从配置上分析怀疑是业务代码中存在问题,4小时内缓存了大量命中率低的数据,造成缓存数超过5W后ehcache开启将缓存写入磁盘的操作,所以暂时给售后以下建议

  • 建议售后先将闲置时间timeToIdleSeconds修改为1小时, 此处也不敢直接修改的太小,有点儿担心不了系统造成系统其他问题,打算观察一段时间后再来决定设置的值
  • 建议将overflowToDisk=true,修改成false禁止将缓存写入磁盘,毕竟缓存是用于提高读取速度。 

其实 ehcache 已经很少被使用了,reidis作为缓存是当今主流, 考虑到迁移需要投入的人力成本,迁移问题暂时搁置吧,考虑成本无法把事情做到最好估计也是很多人心中的痛

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Linux排查CPU负载的原因通常有以下几个方面: 1. 进程负载:可以通过使用top命令或htop命令查看当前系统的进程状态,找到最耗CPU的进程,并检查其是否正常运行。如果是某个进程导致负载,可以进一步使用ps命令查看该进程的详细信息,并根据需要采取相应的措施,如重新启动进程或优化进程配置。 2. 线程负载:如果是线程导致负载,可以使用工具如top、htop或pidstat等来找到最耗CPU的线程,并将线程PID转化为16进制。然后根据线程的PID进一步分析线程的运行状态和资源消耗情况,进行排查和调优。 3. 内存泄漏和频繁GC:内存泄漏和频繁的垃圾回收(GC)也可能导致CPU负载。可以通过使用jstat命令或Java监控工具(如VisualVM)来检查Java应用的内存使用情况,并查看是否存在内存泄漏或GC频繁的问题。如果存在问题,可以通过调整JVM启动参数或优化代码来解决。 4. 其他系统资源问题:除了CPU负载外,还可能存在其他系统资源的问题,如内存被耗尽、磁盘IO或网络出现问题等。可以使用命令如free、df、iostat和netstat等来检查系统的内存、磁盘IO和网络等情况,以确定是否存在相关问题。 相关问题: 1. 如何使用top命令查看系统进程状态? 2. 如何使用ps命令查看进程详细信息? 3. 如何使用jstat命令检查Java应用的内存使用情况?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

=PNZ=BeijingL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值