系统Cpu利用率降低改造之路

系统Cpu利用率降低改造之路

一.背景

1.1 系统背景

该系统是一个专门爬取第三方数据的高并发系统,该系统单台机器以每分钟400万的频次查询第三方数据,并回推给内部第三方系统。从应用类型上看属于IO密集型应用,为了提高系统的吞吐量和并发,我们引入了协程(Quasar框架)。由于业务的特殊性,高峰期的时候我们需要管理快300台机器,抛开单台机器每个月成本不算,光是通过后台管理系统更改快300台机器的配置和将机器出局Ip加入到第三方代理提供商的白名单中这一过程就比较繁琐,且容易出现问题。为了解决这一历史遗留问题,降低机器成本,以及提高运维效率,就有了下面的改造之路。

1.2 知识背景

1.2.1 什么是平均负载

平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。它不仅包括了正在使用 CPU 的进程,还包括等待 CPU等待 I/O 的进程。

1.2.2 什么是CPU使用率

CPU 使用率,是单位时间内 CPU 繁忙情况的统计。

1.2.3 平均负载和CPU使用率的关系

  • CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
  • I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
  • 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。

二.发现与猜想

2.1 发现问题

通过监控发现我们的系统单台机器(8C,16G)的CPU利用率竟然维持在80%-90%左右,负载接近过载

在这里插入图片描述
在这里插入图片描述
由于我们的系统是IO密集型应用,理论上CPU利用率不可能这么高,所以就需要分析为什么CPU利用率高,CPU利用率过高会间接的导致CPU负载过高,导致CPU队列中的任务调度不过来,从而出现吞吐量降低,扫描次数下降等问题。

2.2 猜想

根据经验我们猜测是不是代码里面出现了耗时计算,死循环,大量序列化反序列化等会导致CPU升高的操作。

三.分析问题

3.1 猜想一:并发过高导致日志打印过多

根据框架同事反馈,我们系统每分钟大概向CLog日志系统输出1G左右日志,经过分析发现是由于日志报文过大且量级较多导致。为此在不影响业务的情况下,我们采用了抽样的方式向日志系统输出日志。分析代码底层我们输出日志时存在序列化有可能导致CPU飘高,为此我们采用了直接调用对象的toString方法直接转换成String输入。但是发上线上后,CPU利用率整体只下降了1%~2%,效果不是很明显。

3.2 猜想二 :压缩回推业务数据导致CPU高

由于系统原先部署在公司外部,回推数据的报文较大且是外网和内网交互,当时带宽不足,可能会出现数据丢失现象,所以当时做了数据压缩功能。我们猜测是不是由于压缩数据存在计算逻辑而导致CPU过高。由于目前目前系统已迁入公司内部,内网之间交互无需考虑带宽的影响,经过验证我们发现可以关闭压缩功能,发上线上后,效果仍然不明显,CPU利用率整体只下降了3%~4%左右,效果仍然不是很明显。

3.3 猜想三: 代码中存在常量字符串频繁反序列化成对象操作

经过上述两个优化后,我们的CPU利用率降了4%~6%左右,但是远远没有达到我们的预期,为此我们开始分析业务代码,通过Arthas(Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率)分析占用CPU较高的堆栈信息。我们发现有些类中定义一个静态成员变量,每次调用方法都将该成员变量反序列化成一个对象,在并发高的场景下,频繁的反序列化,显而易见会产生性能问题。下面只列举其中一个,在每次调用test方法时,都将SPECIAL_SEAT_NAME_MAPPING这个常量反序列化成一个Map,并且每次都会将Mapvalue切割,底层采用的是正则很明显会有效率问题。

public class Test {private static final String SPECIAL_SEAT_NAME_MAPPING = "{\"3\": \"硬卧|二等卧\", \"J\": \"二等卧|硬卧\",\"4\": \"软卧|一等卧\", \"I\": \"一等卧|软卧\"}";private void test(SeatInventory seat, String seatTypes) {if (StringUtils.isNotBlank(seatTypes)) {HashSet<String> seatTypeList = Sets.newHashSet(seatTypes.split(""));Map<String, Object> specialSeatNameMap = JacksonUtils.toMap(SPECIAL_SEAT_NAME_MAPPING);for (String seatCode : seatTypeList) {String special_name = String.valueOf(specialSeatNameMap.get(seatCode));String oldName = seat.getSeat_name();if (StringUtils.contains(special_name, oldName) && !StringUtils.startsWith(special_name, oldName)) {seat.setSeat_name(Splitter.onPattern("\\|").splitToList(special_name).get(0));}}}}
}

