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

news2024/11/15 5:33:00

一、复习知识点:

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 above
	final T readObject = (T) in.readObject();
	return readObject;
	} catch (final ClassNotFoundException ex) {
		throw new SerializationException("ClassNotFoundException while reading cloned
		object data", ex);
	} catch (final IOException ex) {
		throw new SerializationException("IOException while reading or closing cloned
		object 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.coloradmin.cn/o/1232218.html

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

相关文章

CommonModule.dll动态链接库(DLL)文件丢失的处理方法

方法一、手动下载修复 (1)从网站下载commonmodule.dll文件到您的电脑上。 (2)将commonmodule.dll文件复制到" X:\Windows\system32 " (X代表您系统所在目录盘符&#xff0c;如&#xff1a;C:\Windows\system32)目录下。 (3)在开始菜单中找到"运行(R)" 或…

shell 脚本变量

目录 什么是 shell shell 的两种面向对象 shell 脚本概述 脚本 &#xff08;本质为程序&#xff09; 脚本的组成 执行脚本 例题 脚本构成 脚本执行逻辑及执行方式 脚本的常见错误 编写 shell 脚本 执行脚本文件的方式 重定向 重定向操作 shell 变量的作用及类型…

智能井盖传感器功能有哪些?

智能井盖传感器是一种集成了多种先进技术的传感器设备&#xff0c;旨在强化城市的公共安全&#xff0c;确保城市基础设施的稳定运作。这种传感器具有多种功能&#xff0c;例如实时监测井盖状态、监测井下气体等是否超出阈值。借助智能井盖传感器&#xff0c;政府和城市管理部门…

C++:拷贝构造函数,深拷贝,浅拷贝

一.什么是拷贝构造函数&#xff1f; 同一个类的对象在内存中有完全相同的结构&#xff0c;如果作为一个整体进行复制&#xff08;拷贝&#xff09;是完全可行的。这个拷贝过程只需要拷贝数据成员&#xff0c;而函数成员是共用的&#xff08;只有一份拷贝&#xff09;。在建立对…

1230天,百度再见!!!

从2020年7月8日至2023年11月20日&#xff0c;在百度的工作到达了终点&#xff0c;完成了从学生向职场人的蜕变&#xff0c;是时候说再见了&#xff01; 一、成长收获 在这1230天里收获颇丰&#xff0c;下面与各位分享一下。 从技术至上到业务赋能的思想转变 相信很多人都存在“…

一个完备的手游地形实现方案

一、地形几何方案&#xff1a;Terrain 与 Mesh 1.1 目前手游主流地形几何方案分析 先不考虑 LOD 等优化手段&#xff0c;目前地形的几何方案选择有如下几种&#xff1a; 使用 Unity 自带的 Terrain使用 Unity 自带的 Terrain&#xff0c;但是等美术资产完成后使用工具转为 M…

键盘快捷键工具Keyboard Maestro mac中文版介绍

Keyboard Maestro mac是一款键盘快捷键工具&#xff0c;它可以帮助用户通过自定义快捷键来快速完成各种操作&#xff0c;提高工作效率。Keyboard Maestro支持多种快捷键组合&#xff0c;包括单键、双键、三键、四键组合等&#xff0c;用户可以根据自己的习惯进行设置。此外&…

全志H616开发版

开发板介绍&#xff1a; 二、开发板刷机 SDFormatter TF卡的格式化工具、Win32Diskimager 刷机工具 刷机镜像为&#xff1a;Orangepizero2_2.2.0_ubuntu_bionic_desktop_linux4.9.170.img 使用MobaXterm_Personal_20.3连接使用 网络配置&#xff1a;nmcli dev wifi 命令接入网…

PLC梯形图实操——风扇正反转

文章目录 1.项目内创建函数块&#xff08;FB&#xff09;2.项目内创建数据块&#xff08;DB&#xff09;2.1去除优化块访问2.2去除优化块的访问后对数据块进行编译 3.在函数块&#xff08;FB&#xff09;内实现正转反转的自锁与互锁3.1在函数块内实现电机正反转的梯形图 4.主函…

Python的os.path.join()详解

当你需要构建文件路径时&#xff0c;os.path.join() 是一个很有用的方法。这个方法会根据你的操作系统使用正确的路径分隔符&#xff08;例如&#xff0c;在 Windows 上是反斜杠 \&#xff0c;在类 Unix 系统上是正斜杠 /&#xff09;来连接路径中的各个部分。这样你就可以确保…

Django实战:从零到一构建安全高效的Web应用

目录 一、概述 二、版本控制和部署 1、Git版本控制 2、Docker部署 三、数据库配置 1、配置数据库设置 2、创建数据库模型 四、URL路由和视图 1、定义URL路由 2、创建视图 五、模板渲染 1、创建模板 2、在视图中使用模板 总结 一、概述 Django是一个高级Python W…

HarmonyOS4.0系列——01、下载、安装、配置环境、搭建页面以及运行示例代码

HarmonyOS4.0应用开发 安装编辑器 这里安装windows版本为例 安装依赖 打开DevEco Studio 这八项全部打钩即可开始编写代码&#xff0c;如果存在x&#xff0c;需要安装正确的库即可 开发 点击Create Project 选择默认模板——next Model部分分为Stage和FA两个应用模型&…

[架构之路-247]:目标系统 - 设计方法 - 软件工程 - 结构化方法的基本思想、本质、特点以及在软件开发、在生活中的应用

目录 前言&#xff1a; 一、什么是非结构化方法 1.1 什么是非结构化方法 1.2 非结构化方法的适用场合 二、什么是结构化方法 1.1 结构化方法诞生的背景&#xff1a;软件规模发展&#xff1a;大规模、复杂系统的需要 1.2 概述 1.3 主要特点与核心思想 三、结构化方法在…

Windows 安装 Docker Compose

目录 前言什么是 Docker Compose &#xff1f;安装 Docker Compose配置环境变量结语开源项目 前言 在当今软件开发和部署领域&#xff0c;容器化技术的应用已成为提高效率和系统可移植性的关键手段。Docker&#xff0c;作为领先的容器化平台&#xff0c;为开发人员提供了轻松构…

【手撕数据结构】(三)顺序表和链表

文章目录 一、线性表二、顺序表1.概念及结构2.关于数组3.顺序表分类&#x1f397;️静态顺序表&#x1f397;️动态顺序表 4.接口实现&#xff08;1&#xff09;思路&#xff08;2&#xff09;SeqList.h文件代码功能1&#xff1a;顺序表初始化功能2&#xff1a;销毁顺序表功能3…

硬盘Write Cache设置效果差异之谜!

Write Cache这个概念对于大家应该不陌生&#xff0c;主要是机械HDD中会有很明显的效果。 Write Cache Enable&#xff0c;WCE&#xff1a;数据不会直接落盘&#xff0c;而是写入DRAM缓存后就直接返回了&#xff0c;对于随机写和顺序写的性能都会有所改善。这个场景&#xff0c;…

el-table 对循环产生的空白列赋默认值

1. el-table 空白列赋值 对el-table中未传数据存在空白的列赋默认值0。使用el-table 提供的插槽 slot-scope&#xff1a;{{ row || ‘0’ }} 原数据&#xff1a; <el-table-column label"集镇" :propcity ><template slot-scope"{row}">{{…

机器学习-笔记

绪论 参考期刊 ICCV 偏向视觉CVPR 偏向MLIAAA AI原理ICML 参考链接 CSDN 机器学习知识点全面总结 课堂内容学习-0912-N1 对于特征提取&#xff0c;简而言之就是同类聚得紧&#xff0c;异类分得开&#xff1b;   detection研究的是样本二分类问题&#xff0c;即分为正样本…

【ArcGIS Pro微课1000例】0033:ArcGIS Pro处理cad数据(格式转换、投影变换)

文章目录 一、cad dwg转shp1. 导出为shp2. cad至地理数据库3. data interoperability tools二、shp投影变换一、cad dwg转shp 1. 导出为shp 加载cad数据,显示如下: 选择需要导出的数据,如面状,右键→数据→导出要素: 导出要素参数如下,点击确定。 导出的要素不带空间参…

“非旺玖原装的PL2303,.........“解决办法

"非旺玖原装的PL2303&#xff0c;…"解决办法 windows安装PL2303串口驱动提示“非旺玖原装的PL2303&#xff0c;请联系您的供货商”的解决办法&#xff1a; 主要原因&#xff1a;驱动版本无法兼容&#xff0c;需要降低使用版本 解决办法&#xff1a; 1.插好串口线&…