【工作中问题解决实践 十二】线上如何排查CPU100%的情况

当我们把服务发布到服务器器,可能会因为一些问题造成我们的服务器CPU被打满甚至超过100%,那如果我们想知道到底上在做什么操作导致CPU持续过高呢?因为在线上只能通过日志看问题,或者排查到哪个进程或者哪个线程持续占用CPU。然后才能找到具体问题在哪里才能进行解决,具体排查过程

排查过程

无论是什么原因导致的,一定会体现在具体的进程和线程上,所以开始从进程入手,找到最大的线程

  1. 执行top -c命令:查看所有进程占系统CPU的排序。极大可能排第一个的就是咱们的java进程(COMMAND列)。PID那一列就是进程号。可以看到,有一个 Java 程序此时 CPU 占用量达到了 98.8%,此时我们可以复制该进程 id9,并且使用如下命令查看该进程的各个线程运行情况 找高CPU进程
top - 08:31:10 up 30 min,  0 users,  load average: 0.73, 0.58, 0.34
KiB Mem:   2046460 total,  1923864 used,   122596 free,    14388 buffers
KiB Swap:  1048572 total,        0 used,  1048572 free.  1192352 cached MemPID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND9 root      20   0 2557160 288976  15812 S  98.0 14.1   0:42.60 java
  1. 执行top -Hp 进程号命令:查看java进程下的所有线程占CPU的情况top -Hp PID 9,可以看到,在进程为 9 的 Java 程序中各个线程的 CPU 占用情况,接下来我们可以通过 jstack 命令查看线程 id 为 10 的线程为什么耗费 CPU 最高 找高CPU线程
top - 08:31:16 up 30 min,  0 users,  load average: 0.75, 0.59, 0.35
Threads:  11 total,   1 running,  10 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.5 us,  0.6 sy,  0.0 ni, 95.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2046460 total,  1924856 used,   121604 free,    14396 buffers
KiB Swap:  1048572 total,        0 used,  1048572 free.  1192532 cached MemPID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND10 root      20   0 2557160 289824  15872 R 79.3 14.2   0:41.49 java11 root      20   0 2557160 289824  15872 S 13.2 14.2   0:06.78 java
  1. 执行printf "%x\n 10命令 :后续查看线程堆栈信息展示的都是十六进制,为了找到咱们的线程堆栈信息,咱们需要把线程号转成16进制。例如,printf "%x\n 10打印:a,那么在jstack中线程号就是0xa.转换获取操作系统线程ID
  2. 执行 jstack 进程号 | grep 线程ID 查找某进程下线程ID(jstack堆栈信息中的nid)=0xa的线程状态。如果"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable,第一个双引号圈起来的就是线程名,如果是VM Thread这就是虚拟机GC回收线程了获取该进程快照并grep到该线程,查看线程状态
"main" #1 prio=5 os_prio=0 tid=0x00007f8718009800 nid=0xb runnable [0x00007f871fe41000]java.lang.Thread.State: RUNNABLEat com.aibaobei.chapter2.eg2.UserDemo.main(UserDemo.java:9)"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable
  1. 执行jstat -gcutil 进程号 统计间隔毫秒 统计次数(缺省代表一致统计),查看某进程GC持续变化情况,如果发现返回中FGC很大且一直增大确认Full GC 也可以使用jmap -heap 进程ID查看一下进程的堆内从是不是要溢出了,特别是老年代内从使用情况一般是达到阈值(具体看垃圾回收器和启动时配置的阈值)就会进程Full GC。【如果是虚拟机线程】统计gc情况,判断是否是full GC过多
root@8d36124607a0:/# jstat -gcutil 9 1000 10S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT0.00   0.00   0.00  75.07  59.09  59.60   3259    0.919  6517    7.715    8.6350.00   0.00   0.00   0.08  59.09  59.60   3306    0.930  6611    7.822    8.7520.00   0.00   0.00   0.08  59.09  59.60   3351    0.943  6701    7.924    8.8670.00   0.00   0.00   0.08  59.09  59.60   3397    0.955  6793    8.029    8.984
  1. 执行jmap -dump:format=b,file=filename 进程ID”,导出某进程下内存heap输出到文件中。可以通过mat工具查看内存中有哪些对象比较多。公司封装后,我们用的命令是heap dump【如果是虚拟机线程】heap dump下虚拟机快照,查看对象树判断

不同的问题结论排查到同的阶段就会有结论

问题定位

针对以上各个步骤,大致排查到某些步骤后就可以大致定位具体原因了

1 内存消耗过大,导致Full GC次数过多