更改后代码如下:将反序列化操作前置,避免每次都反序列化对象,并将其中对value进行切割的操作也前置,避免每次都切割,以此来减少性能开销。经过此次更改CPU利用率竟然下降了**8%~12%**左右。

public class Test {private static final String SPECIAL_SEAT_NAME_MAPPING = "{\"3\": \"硬卧|二等卧\", \"J\": \"二等卧|硬卧\",\"4\": \"软卧|一等卧\", \"I\": \"一等卧|软卧\"}";public static final Map<String, List<String>> specialSeatNameMap = new ConcurrentHashMap<>();static {Map<String, Object> result = JacksonUtils.toMap(SPECIAL_SEAT_NAME_MAPPING);for (Map.Entry<String, Object> entry : result.entrySet()) {String specialName = String.valueOf(entry.getValue());List<String> specialNameList = Splitter.onPattern("\\|").splitToList(specialName);specialSeatNameMap.put(entry.getKey(), specialNameList);}}private void test2(SeatInventory seat, String seatTypes) {if (StringUtils.isNotBlank(seatTypes)) {HashSet<String> seatTypeList = Sets.newHashSet(seatTypes.split(""));for (String seatCode : seatTypeList) {List<String> specialNameList = specialSeatNameMap.get(seatCode);String oldName = seat.getSeat_name();if (CollectionUtils.isNotEmpty(specialNameList) && specialNameList.contains(oldName) && !Objects.equals(specialNameList.get(0),oldName)) {seat.setSeat_name(specialNameList.get(0));}}}}
}

3.4 猜想四: 系统中存在大量深拷贝

通过Arthas命令我们发现,系统内存在大量JacksonUtils.toBeanJacksonUtils.toList调用来实现深拷贝功能,查看代码我们发现由于数据只有一份,会对这一份数据进行过滤并更改数据中的某些字段的值,所以需要拷贝两份完全一样的数据,来达到更改数据互不影响对方的属性值。由于采用的是序列化和反序列化的方式来生成新的对象,这种方式在并发高的系统中是及其消耗CPU的。下图是Arthas打印的Cpu利用率占用较高的堆栈信息。
在这里插入图片描述
在这里插入图片描述

为此我们决定在不影响业务的前提下寻找一种能实现深拷贝且不怎么占用CPU资源的方式来替代目前这种方式。经过调研几种能实现拷贝的工具Spring的BeanUtils.copyPropertiesApache BeanUtils.copyProperties发现都存在很多坑。对于List的拷贝是属于浅拷贝,需要自己写兼容逻辑才能实现深拷贝,并且底层采用反射的方式从一定程度上来讲,采用反射的方式在并发高的情况下也会出现性能问题,不仅不能解决目前的问题,可能还要引发其他问题。对此我们采用了最原始的方式,采用new 对象的方式来实现深拷贝。经过这次的优化CPU利用率直降20%~25%

四.结果

经过上述优化我们系统的CPU使用率从原先的80%-90%左右直接下降到了30%左右,负载也由原来的接近过载降到了原先的三分之一,我们发现原先我们单台机器每分钟查询8W次会出现瓶颈,按照优化之后理论上我们可以单台机器可以每分钟查询24W次,这样原先需要3台机器才能满足的查询次数现在只要1台机器就可以满足。

4.1 优化前后CPU利用率对比图和优化后负载情况

在这里插入图片描述

4.2 增大并发后CPU利用率和负载情况

在这里插入图片描述
从上图可知,当我们将并发增大至原先的三倍,CPU利用率甚至比原来的还要低,负载也比原先的低,说明我们的优化后的结果是符合我们的预期的查询第三方系统的次数从原先单台机器的每分钟8W多次变成了每分钟24W多次,平峰期我们日常需要维护90台机器可以直接缩减成30台,高峰期维护的300台机器可以直接缩减成100台,不仅每年可以直接为公司省去机器成本几十万,在机器的管理上也更加方便。

