「性能指标」CPU飙高排查实战

上篇提到了什么是 CPU 以及如何计算的。接下来主要说说实际工作中遇到 CPU 飙高如何去排查呢?

往期回顾:

聊聊性能指标 CPU 利用率如何计算的?

问题发现

前段时间我们新上线了一个应用,由于流量一直不大,集群的每秒查询率(QPS)大约只有 5。接口的响应时间大约在 30 毫秒左右。

最近我们接入了新的业务,业务方提供的数据显示,日常的 QPS 预计可以达到 2000,而在大促期间峰值 QPS 可能会达到 1 万。

为了评估系统的性能水平,我们进行了一次压力测试。测试在预发布环境进行。在压力测试过程中,我们观察到当单台服务器的 QPS 达到约 200 时,接口的响应时间没有明显变化,但是 CPU 利用率迅速上升,直到达到极限。

image.png

压力测试结束后,CPU 利用率立即下降。

随后我们开始排查是什么原因导致了 CPU 的突然飙升。

排查与解决

在压力测试期间,登录到机器后,我们开始排查问题。

本案例的排查过程使用了阿里开源的 Arthas 工具。如果没有 Arthas,也可以使用 JDK 自带的命令进行排查。

在开始具体排查之前,可以先查看 CPU 的使用情况。最简单的方法是使用top命令直接查看:

top - 10:32:38 up 11 days, 17:56,  0 users,  load average: 0.84, 0.33, 0.18
Tasks:  23 total,   1 running,  21 sleeping,   0 stopped,   1 zombie
%Cpu(s): 95.5 us,  2.2 sy,  0.0 ni, 76.3 id,  0.0 wa,  0.0 hi,  0.0 si,  6.1 st
KiB Mem :  8388608 total,  4378768 free,  3605932 used,   403908 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  4378768 avail MemPID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND3480 admin     20   0 7565624   2.9g   8976 S  241.2 35.8 649:07.23 java1502 root      20   0  401768  40228   9084 S   1.0  0.5  39:21.65 ilogtail181964 root      20   0 3756408 104392   8464 S   0.7  1.2   0:39.38 java496 root      20   0 2344224  14108   4396 S   0.3  0.2  52:22.25 staragentd1400 admin     20   0 2176952 229156   5940 S   0.3  2.7  31:13.13 java235514 root      39  19 2204632  15704   6844 S   0.3  0.2  55:34.43 argusagent236226 root      20   0   55836   9304   6888 S   0.3  0.1  12:01.91 systemd-journ

可以清楚的看到,进程 ID 为 3480 的 Java 进程占用了较高的 CPU,可以初步推断是应用代码执行过程中消耗了大量的 CPU 资源。接下来,我们需要进一步排查是哪个线程、哪段代码导致了这种情况。

首先,我们需要下载 Arthas 工具:

curl -L https://arthas.aliyun.com/install.sh | sh

启动:

./as.sh

使用 Arthas 命令 "thread -n 3 -i 1000"查看当前"最忙"(耗 CPU)的三个线程:

image.png

通过上述堆栈信息可以看出,占用 CPU 资源的线程主要是在 JDBC 底层的 TCP 套接字读取上阻塞。经过连续执行多次分析,发现很多线程都在这个地方卡住。

进一步分析调用链后发现,这个问题源自于我代码中的数据库 insert 操作,其中使用了 TDDL 来创建 sequence。在 sequence 的创建过程中,需要与数据库进行交互。

根据对 TDDL 的了解,它每次从数据库查询 sequence 序列时,默认会获取 1000 条,并在本地进行缓存,直到使用完这 1000 条序列之后才会再次从数据库获取下一个 1000 条序列。

考虑到我们的压测 QPS 仅约为 300 左右,不应该导致如此频繁的数据库交互。然而,通过多次使用 Arthas 进行查看,发现大部分的 CPU 资源都耗费在这里。

因此,我们开始排查代码问题。最终,发现了一个非常简单的问题,即我们的 sequence 创建和使用存在着明显的缺陷:

public Long insert(T dataObject) {if (dataObject.getId() == null) {Long id = next();dataObject.setId(id);}if (sqlSession.insert(getNamespace() + ".insert", dataObject) > 0) {return dataObject.getId();} else {return null;}
}public Sequence sequence() {return SequenceBuilder.create().name(getTableName()).sequenceDao(sequenceDao).build();
}/*** 获取下一个主键ID** @return*/
protected Long next() {try {return sequence().nextValue();} catch (SequenceException e) {throw new RuntimeException(e);}
}

因此,我们每次执行 insert 语句时都重新构建了一个新的 sequence 对象,这导致本地缓存被清空。因此,每次都需要从数据库重新获取 1000 条 sequence,但实际上只使用了一条,下次又会重复这个过程。

为了解决这个问题,我们调整了代码,在应用启动时初始化了一个 Sequence 实例。这样,在后续获取 sequence 时,不会每次都与数据库交互。而是首先检查本地缓存,只有在本地缓存用尽时才会再次与数据库交互,获取新的 sequence。

public abstract class BaseMybatisDAO implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {sequence = SequenceBuilder.create().name(getTableName()).sequenceDao(sequenceDao).build();}}

通过实现 InitializingBean 接口,并重写其中的 afterPropertiesSet()方法,在该方法中进行 Sequence 的初始化。

完成以上代码修改后,提交并进行验证。根据监控数据显示,优化后数据库的读取响应时间(RT)明显下降。

image.png
sequence 的写操作 QPS 也有明显下降:

image.png

于是我们开始了新的一轮压测,但是发现 CPU 的使用率仍然很高,压测的 QPS 还是无法达到预期。因此,我们决定重新使用 Arthas 工具查看线程的情况。

image.png

发现了一个 CPU 消耗较高的线程堆栈,主要是因为我们在使用一个联调工具时,该工具预发布状态下默认开启了 TDDL 的日志采集(尽管官方文档中描述预发布状态下默认不会开启 TDDL 采集,但实际上确实会进行采集)。

在该工具打印日志时,会进行数据脱敏操作,脱敏框架使用了 Google 的 re2j 进行正则表达式匹配。

由于我的操作涉及到大量的 TDDL 操作,而默认情况下会采集大量 TDDL 日志并进行脱敏处理,这导致了较高的 CPU 消耗。

因此,通过在预发布环境中关闭对 TDDL 的日志采集,可以有效解决这个问题。

总结

这篇总结回顾了一次线上 CPU 飙高问题的排查过程,虽然问题最终解决起来并不复杂,但排查过程中却有其独特的教育意义。

之前经验丰富的我按照惯例进行了排查,初始阶段并未发现明显问题,错误地将数据库操作增加归因于流量上升所致的正常情况。

通过多方查证(例如使用 arthas 查看序列获取情况,以及通过数据库查询最新插入数据的主键 ID 等方法),最终确认问题出在 TDDL 的序列初始化机制上。

解决了这个问题后,本以为问题彻底解决,却又遭遇到 DP 采集 TDDL 日志导致 CPU 飙高的情况,最终再次解决问题后系统性能有了显著提升。

因此,这个经历再次验证了“事出反常必有妖”,排查问题确实需要有耐心和系统性。

如有问题,欢迎微信搜索【码上遇见你】。

好了,本章节到此告一段落。希望对你有所帮助,祝学习顺利。

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

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

相关文章

力扣 单链表元素删除解析及高频面试题

目录 删除元素的万能方法 构造虚拟头结点来应对删除链表头结点的情况 一、203.移除链表元素 题目 题解 二、19.删除链表中倒数第K个节点 题目 题解 三、 83.删除某个升序链表中的重复元素,使重复的元素都只出现一次 题目 题解 82.删除某个升序链表中的…

2023年第十四届蓝桥杯JavaB组省赛真题及全部解析(下)

承接上文:2023年第十四届蓝桥杯JavaB组省赛真题及全部解析(下)。 目录 七、试题 G:买二赠一 八、试题 H:合并石子 九、试题 I:最大开支 十、试题 J:魔法阵 题目来自:蓝桥杯官网…

【星海随笔】vue+vite

开头问一个问题&#xff0c;我发现有的人粉丝是点赞数的好几倍&#xff0c;可能和必须关注他才能阅读他的文章有关。 所以问一下怎么设置为关注才能查看该文章。 screen -ls #查看 id 列表 screen -S <session_name> # 创建一个会话 screen -R <session_id> # 根据…

iconfont-阿里巴巴矢量图标库 在vue项目使用记录

官网地址&#xff1a;https://www.iconfont.cn/manage/index?manage_typemyprojects&projectId4539761 第一步&#xff1a; 下载资源 ->解压到项目文件夹 第二步 在项目中main.ts 或者main.js 引入资源 import //assets/iconfont/font/iconfont.js; import //assets…

IBM Spectrum LSF RTM,针对 IBM Spectrum LSF 环境的高级报告、跟踪和监控工具

亮点 为 IBM Spectrum LSF 环境提供性能监控和报告 监控 FlexNet Publisher 和 Reprisebased 许可证的使用&#xff0c;提供详细和总结性报告 通过多个级别&#xff08;包括应用程序和组织&#xff09;的报告来监控共享存储的利用率 提供强大的生产力工具&#xff0c;包括操…

JVM专题五:类加载器与双亲委派机制

通过上一篇Java的类加载机制相信大家已经搞明白了整个类加载从触发时机&#xff0c;接着我们就来看下类加载器&#xff0c;因为类加载机制是有加载器实现的。 类加载器的分类 启动类加载器 Bootstrap ClassLoader 是 Java 虚拟机&#xff08;JVM&#xff09;的一部分&#x…

斜光测距的原理及python实现

1.前言 最近做了一个基于opencv的斜光测距的小项目&#xff0c;东西不多&#xff0c;但是很有意思&#xff0c;值得拿出来学一学。项目里面需要比较精确的定位功能&#xff0c;将前人matlab代码移植到python上&#xff0c;并且做了一些优化&#xff0c;简化逻辑(毕竟我是专业的…

iOS 真机打包,证书报错No signing certificate “iOS Distribution” found