一直排查,执行了步骤1-5

  • 步骤2明确为虚拟机线程】多个线程的CPU都超过了100%,通过jstack命令可以看到这些线程主要是垃圾回收线程
  • 步骤5查看GC情况】通过jstat命令监控GC情况,可以看到Full GC次数非常多,并且次数在不断增加。

确定是Full GC, 接下来找到具体原因:

  • 步骤6查看堆Dump文件】使用MAT工具分析,如果生成大量的对象,导致内存溢出,查看具体内存对象占用情况。
  • 如果对象占用不算高,但是Full GC次数还是比较多,此时可能是代码中手动调用 System.gc()导致GC次数过多,这可以通过添加 -XX:+DisableExplicitGC来禁用JVM对显示GC的响应。

2 代码中有大量消耗CPU的操作,导致CPU过高,系统运行缓慢

一直排查,执行了步骤1-4

  • 步骤2明确为非虚拟机线程
  • 步骤4查看线程快照情况】可直接定位到代码行。问题原因有某些复杂算法,甚至算法BUG,无限循环递归等。

3 由于锁使用不当,导致死锁

一直排查,执行了步骤1-4

  • 步骤2明确为非虚拟机线程
  • 步骤4查看线程快照情况】如果有死锁,会直接提示。关键字:deadlock 会打印出业务死锁的位置

在这里插入图片描述

4 不定期出现的接口耗时现象

对于这种情况,比较典型的例子就是,我们某个接口访问经常需要 2~3s 才能返回。这是比较麻烦的一种情况,因为一般来说,其消耗的 CPU 不多,而且占用的内存也不高,也就是说,我们通过【1-4】排查是无法解决这种问题的。而且由于这样的接口耗时比较大的问题是不定时出现的,这就导致了我们在通过 jstack 命令即使得到了线程访问的堆栈信息,我们也没法判断具体哪个线程是正在执行比较耗时操作的线程。对于不定时出现的接口耗时比较严重的问题,我们的定位思路基本如下:首先找到该接口,通过压测工具不断加大访问力度,如果说该接口中有某个位置是比较耗时的,由于我们的访问的频率非常高,那么大多数的线程最终都将阻塞于该阻塞点

  • 通过压测工具不断加大接口访问力度
  • 一直排查,执行了步骤1-4:查看线程快照信息,大量线程都会阻塞在该点
"http-nio-8080-exec-4" #31 daemon prio=5 os_prio=31 tid=0x00007fd08d0fa000 nid=0x6403 waiting on condition [0x00007000033db000]java.lang.Thread.State: TIMED_WAITING (sleeping)-》期限等待at java.lang.Thread.sleep(Native Method)at java.lang.Thread.sleep(Thread.java:340)at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)at com.*.user.controller.UserController.detail(UserController.java:18)-》业务代码阻塞点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/285992.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Avue框架实现图表的基本知识 | 附Demo(全)

目录 前言1. 柱状图2. 折线图3. 饼图4. 刻度盘6. 仪表盘7. 象形图8. 彩蛋8.1 饼图8.2 柱状图8.3 折线图8.4 温度仪表盘8.5 进度条 前言 以下Demo,作为初学者来说,会相应给出一些代码注释,可相应选择你所想要的款式 对于以下Demo&#xff0c…

【云开发笔记No.9】Kanban与敏捷开发

Kanban看板起源于丰田。 看板(Kanban)一词来自日文,本义是可视化卡片。如下图所示,看板工具的实质是:后道工序在需要时,通过看板向前道工序发出信号——请给我需要数量的输入,前道工序只有得到看…

C# 特性(Attribute)

C# 特性(Attribute) 文章目录 C# 特性(Attribute)Obsolete语法示例代码 创建自定义特性(Attribute) Obsolete 这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例…

五、初识Django

初识Django 1.安装django2.创建项目2.1第一种方式:在终端2.2第二种方式:Pycharm 3.创建app4.快速上手4.1再写一个页面4.2templates模板4.3静态文件4.3.1static目录4.3.2引用静态文件 5.模板语法案例:伪联通新闻中心6.请求和相应案例&#xff…

图像变换(python)

前言 这个Python没学过,写的是真的不方便,有很多问题还没解决,暂时不想写了,感兴趣的同学可以完善一下。设计的思路就是摆几个控件然后将对应的函数实现,这个Python的坐标放置以及控件的大小我没弄懂,算出…

3月份的倒数第二个周末有感

坐在图书馆的那一刻,忽然感觉时间的节奏开始放缓。今天周末因为我们两都有任务需要完成,所以就选了嘉定图书馆,不得不说嘉定新城远香湖附近的图书馆真的很有感觉。然我不经意回想起学校的时光,那是多么美好且短暂的时光。凝视着窗…