五.总结

在日常编码中,我们不仅要注重业务代码的实现,还需要考虑到系统的性能问题,要学会发现问题,并解决问题。对个人能力来说不仅是一个很大的提升,在一定程度上也能为公司带来效益。

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

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

相关文章

音频数字信号I2S一些知识理解

(1)I2S单向基本传输需要几根线传输音频信号? 3根线 LRCK SCLK(也叫BLK) DATA(单向) (2)如何理解I2S MASTER或者SLAVE的模式&#xff1f; codec的i2s作为slave mode,LRCK和SCLK来自于soc主控端,codec端自动检测MCLK和LRCK codec的i2s作为master mode,codec通过MCLK LRCLKDIV…

CSS-浮动

float (浮动) 作用&#xff1a;盒子的顶点是一样的&#xff0c;具备行内块的特征&#xff0c;能设置宽高 属性&#xff1a;float 属性值&#xff1a;left 浮动在网页左边 right 浮动在网页右边 .a{width: 100px;height: 100px;float:left;background-color: red;}.b…

drawio 网页版二次开发(1):源码下载和环境搭建

目录 一 说明 二 源码地址以及下载 三 开发环境搭建 1. 前端工程地址 2. 配置开发环境 &#xff08;1&#xff09;安装 node.js &#xff08;2&#xff09;安装 serve 服务器 3. 运行 四 最后 一 说明 应公司项目要求&#xff0c;需要对drawio进行二次开发&…

VUE 或 Js封装通用闭包循环滚动函数

1、vue3 闭包滚动函数的使用 js 调用也基本雷同 // 滚动Tab组件const scoreTabRef ref()// 滚动的选项const scrollOption ref({// 滚动的Dom元素scrollDom: null,// 滚动的时间间隔scrollInterval: 1500,// 滚动的距离scrollSep: 100,// 滚动历时时间scrollDuration: 10…

Microsoft Project使用简明教程

一.认识Microsoft Project Microsoft Project 是微软公司开发的项目管理软件&#xff0c;用于规划、协调和跟踪项目的进度、资源和预算&#xff0c;如下图所示&#xff0c;左边是任务的显示&#xff0c;右边是一个日程的显示图&#xff0c;最上方的长方形处在我们项目设定日程…

Python 3 中zip()函数的用法

1 创作灵感 我们在阅读代码的时候&#xff0c;经常会看到zip函数&#xff0c;有的时候还和循环在一起用&#xff0c;今天举几个例子测试一下该函数的用法 2.应用举例 &#xff08;1&#xff09;定义了两个列表一个是num,一个是letter (2)使用zip可以把num列表和letter列表中…

【高阶数据结构】图 -- 详解

一、图的基本概念 图 是由顶点集合及顶点间的关系组成的一种数据结构&#xff1a;G (V&#xff0c; E)。其中&#xff1a; 顶点集合 V {x | x属于某个数据对象集} 是有穷非空集合&#xff1b; E {(x,y) | x,y属于V} 或者 E {<x, y> | x,y属于V && Path(x, y…

pdf编辑软件,四款软件让你轻松玩转PDF编辑!

在信息爆炸的当今时代&#xff0c;PDF格式文档因其跨平台、不易被篡改的特性而深受大家喜爱。然而&#xff0c;如何高效地编辑PDF文档却成为许多人的难题。今天&#xff0c;我将为大家推荐四款实用的PDF编辑软件&#xff0c;让你轻松玩转PDF编辑&#xff0c;告别繁琐操作&#…

Springboot集成Mybatispuls操作mysql数据库-04

MyBatis-Plus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强而不做改变。它支持所有MyBatis原生的特性&#xff0c;因此引入MyBatis-Plus不会对现有的MyBatis构架产生任何影响。MyBatis-Plus旨在简化开发、提高效率&#xff0c;…

【机器学习与实现】线性回归分析

目录 一、相关和回归的概念&#xff08;一&#xff09;变量间的关系&#xff08;二&#xff09;Pearson&#xff08;皮尔逊&#xff09;相关系数 二、线性回归的概念和方程&#xff08;一&#xff09;回归分析概述&#xff08;二&#xff09;线性回归方程 三、线性回归模型的损…

