cpu飙高问题,案例分析(二)——批处理数据过大引起的应用服务CPU飙高

news2024/10/6 2:25:53

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

一、批处理数据过大引起的应用服务CPU飙高

1.1 问题场景

某定时任务job 收到cpu连续(配置的时间是180s)使用超过90%的报警;

1.2 问题定位

  1. 观察报警中的jvm监控,发现周期性出现即每天8:00,cpu从5%-99%大约持续3分钟左右然后恢复正常,平时cpu使用率较为平稳(排除因为应用发布导致的cpu升高);
  2. 任务系统周期性出现很可能是定时执行了大量运算导致的,查看任务系统页面,确实存在一个8点执行的定时任务;
  3. 分析代码梳理该任务的业务逻辑为:一个兜底的定时的job任务;其中涉及大量复杂运算,现在猜测基本是改任务导致的,那么可以复现一下,确认下;

复现操作很简单:
a.找一台机器,观察jvm相关监控;观察日志;
b.修改分片数量为1且指定分片容器ip为监控的容器ip,点击执行分片,查看分片确认成功后, 点击执行一次。通过观察步骤c1)成功复现。

  1. 至此基本方向确定是这个任务导致的CPU升高,接下来分析为何CPU升高,以及如何优化问题;

1.3 问题分析

  1. a)也可能是程序运行过程创建大量对象触发GC,GC线程占用CPU过高导致;b)CPU升高原因可能是程序大量运算导致;
  2. 不管是情况a) 还是情况b) 都需要复现问题,观察使用cpu高的线程有哪些,使用jstack命令导出线程栈的信息进行观察,观察每个线程CPU使用率;

1.4 操作步骤

  1. 预发环境触发任务执行,复现场景。注意:此步骤需要谨慎操作,由于预发和线上是相同的数据库,所以预发环境部署代码需要把相关的操作屏蔽掉了,比如发送MQ,更新数据库等。避免影响线上数据和MQ等;
  2. 登录堡垒机使用top命令查看目前的进程信息:
    在这里插入图片描述
  3. 发现java进程33907 使用的cpu已经达到200%,使用命令 top-H -p 33907 命令查看该进程下的哪个线程使用的资源最多
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

340271 5312f Curator-TreeCache-18" #648 daemon prio=5 os_prio=0 tid=0x00007f10dc156000 nid=0x5312f waiting on condition [0x00007f1158bcb000]

1.5 结论

  1. ThreadPoolTaskExecutor为该任务显示创建,核心线程数为2,最大为6,队列大小为300,根据线程栈信息可以看出与程序配置一致,根据实际配置可以发现此部分正常配置符合预期;
  2. 程序中没有创建FrokJoinPool,但是程序使用了大量的 parallelStream();由于parallelStream默认使用的是公共的forkJoinPool线程池,且该线程池的线程数量配置为系统的 Runtime.getRuntime().availableProcessors() - 1; 现在对于parallelStream的使用等于在多线程中,嵌套了多线程;
  3. Curator-TreeCache 线程的来源,通过发现线程池的初始化参数可知:线程的的拒绝策略为CallerRunsPolicy(),该策略为:如果线程池队列和核心线程数满了后,继续提交到线程池的任务会通过方法线程即调用线程池的那个方法来执行,可以理解为主线程;

1.6 优化方案

  1. 修改所有的parallelStream() 为stream();4c8G配置的机器cpu使用率稳定在50%左右;
  2. 2C4G的机器执行,CPU使用率仍然高达90%,通过分析线程栈的dump文件发现主要是业务线程占用资源过高,其中不足2%的还有部分是由于并行流导致的,在job执行时候引用的第三方jar包中,此部分暂时不处理;

对于2C4G优化方案:

  1. 由于这个任务是兜底的,不需要立即执行完成,且执行频率为1天1次可以将线程池调整为1个线程;
  2. 申请容器升级为4c*8G.;

1.7 问题引申

parallelStream()原理:

  1. parallerlStream是jdk8的特性,是在Stream的基础上实现的并行流式操作;旨在简化并行编码,提升运算效率;
  2. 并行流的底层是基于ForkJoinPool实现的,其中ForkJoinPool采用的思想类似MapReduce的思想,将一个大的运算任务拆分为子任务(fork的过程);然后执行所有的子任务运算后的结果合并在一起(join过程); 通过分治的方式完成一个计算;