之前将APP从旧账号转移到了新账号&#xff0c;在新账号打包的时候遇到的证书问题。 因为新账号还没有导出“本地签名证书”&#xff0c;也还没有创建新的“发布证书”。当我创建好这两者之后&#xff0c;在xcode打包的时候就报错了。 报错信息&#xff1a; No signing certifi…

字节码增强技术:ASM与Byte Buddy详解

在Java的世界中&#xff0c;字节码增强技术是一种强大的工具&#xff0c;它允许开发者在运行时修改或生成Java类的字节码。这种技术在AOP&#xff08;面向切面编程&#xff09;、框架开发、性能监控等方面有着广泛的应用。本文将详细介绍两种流行的字节码操作库&#xff1a;ASM…

我教会了我妈搭建自己的 AI 聊天机器人...

在这个人工智能爆发的年代,ChatGPT、Claude、Kimi、文心一言等 AI 大模型产品火遍全网,仿佛一夜之间,人人都在谈论 AI。 作为普通人的我们,难道就只能看着程序员们尽情玩耍,自己却无法参与其中吗?NO! 鉴于最近自己社群学员和粉丝的要求&#xff0c;一进来大家无论是不是小白…

Linux防火墙【SNAT,DNAT】

NAT: 支持PREROUTING&#xff0c;INPUT&#xff0c;OUTPUT&#xff0c;POSTROUTING四个链 请求报文&#xff1a;修改源/目标IP&#xff0c; 响应报文&#xff1a;修改源/目标IP&#xff0c;根据跟踪机制自动实现 NAT的实现分为下面类型&#xff1a; SNAT&#xff1a;source…

SpringBoot实现文件下载限速

SpringBoot实现文件下载限速 在SpringBoot项目中&#xff0c;实现文件下载的限速功能可以有效控制服务器带宽的占用&#xff0c;并防止单个用户消耗过多的资源。本文将通过具体的代码示例和详细的流程解释&#xff0c;介绍如何在SpringBoot项目中实现文件下载的限速功能。 前…

如何实现数字人系统私有化部署?数字人源码部署教程简易版来了!

当前&#xff0c;数字人行业的市场前景和应用潜力不断显现&#xff0c;不少创业者都想要通过学习数字人源码部署教程来搭建属于自己的数字人系统&#xff0c;以此获得进军数字人行业的入场券。而事实上&#xff0c;该想法本身当然是固然值得鼓励的&#xff0c;但就目前的实践情…

用Python写一个ai agent采集,分析,预测跨境选品策略

为了实现一个AI代理&#xff0c;用于采集、分析和预测跨境选品策略&#xff0c;我们可以使用Python的一些库&#xff0c;如pandas、numpy、sklearn和requests。以下是一个简化的跨境选品策略AI代理的示例。 首先&#xff0c;确保安装了所需的库&#xff1a; bash pip instal…

基于改进天鹰优化算法(IAO)优化RBF神经网络数据回归预测 (IAO-RBF)的数据回归预测(多输入多输出)

改进天鹰优化算法(IAO)见&#xff1a;【智能优化算法】改进的AO算法(IAO)-CSDN博客 代码原理 基于改进天鹰优化算法&#xff08;IAO&#xff09;优化RBF神经网络数据回归预测&#xff08;IAO-RBF&#xff09;的多输入多输出&#xff08;MIMO&#xff09;数据回归预测&#xf…

视频去水印软件?在线去除视频水印工具网站?

视频去水印软件哪个好&#xff1f;在数字时代&#xff0c;视频内容的传播变得日益普遍&#xff0c;然而&#xff0c;许多视频带有水印&#xff0c;影响了观看体验&#xff0c;如果有这些图案我们需要找方法把这些图案从视频上去掉。今天我们就来看一下视频去水印的超级简单的方…

添加阈值滞后以实现平滑的欠压/过压锁定

电阻分压器将高压衰减到低压电路可以承受的水平&#xff0c;而不会过驱动或损坏。在电源路径控制电路中&#xff0c;电阻分压器有助于设置电源欠压和过压锁定阈值。这种电源电压鉴定电路存在于汽车系统、电池供电的便携式仪器以及数据处理和通信板中。 欠压锁定 (UVLO) 可防止…

Java发送post或者get请求时如何信任所有证书

1.使用HttpURLConnection发送请求 private static void trustAllCertificates(HttpURLConnection con) throws NoSuchAlgorithmException, KeyManagementException {((HttpsURLConnection) con).setHostnameVerifier(new HostnameVerifier() {public boolean verify(String ho…

JWT(Json web token)认证详解

JSON Web Tokens - jwt.io官方地址 JWT&#xff08;Json web token&#xff09;认证详解 - 整合侠 - 博客园 (cnblogs.com) 案例jwt使用技巧https://m.jb51.net/article/186707.htm

算法刷题记录 二十二【替换数字】

前言 字符串篇&#xff0c;继续。 记录 二十二【替换数字】&#xff08;非力扣网题目&#xff09; 一、题目阅读 给定一个字符串 s&#xff0c;它包含小写字母和数字字符&#xff0c;请编写一个函数&#xff0c;将字符串中的字母字符保持不变&#xff0c;而将每个数字字符替换…