3D Gaussian Splatting for Real-Time Radiance Field Rendering 论文阅读

如此热门的项目&#xff0c;网络上有很多大牛分析了这篇文章的做法&#xff0c;在这里简单记录一下个人粗浅的理解。 关于各种数学表达式的推导&#xff0c;论文和参考资料中都提供了较为详细的解读&#xff0c;本人能力有限&#xff0c;这一部分理解不够深刻&#xff0c;先不做…

【CSDN搜材料的小技巧】怎么快速查到高质量最新的内容

问题描述: 我最近搜CSDN已经搜累了&#xff0c;好多东西明显是有问题的&#xff0c;还有一堆人复制粘贴&#xff0c;从海量文章中提取出最新且高质量文章成了当务之急&#xff01; 解决方案: 我本来想写个爬虫按照文章的收藏或者点赞排序的&#xff0c;无意中看到了这篇文章…

多线程三种实现

多线程 线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 &#xff08;理解&#xff1a;应用软件中互相独立&#xff0c;可以同时运行的功能&#xff09; 进程 进程是程序的基本执行实体。&#xff08;理解&#…

在windows下安装wsl子系统

一、安装环境 windows规格 版本Windows 10企业版版本号22H2操作系统内部版本19045.4291 二、安装过程 2.1 以管理员身份打开PowerShell&#xff08;win X快捷键&#xff09;&#xff1b; 2.2 输入命令&#xff1a;wsl --list --online&#xff08;简写&#xff1a;wsl -l …

探索 Joomla! CMS:打造个性化网站的利器

上周我们的Hostease客户咨询建站服务。他想要用Joomla建站。Hostease提供免费安装Joomla CMS服务。这可以让客户搭建网站变得更加简单和高效。下面是针对Joomla建站的一些使用心得。 Joomla CMS是一款开放自由的软件&#xff0c;为用户提供了创建和维护网站的自由度。它经过全…

鸿蒙应用开发DevEco Studio工程目录模块介绍

面向开发者&#xff0c;HarmonyOS 推出了 DevEco Studio 和 Dev Device Tool 两款开发工具&#xff0c;前者目前迭代至 3.1 版本&#xff08;对外开放版本&#xff09;&#xff0c;用于开发 HarmonyOS 应用&#xff1b;后者用于开发智能设备 应用的工程主体结构如上图 在这里我…

编写一个C#程序,实现音乐文件的播放功能

一、作业要求 要求1&#xff1a; 1. 程序应能够读取MP3文件&#xff0c;并播放其中的音频。 2. 程序应能够处理可能出现的异常&#xff0c;如文件不存在、文件读取错误等。 3. 程序应具有良好的用户界面&#xff0c;方便用户进行操作。 4. 程序应具有良好的兼容性&#xf…

数据可视化训练第三天(富豪借钱问题可视化)

题目 一个穷人到富人那里去借钱&#xff0c;原以为富人不愿意&#xff0c;哪知富人一口答应了下来&#xff0c; 但提出了如下条件&#xff1a; 在30天中&#xff0c;富人第一天借给穷人1万元&#xff0c;第二天借给2万&#xff0c;以后每天所借的钱数都比上一天的多一万&…

C++数据结构——AVL树

前言&#xff1a;本篇文章将紧随二叉搜索树的节奏&#xff0c;分享一个新的数据结构——AVL树。 目录 一.AVL树概念 二.AVL树插入规则 三.AVL树实现 1.基本框架 2.插入 3.旋转 1&#xff09;左\右单旋 2&#xff09;左右/右左双旋 4.遍历 5.求树高度 6.判断平衡 7.…

仿真算法验证成功后,如何快速实现真机无缝切换?

Prometheus仿真优势 首先&#xff0c;我们先通过下面这个视频了解一下Prometheus仿真有哪些优势&#xff1a; 开源自主无人机平台重大更新&#xff01;Promethus仿真到真机无缝切换 Prometheus仿真最大的优势之一是采用了模块化设计&#xff0c;对每个操作节点进行了封装&…