1.8 parallelStream()最佳实践

1.8.1 并行流使用问题分析

  1. 根据parallelSteam的原理我们知道底层是使用的ForkJoinPool;那么我们程序通常会有如下代码:
//code1
WORDS.entrySet()
	.parallelStream()
	.sorted((a,b)->b.getValue().compareTo(a.getValue()))
	.collect(Collectors.toList());
//code2
Set<String> words = new ConcurrentHashSet<>();
words1
.parallelStream()
.forEach(word -> words.add(word.getText()));
  1. 那么我们并没有创建ForkJoinPool,且不同的集合都在调用parallerStream(), 那么最终用的是哪个线程池呢?很显然既然没有报错,就说明jdk应该会给一个默认的ForkJoinPool。源码如下:

注意:
默认的如果使用默认的线程池执行的话,forkJoinPool会使用当前系统默认的cpu核心数量-1,但是主线程也会参与计算。

执行结果: 可以看出默认的ForkJoinPool线程池,除了worker线程参与运算 ,方法线程也会参与预算。

1.9 最佳实践总结:

  1. 并行流如果使用,最好使用自定义的线程池,避免使用默认的线程池即线程池隔离思想,造成阻塞或者资源竞争等问题;
  2. parallelStream 适用的场景是CPU密集型的,假如本身电脑CPU的负载很大,那还到处用并行流,那并不能起到作用,切记不要再paralelSreram操作是中使用IO流;
  3. 不要在多线程中使用parallelStream,如本次案例,大家都抢着CPU是没有提升效果,反而还会加大线程切换开销;

1.10 踩坑记录:

  Runtime.getRuntime().availableProcessors() ;是jdk提供的获取当前系统的可用的核心数,本次踩坑在于,现在多数应用都是发布在容器中的,虽然应用部署的容器是2C4G的,但是ForkJoinPool创建的ForkJoinPool.commonPool-worker-线程却有几十个,登录容器所在的物理机查看机器配置如下:
在这里插入图片描述
实际为2个cpu每个cpu 32核 总共是64核,编写测试程序验证也是如此:
在这里插入图片描述
  由此可知,默认的ForkJoinPool获取的是当前系统的核心数量,如果应用部署在docker容器中,那么就获取的是宿主机的CPU核心数。

1.11 Runtime.getRuntime().availableProcessors()问题

 容器明明分配的是2个逻辑核心数,为什么java获取的会是物理机的核心数呢?如何解决这个问题呢。

 是否是容器构建的时候某些参数配置的原因导致的? 将问题反馈给运维,但是对方并未解决该问题。

 那么java是否可以解决呢?毕竟如果我们自定义线程池设置线程数量也会使用
Runtime.getRuntime().availableProcessors()这个方法,这其实是JDK的一个问题,已经trace在 JDK-8140793 ,原因是获取CPU核数是通过读取两个环境变量,其中:
在这里插入图片描述
其中_SC_NPROCESSORS_CONF 就是我们需要容器真实的CPU数量。

获取CPU数量的源码

第一种办法是使用新版本的Jdku131以上的版本 :
容器内获取CPU核数的坑

另外一个办法是使用自编译上面的源代码,通过LD_PRLOAD的方式将修改后的so文件加载进去Mock掉CPU的核数。

jdk官方链接声明: Java SE support for Docker CPU and memory limits

1.11.1 使用方法一测试:测试环境容器验证,验证通过,结果如下:

jdk版本 jdk1.8.0_20 :返回cpu核心数28
在这里插入图片描述
jdk版本: jdk-1.8.0_192 返回cpu核心数2
在这里插入图片描述

1.12 建议

尽量使用lambda表达式遍历数据,推荐使用常规的for、for-each模式

原因:

  1. 性能比传统foreach低;

lambda内部有着一套复杂的处理机制(反射、类型转换、拷贝),性能开销要比常规for、for-eatch大的多。在普通业务场景下这种性能差异可以忽略不计,但是在某些高频场景下(N万次调用/秒)就不能忽略了。它虽然不会导致一次迭代卡顿,但是会持续增加cpu的消耗,以及增加GC的压力。

  1. 不便于代码调试;

反例:

// lambda并没有起到简化代码的作用,反而会增加系统压力
List<ValidationResult> results = children.stream()
.map(e -> e.validate(context, nextCell, nextCoverCells, occupyAreas))
.collect(Collectors.toList());
List<ValidationResult> failureList =
results.stream().filter(ValidationResult::isFailure).collect(Collectors.toList());
List<ValidationResult> successList =
results.stream().filter(ValidationResult::isSuccess).collect(Collectors.toList());

正例:

// 优化后总cpu下降2%-4%左右。
// 备注:cpu下降如此明显的原因是该代码的调用频率非常高,真正的N万次/秒调用
List<ValidationResult> failureList = new ArrayList<>(4);
List<ValidationResult> successList = new ArrayList<>(4);
for (PathPreAllocationValidator child : children) {
	ValidationResult result = child.validate(context, currCell, previousCell, nextCell);
	if (result.isSuccess()) {
		successList.add(result);
	} else {
		failureList.add(result);
	}
}

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

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

相关文章

LeetCode(33)最小覆盖子串【滑动窗口】【困难】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 76. 最小覆盖子串 1.题目 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字…

python爬虫实习找工作练习测试(以下内容仅供参考学习)

要求&#xff1a;获取下图指定网站的指定数据 空气质量状况报告-中国环境监测总站 输入&#xff1a;用户输入下载时间范围&#xff0c;格式为2022-10 输出&#xff1a;将更新时间在2022年10月1日到31日之间的文件下载到本地目录&#xff08;可配置&#xff09;&#xff0c;并…

在Rust中编写自动化测试

1.摘要 Rust中的测试函数是用来验证非测试代码是否是按照期望的方式运行的, 测试函数体通常需要执行三种操作:1.设置任何所需的数据或状态;2.运行需要测试的代码;3.断言其结果是我们所期望的。本篇文章主要探讨了Rust自动化测试的几种常见场景。 2.测试函数详解 在Rust项目工…

图像去噪——k-Sigma变换,模拟增益,噪声方差

目录 一、k-Sigma变化k-Sigma变换定义式定义式参数解析 二、模拟增益三、噪声方差 一、k-Sigma变化 k-Sigma变换是一种用于图像去噪的方法&#xff0c;它的主要思想是通过一个特定的线性转换&#xff0c;将训练数据从ISO-dependent的域名转换到ISO-independent的域上。这个转换…

QtCreator创建的文件复制到VS下报错

报错1&#xff1a; 错误 C2447 “{”: 缺少函数标题(是否是老式的形式表?) (编译源文件 myselectpoint.cpp) DataTypeLib e:\qtnewproject\linuxversion\videointerpretationanddataprocesssystem_vs\jwycfsoftware\datatypelib\allstructdefine.h 117 解…

快速开发出一个公司网站

问题描述&#xff1a;参加一个创业活动&#xff0c;小组要求做一个公司网站&#xff0c;简单介绍一下自己公司的业务。需要快速完成。 问题解决&#xff1a;从网上找一个网站模板&#xff0c;类似于做PPT&#xff0c;搭建一个网站即可。 这里推荐的是京美建站、wordpress、he…

车规激光雷达再商用车前装市场的应用

1、商用车需要什么样的激光雷达 2、如何实现车规级&#xff08;商用车&#xff09;的激光雷达 3、激光雷达安装部署方案

PHP TCP服务端监听端口接收客户端RFID网络读卡器上传的读卡数据

本示例使用设备&#xff1a;WIFI/TCP/UDP/HTTP协议RFID液显网络读卡器可二次开发语音播报POE-淘宝网 (taobao.com) <?php header("content-type:text/html;charsetGBK");set_time_limit(0); $port39169; //监听端口if(($socket socket_create(AF_INET, SOCK…

pycharm 怎么切换Anaconda简单粗暴

&#xff08;1&#xff09;创建一个环境 &#xff08;2&#xff09;选择一下自己conda的安装路径中conba.exe (3)选择存在的环境&#xff0c;一般会自动检测到conda创建有哪些环境&#xff0c;导入就行

C++二分查找视频教程:两数之和

作者推荐 利用广度优先或模拟解决米诺骨牌 本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 n…