如何进行Modbus转Profinet网关的调试与故障排除

Modbus转Profinet网关(XD-MDPN100)带有网口和串口很大限度地解决了设备接口不统一的问题,支持485和232,可以实现从Modbus通信协议到Profinet通信协议的无缝转换,为不同协议之间的互联互通提供了便利。 Modbus转Profine…

时间戳的转换-unix时间戳转换为utc时间(python实现)

import datetimetimestamp = 1711358882# 将时间戳转换为UTC时间 utc_time = datetime.datetime.utcfromtimestamp(timestamp)# 格式化并输出时间 formatted_time = utc_time.strftime(%Y-%m-%d %H:%M:%S) print(formatted_time)同样:UTC如何转换为unix时间戳 from datetime …

Axure案例分享—折叠面板(附下载地址)

今天和大家分享的Axure案例是折叠面板 折叠面板是移动端APP中常见的组件之一,有时候也称之为手风琴。咱们先看下Axure画出的折叠面板原型效果,然后再对该组件进行详细讲解。 一、功能介绍 折叠或展开多个面板内容,默认为展开一项内容&…

K8s-网络原理-中篇

引言 本文是《深入剖析 K8s》的学习笔记,相关图片和案例可从https://github.com/WeiXiao-Hyy/k8s_example中获取,欢迎 ⭐️! 上篇主要介绍了 Flannel 插件为例,讲解了 K8s 里容器网络和 CNI 插件的主要工作原理。还有一种“纯三层”的网络方…

C语言程序与设计——预处理命令

宏 在C语言中宏有三种形式: 定义符号常量定义傻瓜表达式定义代码段 在使用宏的过程中需要注意的是,宏的作用仅仅是在预处理阶段对代码进行替换,而非进行运算,所以在使用时,如果出现了我们预期之外的结果,很有可能是宏…

Java代码基础算法练习-搬砖问题-2024.03.25

任务描述: m块砖,n人搬,男搬4,女搬3,两个小孩抬一砖,要求一次全搬完,问男、 女、小孩各若干? 任务要求: 代码示例: package M0317_0331;import java.util.S…

【Android】图解View事件分发机制

文章目录 View事件分发机制dispartchTouchEvent()dispatchTouchEvent() 方法主要负责什么? onTouchEvent(event) 点击事件分发的传递规则自上而下自下而上 View事件分发机制 View的事件分发机制是Android中非常核心的一个概念,它负责处理触摸事件&#…

SpringMVC | Spring MVC中的“拦截器”

目录: 一、拦截器 :1. 拦截器的 “概述”2. 拦截器的 “定义” (创建“拦截器”对象)3. 拦截器的 “配置” (让“拦截器”对象生效)4. 拦截器的 “执行流程”“单个拦截器”的执行流程“多个拦截器”的执行流程 二、应用案例一实现用户登录权限验证 作者简介 &#…

nav仿真(2)

开启仿真和建图 打开第一个窗口启动仿真: source devel/setup.bash export TURTLEBOT3_MODELburger roslaunch turtlebot3_gazebo turtlebot3_world.launch # 启动仿真打开第二个窗口,开始建图: source devel/setup.bash export TURTLEBOT3_…

举4例说明Python如何使用正则表达式分割字符串

在Python中,你可以使用re模块的split()函数来根据正则表达式分割字符串。这个函数的工作原理类似于Python内置的str.split()方法,但它允许你使用正则表达式作为分隔符。 示例 1: 使用单个字符作为分隔符 假设你有一个由逗号分隔的字符串,你可…

Redis入门到实战-第三弹

Redis入门到实战 Redis数据类型官网地址Redis概述Redis数据类型介绍更新计划 Redis数据类型 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的(采用BSD许可证&#…

用大语言模型控制交通信号灯,有效缓解拥堵!

城市交通拥堵是一个全球性的问题,在众多缓解交通拥堵的策略中,提高路口交通信号控制的效率至关重要。传统的基于规则的交通信号控制(TSC)方法,由于其静态的、基于规则的算法,无法完全适应城市交通不断变化的…

Unity 学习日记 8.2D物理引擎

1.2D刚体的属性和方法 2.碰撞器

MySQL -- 开窗函数 row_number 之 先根据名字分组,然后再根据分数排序

目录 开窗函数 row_number需求: 先根据名字分组,然后再根据分数排序 开窗函数 row_number 需求: 先根据名字分组,然后再根据分数排序 sql写法及解释: 可以再加子查询进行条件判断 函数用法解释: