cpu飙高问题,案例分析(一)

一、复习知识点:

CPU性能指标:
load average:负载,linux查看的时候,通常显示如下:
top命令后,显示
load average后面有三段数字:代表了系统1分钟,5分钟,15分钟平均负载。
形象的类别可以参考:了解 Linux CPU 负载 - 什么时候应该担心?(网址可翻译中文)
另一个形象的比喻:CPU的load和使用率傻傻分不清(非常重要,建议详细阅读)
top命令显示2
load average高,%Cpu(s)低,表示:负载高,利用率低。

二、查看cpu飙升原因需要用到的命令

查看cpu信息:

cat /proc/cpuinfo

仅显示将使用的处理器名称:

grep -c 'model name' /proc/cpuinfo

2.1 定位CPU标高

1.执行完 java -jar 2_cpu-0.0.1-SNAPSHOT.jar 8 > log.file 2>&1 & 命令:
在这里插入图片描述
2.查看进程号,jps -l
在这里插入图片描述
3.用top查看进程中的线程,top -Hp 25128
在这里插入图片描述
4.执行后,就出来了每个线程锁占的cpu,如图:
在这里插入图片描述
最简单直接的,就是看某个线程的cpu占用;
有一种情况不好分析:分析是正常现象还是异常现象,有些项目可以cpu执行就稳态在60%-70%之间。

5.将线程转成16进制,printf “%x\n” 25148
在这里插入图片描述
这里的623c就是25148线程的16进制线程号。

6.导出某线程的stack,jstack 25128 》stack.txt
在这里插入图片描述
7.到stack.txt文本中找623c线程号相关日志:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 总结

方法1:

  1. 启动:java -jar 2_cpu-0.0.1-SNAPSHOT.jar 8 > log.file 2>&1 &
  2. 一般来说,应用服务器通常只部署了java应用,可以top一下先确认,是否是java应用导致的:命令:top
  3. 如果是,查看java进场ID,命令:jps -l
  4. 找出该进程内最好非CPU的线程,命令:top -Hp pid 25128
  5. 将线程ID转化为16进制,命令:printf “%x\n” 线程ID 623c 25148
  6. 导出java堆栈信息,根据上一步的线程ID查找结果:命令:
    jstack 11976 >stack.txt
    grep 2ed7 stack.txt -A 20

方法2:
在线工具:FastThread

  1. 方法1中导出的对快照文件,上传到该网站即可

三、案例一:序列化问题引起的应用服务CPU飙高

3.1 发现问题

7.8日 17:09监控大盘发现xxx-web的CPU快跑满,导致机器不断扩容增加机器。

平均负载图如下:
在这里插入图片描述

CPU利用率:
在这里插入图片描述

3.2 分析阶段

  根据对线程dump文件进行分析,主要是否存在死锁、阻塞现象,以及CPU线程的占用情况,分析工具采用在线fastThread工具。地址: https://gceasy.io/ft-index.jsp

3.2.1 查看线程数情况

 数据图示可知,创建的线程等待线程有3000,提示高线程数可能导致内存泄露异常,从而可能影响后面任务的创建线程。
在这里插入图片描述

3.2.2 查看当前CPU线程使用情况

  根据CPU线程情况,查询CPU正在执行的线程堆栈列表,可以发现大部分日志都是类似于:catalina-exec-879
在这里插入图片描述

3.2.3 定位出现问题的线程堆栈

  查看是新版头像圈的一段代码逻辑,其中有个步骤需要深拷贝对象,以便以后逻辑更改使用。
在这里插入图片描述

3.3 问题恢复

 从而猜测可能是跟8号开放一批白名单规则用户有关,所以临时采用更改config的白名单策略配置,降低灰度用户范围。通过配置推送后,CPU利用率恢复正常情况。

3.4 相关代码

public Map<String, TopHeadInfoV3> getTopHeadInfoGroupByLiveIdCache(){Map<String, TopHeadInfoV3> topHeadInfoGroupByLiveIdMap =topHeadInfoGroupByLiveIdCache.getUnchecked("top_head_info_group_by_live_id");if (MapUtils.isEmpty(topHeadInfoGroupByLiveIdMap)) {return Collections.emptyMap();} // guava cache 对象对外不可⻅,防⽌上游对cache⾥对象进⾏修改,并发场景下出现问题Map<String, TopHeadInfoV3> topHeadInfoGroupByLiveIdMapDeepCopy =Maps.newHashMapWithExpectedSize(topHeadInfoGroupByLiveIdMap.size());for (Map.Entry<String, TopHeadInfoV3> entry : topHeadInfoGroupByLiveIdMap.entrySet()) {topHeadInfoGroupByLiveIdMapDeepCopy.put(entry.getKey(),SerializationUtils.clone(entry.getValue()));} return topHeadInfoGroupByLiveIdMapDeepCopy;
}

 其中影响性能的问题方法是apache commongs工具包提供的对象克隆工具:SerializationUtils.clone(entry.getValue())),基本操作就是利用Object InputStream和Object OutputSTream进行,先序列化再发序列化。频繁克隆且耗时较长,导致占用其他任务的执行。

	// Clone//-----------------------------------------------------------------------/*** <p>Deep clone an {@code Object} using serialization.</p>* *<p>This is many times slower than writing clone methods by hand* on all objects in your object graph. However, for complex object* graphs, or for those that don't support deep cloning this can* be a simple alternative implementation. Of course all the objects* must be {@code Serializable}.</p>* *@param <T> the type of the object involved* @param object the {@code Serializable} object to clone* @return the cloned object* @throws SerializationException (runtime) if the serialization fails*/
public static <T extends Serializable> T clone(final T object) {if (object == null) {return null;}final byte[] objectData = serialize(object);final ByteArrayInputStream bais = new ByteArrayInputStream(objectData);try (ClassLoaderAwareObjectInputStream in = new ClassLoaderAwareObjectInputStream(bais,object.getClass().getClassLoader())) {/** when we serialize and deserialize an object,* it is reasonable to assume the deserialized object* is of the same type as the original serialized object*/@SuppressWarnings("unchecked") // see abovefinal T readObject = (T) in.readObject();return readObject;} catch (final ClassNotFoundException ex) {throw new SerializationException("ClassNotFoundException while reading clonedobject data", ex);} catch (final IOException ex) {throw new SerializationException("IOException while reading or closing clonedobject data", ex);}
}

源代码注释:
使用序列化来深度克隆一个对象。
这比在你的对象图中的所有对象上手工编写克隆方法要慢很多倍。然而,对于复杂的对象图,或者那些不支持深度克隆的对象,这可以是一个简单的替代实现。当然,所有的对象必须是可序列化的。

3.5 优化方案

经过讨论临时采用创建对象和属性设置的方式进行对象复制,先不采用对象序列化工具。实现java.lang.Cloneable接口并实现clone方法。
主要对象拷贝代码如下:

@Override
public TopHeadInfoV3 clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {return null;}TopHeadInfoV3 topHeadInfoV3 = (TopHeadInfoV3) object;topHeadInfoV3.playEnums = Sets.newHashSet(topHeadInfoV3.playEnums);topHeadInfoV3.recallTypeEnums = Sets.newHashSet(topHeadInfoV3.recallTypeEnums);topHeadInfoV3.behaviorEnums = Sets.newHashSet(topHeadInfoV3.behaviorEnums);topHeadInfoV3.micLinkUserList =topHeadInfoV3.micLinkUserList.stream().map(MicLinkUser::clone).collect(Collectors.toList());return topHeadInfoV3;}

3.7 问题总结

针对相对大流量的接口可以提前做好压测分析;
上线后定期通过监控大盘查看线上运行情况,留意机器监控告警便于及时发现问题;
若告警或大盘发现问题CPU或内存使用情况异常,其中可以打印线程堆栈日志,通过堆栈分析工具帮助分析线程使用的情况。

序列化参考:eishay/jvm-serializers

四、案例二:FULL GC引起的应用服务CPU飙高

4.1 排查过程

  1. 查看机器监控,初步判断可能有耗CPU的线程;
  2. 导出jstat信息,发现JVM老年代占用过高(达到97%),Full-GC频率超高,FULL-GC总共占用了36小时。初步定位是频繁FULL-GC导致CPU负载过高。
    在这里插入图片描述
  3. 使用jmap –histo导出堆概要信息,发现有个超大的HashMap;
  4. 使用jmap –dump导出堆。得出hashMap中的KEY是运单号;

4.2 总结

  1. 使用缓存时要做容量估算,并考虑数据增长率;
  2. 缓存要有过期时间;

五、gc问题导致调用端出现RpcException问题排查

5.1 场景问题案例解读:

  1. 该应用上线弹性数据库后,调用端通过接口查询历史库应用服务时,出现大面积RpcException,如下图所示:
    在这里插入图片描述
  2. 观察该应用,full gc 情况,如下图所示,会出现高频full gc 情况,如图所示:
    在这里插入图片描述
  3. 观察应用,young gc情况,如下图所示:
    在这里插入图片描述
  4. 查看jvm配置参数时,配置内容如下(可以通过ump、应用配置、堡垒机打印应用信息等方式查看)
-Xss512k
-Xmn2048m
-XX:+UseConcMarkSweepGC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+CMSParallelRemarkEnabled
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingOccupancyFraction=60
-XX:CMSInitiatingPermOccupancyFraction=60
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintClassHistogram
-Xloggc:/export/Logs/jvm/gc.log
  1. 通过jstat命令打印内存,情况如下图所示:
    命令:jstat -gcutil pid
    在这里插入图片描述
  2. 之前我们已经配置了jvm参数来打印gc日志,如下所示
    在这里插入图片描述
    综上所述:

  通过gc日志可以看到CMS remark阶段耗时较长,如果频繁的full gc且remark时间比较长,会导致调用端大面积超时,接下来需要通过jstat命令查看内存情况结合配置的jvm启动参数看一下为啥会频繁的full gc。应用jvm启动参数配置了-XX:CMSInitiatingPermOccupancyFraction=60,持久带使用空间占60%的时候就会触发一次full gc,由于持久带存放的是静态文件,持久带一般情况下对垃圾回收没有显著影响。所以可考虑去掉该配置项。

解决方案:

 持久带用于存放静态文件,如今Java类、方法等, 持久代一般情况下对垃圾回收没有显著影响,应用启动后持久带使用量占比即接近60%,所以可考虑去掉该配置项。

同时增加配置项-XX:+CMSScavengeBeforeRemark,在CMS GC前启动一次young gc,目的在于减少old gen对ygc gen的引用,降低remark时的开销(通过上述案例可观察到,一般CMS的GC耗时 80%都在remark阶段 )

jvm启动参数更正如下:

-Xss512k
-XX:+UseConcMarkSweepGC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=80
-XX:+CMSScavengeBeforeRemark
-XX:+CMSParallelRemarkEnabled
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/export/Logs/jvm/gc.log
-javaagent:/export/servers/jtrace-agent/pinpoint-bootstrap-1.6.2.jar
-Dpinpoint.applicationName=afs
-Dpinpoint.sampling.rate=100

备注:相比有问题版本,去除了配置项:-XX:CMSInitiatingPermOccupancyFraction=60。

-XX:CMSInitiatingOccupancyFraction 修改为80(Concurrent Mark Sweep (CMS)
Collector ),添加配置项
-XX:+CMSScavengeBeforeRemark,为了个更好的观察
gc日志,修改时间戳打印格式为-XX:+PrintGCDateStamps

5.2 其他:

  • -XX:CMSInitiatingOccupancyFraction;
  • -XX:+CMSScavengeBeforeRemark;

这两个参数建议不要配,直接使用jvm默认的。

垃圾回收器:
国内基本都是用jdk1.8,要不用CMS,要不就是用G1;

触发young gc只可能有两个条件:

  1. 新生代(eden区)内存不够;
  2. 配置了XX:+CMSScavengeBeforeRemark 参数,在运行full gc(full gc本身就会有young gc)之后,强制又运行了young gc;

命令:

  • jps
  • jinfo

五、Idea安装VisualVM launcher插件

Idea 离线安装插件 Idea 安装离线插件

IDEA插件的在线离线安装

IDEA集成性能分析神器VisualVM

注意:

VisualVM launcher离线安装是jar格式,不是zip格式;

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

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

相关文章

使用npm发布自己的组件库

在日常开发中&#xff0c;我们习惯性的会封装一些个性化的组件以适配各种业务场景&#xff0c;突发奇想能不能建一个自己的组件库&#xff0c;今后在各种业务里可以自由下载安装自己的组件。 一. 项目搭建 首先直接使用vue-cli创建一个vue2版本的项目&#xff0c;并下载好ele…

Ps:陷印

在准备图像进行专业印刷之前&#xff0c;陷印 Trap是一个重要的步骤。 在彩色印刷中&#xff0c;多种颜色的墨水通常分别印刷。陷印是一种叠印技术&#xff0c;它可避免打印时印版的微小偏差或移动而使打印图像出现微小的缝隙。 进行陷印处理以纠正未对齐现象 A. 未对齐现象&am…

代码逻辑修复与其他爬虫ip库的应用

在一个项目中&#xff0c;由于需要设置 http_proxy 来爬虫IP访问网络&#xff0c;但在使用 requests 库下载文件时遇到了问题。具体表现为在执行 Python 脚本时&#xff0c;程序会阻塞并最终超时&#xff0c;无法正常完成文件下载。 解决方案 针对这个问题&#xff0c;我们可以…

VB.net读写S50/F08IC卡,修改卡片密码控制位源码

本示例使用设备&#xff1a;Android Linux RFID读写器NFC发卡器WEB可编程NDEF文本/智能海报/-淘宝网 (taobao.com) 函数声明 Module Module1读卡函数声明Public Declare Function piccreadex Lib "OUR_MIFARE.dll" (ByVal ctrlword As Byte, ByRef serial As Byte, …

基于单片机K型热电偶温度采集报警系统

**单片机设计介绍&#xff0c; 基于单片机K型热电偶温度采集报警系统 文章目录 一 概要简介系统特点系统组成工作原理应用领域 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 # 基于单片机K型热电偶温度采集报警系统介绍 简介 该系统是基于单片…

【论文阅读笔记】Deep learning for time series classification: a review

【论文阅读笔记】Deep learning for time series classification: a review 摘要 在这篇文章中&#xff0c;作者通过对TSC的最新DNN架构进行实证研究&#xff0c;探讨了深度学习算法在TSC中的当前最新性能。文章提供了对DNNs在TSC的统一分类体系下在各种时间序列领域中的最成功…

8 Redis与Lua

LUA脚本语言是C开发的&#xff0c;类似存储过程,是为了实现完整的原子性操作&#xff0c;可以用来补充redis弱事务的缺点. 1、LUA脚本的好处 2、Lua脚本限流实战 支持分布式 import org.springframework.core.io.ClassPathResource; import org.springframework.data.redis…

Excel 文件比较工具 xlCompare 11.01 Crack

比较两个 Excel 文件之间的差异 xlCompare. xlCompare.com 是性能最佳的 Excel diff 工具&#xff0c;用于比较两个 Excel 文件或工作表并在线突出显示差异。xlCompare 包括免费的在线 Excel 和 CSV 文件比较服务以及用于比较和合并 Excel 文件的强大桌面工具。如果您想在线了…

软件测试: 测试用例

一. 软件测试四要素 测试环境,操作步骤,测试数据,预期结果 二. 基于需求进行测试用例的设计 基于需求设计测试用例是测试设计和开发测试用例的基础,第一步就要分析测试需求,验证需求是否正确,完整,无二义性,并且逻辑自洽.在需求正确的基础上细化测试需求,从测试需求提炼出一…

React整理总结(五、Redux)

1.Redux核心概念 纯函数 确定的输入&#xff0c;一定会产生确定的输出&#xff1b;函数在执行过程中&#xff0c;不能产生副作用 store 存储数据 action 更改数据 reducer 连接store和action的纯函数 将传入的state和action结合&#xff0c;生成一个新的state dispatc…

猫12分类:使用yolov5训练检测模型

前言&#xff1a; 在使用yolov5之前&#xff0c;尝试过到百度飞桨平台&#xff08;小白不建议&#xff09;、AutoDL平台&#xff08;这个比较友好&#xff0c;经济实惠&#xff09;训练模型。但还是没有本地训练模型来的舒服。因此远程了一台学校电脑来搭建自己的检测模型。配置…

hdfsClient_java对hdfs进行上传、下载、删除、移动、打印文件信息尚硅谷大海哥

Java可以通过Hadoop提供的HDFS Java API来控制HDFS。通过HDFS Java API&#xff0c;可以实现对HDFS的文件操作&#xff0c;包括文件的创建、读取、写入、删除等操作。 具体来说&#xff0c;Java可以通过HDFS Java API来创建一个HDFS文件系统对象&#xff0c;然后使用该对象来进…

集合的自反关系和对称关系

集合的自反关系和对称关系 一&#xff1a;集合的自反关系1&#xff1a;原理&#xff1a;2&#xff1a;代码实现 二&#xff1a;对称关系1&#xff1a;原理&#xff1a;2&#xff1a;代码实现 三&#xff1a;总结 一&#xff1a;集合的自反关系 1&#xff1a;原理&#xff1a; …

【python】直方图正则化详解和示例

直方图正则化&#xff08;Histogram Normalization&#xff09;是一种图像增强技术&#xff0c;目的是改变图像的直方图以改善图像的质量。具体来说&#xff0c;它通过将图像的直方图调整为指定的形状&#xff0c;以增强图像的对比度和亮度。 直方图正则化的基本步骤如下&…

【Android Jetpack】Hilt的理解与浅析

文章目录 依赖注入DaggerHiltKoin添加依赖项Hilt常用注解的含义HiltAndroidAppAndroidEntryPointInjectModuleInstallInProvidesEntryPoint Hilt组件生命周期和作用域如何使用 Hilt 进行依赖注入 本文只是进行了简单入门&#xff0c;博客仅当做笔记用。 依赖注入 依赖注入是一…

某60区块链安全之不安全的随机数实战二学习记录

区块链安全 文章目录 区块链安全不安全的随机数实战二实验目的实验环境实验工具实验原理实验内容EXP利用 不安全的随机数实战二 实验目的 学会使用python3的web3模块 学会以太坊不安全的随机数漏洞分析及利用 实验环境 Ubuntu18.04操作机 实验工具 python3 实验原理 由…

吴恩达《机器学习》9-1:代价函数

一、引入新标记方法 首先&#xff0c;引入一些新的标记方法&#xff0c;以便更好地讨论神经网络的代价函数。考虑神经网络的训练样本&#xff0c;其中每个样本包含输入 x 和输出信号 y。我们用 L 表示神经网络的层数&#xff0c;表示每层的神经元个数&#xff08;表示输出层神…

基于单片机GPS轨迹定位和里程统计系统

**单片机设计介绍&#xff0c; 基于单片机GPS轨迹定位和里程统计系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 一个基于单片机、GPS和里程计的轨迹定位和里程统计系统可以被设计成能够在移动的交通工具中精确定位车辆的位置…

Spring Boot - 自定义注解来记录访问路径以及访问信息,并将记录存储到MySQL

1、准备阶段 application.properties&#xff1b;yml 可通过yaml<互转>properties spring.datasource.urljdbc:mysql://localhost:3306/study_annotate spring.datasource.usernameroot spring.datasource.password123321 spring.datasource.driver-class-namecom.mysq…

【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…