单片机学习11——矩阵键盘

矩阵键盘&#xff1a; 这个矩阵键盘可以接到P0、P1、P2、P3都是可以的。 使用矩阵键盘是能节省单片机的IO口。 P3.0 P3.1 P3.2 P3.3 称之为行号。 P3.4 P3.5 P3.6 P3.7 称之为列号。 矩阵键盘检测原理&#xff1a; 1、检查是否有键按下&#xff1b; 2、键的抖动处理&#xf…

XIAO ESP32S3之套件简绍

很高兴收到柴火创客空间寄来的XIAO ESP32S3开发套件。 一、套件介绍 1、电路板部分 一块XIAO ESP32S3主板、一块摄像头接口板&#xff08;可接SD卡&#xff09;&#xff0c;一根2.4G天线。 2、配件部分 一根USB-A转TypeC数据线、一个USB3.0转TypeC转接头、一个SD卡读卡器&am…

集动作捕捉与表情捕捉的系统,怎么用于动画制作?

对于传统动画制作来说&#xff0c;将要处理数字人的动作与表情&#xff0c;最原始的方式是打关键帧&#xff0c;通过关键帧的形式来展现数字人的弹跳、行走、奔跑等动作&#xff0c;但这种制作方式往往时间长&#xff0c;成本高&#xff0c;效率低。而一个集动作捕捉与表情捕捉…

spring boot的redis连接数过多导致redis服务器压力过大的一次问题排查

一、背景 在今天上午的时候&#xff0c;突然收到大量的sentry报错&#xff0c;都是关于redis连接超时的警告。 首先想到的是去查看redis的监控&#xff0c;发现那个时间段&#xff0c;redis的请求数剧增&#xff0c;cpu使用率和带宽都陡增双倍。 下面的是redis监控的cpu情况 …

【MySql】14- 实践篇(十二)-grant权限/分区表/自增Id用完怎么办

文章目录 1.grant之后要跟着flush privileges吗&#xff1f;1.1 全局权限1.2 db 权限1.3 表权限和列权限1.4 flush privileges 使用场景 2. 要不要使用分区表?2.1 分区表是什么?2.2 分区表的引擎层行为2.3 分区策略2.4 分区表的 server 层行为2.5 分区表的应用场景 3. 自增Id…

高效视频剪辑:按指定时长批量分割视频,释放无尽创意

随着数字媒体技术的不断发展&#xff0c;视频剪辑已经成为日常生活中不可或缺的一部分。无论是制作电影、电视剧&#xff0c;还是创意生活短视频&#xff0c;视频剪辑都扮演着重要的角色。然而&#xff0c;对于许多非专业人士来说&#xff0c;视频剪辑可能是一项复杂而耗时的任…

数字营销:概述和类型

数字营销无处不在。公司已经开始采用密集的数字营销活动来接触目标受众。从社交媒体句柄到网站&#xff0c;数字营销彻底改变了互联网时代产品和服务的营销和推广方式。本文将详细讨论数字营销的范围和类型。 什么是数字营销&#xff1f; 数字营销使用社交媒体、电子邮件、网…

免费SSL证书有效期只有90天?太短?

随着网络安全问题日益受到重视&#xff0c;SSL证书成为了网站安全的必需品。然而&#xff0c;在许多情况下&#xff0c;免费提供的SSL证书往往只有90天的有效期&#xff0c;这种期限对于很多用户来说显得过于短暂。 首先&#xff0c;我们要理解为什么 SSL 证书的有效期设定为90…

P8A003-系统加固-系统管理员账户安全

【预备知识】 Administrator 原意为管理人或行政官员或遗产管理人&#xff0c;在计算机名词中&#xff0c;它的意思是系统超级管理员或超级用户。但是在Windows系统中此用户名只在安全模式中使用。 【实验步骤】 网络拓扑&#xff1a;server2008-basic windows server 2008 …

Ps:转换路径

在 Photoshop 中&#xff0c;路径 Path是一种非常灵活的手段&#xff0c;可以被转换成多种不同的形式&#xff0c;以适应各种不同的设计和编辑需求。 ◆ ◆ ◆ 将路径转换为选区 方法一&#xff1a; 在使用路径类工具的状态下&#xff0c;在路径上右键选择“建立选区” Make …