美团一面,你碰到过CPU 100%的情况吗?你是怎么处理的?

本文主要分为三部分

  1. 分析一下CPU 100%的常见原因

  2. CPU 100%如何排查

  3. 回答这个问题的一个参考答案

CPU被打满的常见原因

1. 死循环

在实际工作中,可能每个开发都写过死循环的代码。

死循环有两种:

  1. 在 while、for、forEach 循环中的死循环。

  2. 无限递归。

这两种情况,程序会不停地运行,使用寄存器保存循环次数或者递归深度,一直占用 cpu,导致 cpu 使用率飙升。

在使用 JDK1.7 时,还有些死循环比如多线程的环境下,往 HashMap 中 put 数据,可能会导致链表出现死循环

就会导致cpu不断飙高。

2.大量GC

我之前参与过餐饮相关的业务系统开发,当时我所在的团队是菜品的下游业务。

当时菜品系统有菜品的更新,会发kafka消息,我们系统订阅该topic,就能获取到最近更新的菜品数据。

同步菜品数据的功能,上线了一年多的时候,没有出现过什么问题。

但在某一天下午,我们收到了大量 CPU100% 的报警邮件。

追查原因之后发现,菜品系统出现了 bug,我们每次获取到的都是全量的菜品数据,并非增量的数据。

一次性获取的数据太多。

菜品修改还是比较频繁的,也就是说我们系统,会频繁地读取和解析大量的数据,导致 CPU 不断飙升。

其根本原因是频繁的full gc

3. 大量计算密集型任务

有时候,我们的业务系统需要实时计算数据,比如:电商系统中需要实时计算优惠后的最终价格。

或者需要在代码中,从一堆数据中,统计汇总出我们所需要的数据。

如果这个实时计算或者实时统计的场景,是一个非常耗时的操作,并且该场景的请求并发量还不小,就可能会导致 cpu 飙高。

因为实时计算需要消耗 cpu 资源,如果一直计算,就会一直消耗 cpu 资源。

4. 死锁

为了防止并发场景中,多个线程修改公共资源,导致的数据异常问题,很多时候我们会在代码中使用synchronized或者Lock加锁。

这样多个线程进入临界方法或者代码段时,需要竞争某个对象或者类的锁,只有抢到相应的锁,才能访问临界资源。其他的线程,则需要等待,拥有锁的线程释放锁,下一次可以继续竞争那把锁。

有些业务场景中,某段代码需要线程获取多把锁,才能完成业务逻辑。

但由于代码的 bug,或者释放锁的顺序不正确,可能会引起死锁的问题。

例如:

"pool-4-thread-1" prio=10 tid=0x00007f27bc11a000 nid=0x2ae9 waiting on condition [0x00007f2768ef9000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x0000000090e1d048> (a java.util.concurrent.locks.ReentrantLock$FairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)

比如线程 a 拥有锁 c,需要获取锁 d,才能完成业务逻辑。

而刚好此时线程 b 拥有锁 d,需要获取锁 c,才能完成业务逻辑。

线程 a 等待线程 b 释放锁,而线程 b 等待线程 a 释放锁,两个线程都持有对方需要的锁,无法主动释放,就会出现死锁问题。

死锁会导致 CPU 使用率飙升。

CPU被打满如何排查

1. 使用系统工具和JDK自带的jstack工具

第一步:使用top命令找出占用CPU最高的Java进程

首先,使用top命令确认是不是Java进程是罪魁祸首。Java进程要么是个后台任务,要么是个jar包,比如一个Spring Boot服务。

图片

假设发现占用CPU 99.7%的线程是Java进程,进程PID为13731。

第二步:找到占用CPU最高的线程

接下来,还是用top命令,只不过加一个参数-Hp,就是下面这样:

top -Hp 13731

H参数表示要显示线程级别的信息,p则表示指定的pid,也就是进程ID。执行之后,这个Java进程中占用线程占用CPU的情况就列出来了。假设占用CPU最高的那个线程PID为13756。

图片

第三步:保存线程堆栈信息

这就要用到JDK默认提供的一个工具——jstack。jstack用于生成Java进程的线程快照(thread dump)。线程快照是一个关于Java进程中所有线程当前状态的快照,包括每个线程的堆栈信息。通过分析线程快照,可以了解Java进程中各个线程的运行状态、锁信息等。

我们用jstack的目的是将那个占用CPU最高的线程的堆栈信息搞下来,然后进一步分析。使用命令jstack pid > out.log将某个进程的堆栈信息输出到out.log文件中。

jstack 13731 > thread_stack.log
第四步:在线程栈中查找罪魁祸首的线程

将13756转换为16进制,可以用在线进制转换工具直接转换,比如这个。转换结果为0x35bc。

然后在线程栈中,也就是上一步保存的那个thread_stack.log文件,查找这个16进制的线程ID(0x35bc)。

这样,我们就能看到需要的线程名称、线程状态,哪个方法的哪一行代码消耗了最多的CPU都很清楚了。

图片

2. 使用Arthas探测工具

Arthas是阿里开源的一款线上监控诊断产品,通过全局视角实时查看应用load、内存、GC、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

安装Arthas

要使用Arthas,你需要先把它安装到你的目标服务器上。

  1. 下载jar包:

curl -O https://arthas.aliyun.com/arthas-boot.jar
  1. 启动Arthas服务:

java -jar arthas-boot.jar

启动之后,会列出当前这台服务器上的所有Java进程,选择你要排查的那个服务即可。出现arthas@之后表示已经启动,并成功attach到目标进程上。

图片

可以输入命令dashboard看一下实时面板,默认5秒刷新一次,在这个面板上能够看到线程、内存堆栈、GC和Runtime的基本信息。如果你用过VisualVM的话,操作界面与之类似。

找到占用CPU最高的线程

执行thread命令,这个命令会显示所有线程的信息,并且把CPU使用率高的线程排在前面。

这样,一眼就看出来了,第一个线程的CPU使用率高达99%。

图片

查看堆栈信息

使用thread ID获取堆栈信息,其实就是jstack pid相同的作用。通过前一步看到这个线程的ID是18,然后执行:

thread 18

图片

直接就看出来了出现问题的位置,比如TestController.java文件的high方法的第23行。然后可以进入代码查看具体问题。

参考答案

面试官:“你碰到过CPU 100%的情况吗?你是怎么处理的?”

生产环境如果cpu已经被打满了,不要一上来就说什么top,jstack,记住,真实的生产环境如果CPU已经要被打爆了的话

第一选择肯定是重启,并且如果你近段时间有发布的话,还要考虑是否可以回滚,保障生产环境的稳定性是最重要的

还有就是,如果CPU已经被打爆了,不管arthas还是jstack大概率也是执行不了的,jvm无法响应

我:“之前碰到过CPU被打满的情况,我们线上第一时间做了重启,在重启的过程中,我们去查了服务在那段时间的日志、链路、指标,没有发现特殊的异常。”

有时候CPU100&会伴随非常明显的日志、链路或者指标异常。例如:通过gc的指标发现,发现full gc的次数激增,或者发现内存的使用率很高,这个时候大概率是因为gc导致的cpu 100%。这个时候就不要再去jstack了,应该第一次时间查看堆dump文件,确认是哪个对象占用了大量内存

我:“当服务重启完成后,我们开始排查具体的原因。我们通过定期执行top命令,发现java进程的CPU的使用率确实在慢慢增加”

我:“接着,我通过top -Hp以及jstack命令拿到了应用里cpu使用率最高的那个线程的堆栈,通过分析堆栈最终定位到了具体的代码,是因为代码触发了一个临界值,进入了死循环”

下面这段代码是我实际工作碰到一个导致线上CPU 100%的代码:

public ShortUrlRandomSeed getAvailableSeed()  {MachineInfo machineInfo = UrlConverUtil.getMachineInfo();for (; ; ) {// 获取种子ShortUrlRandomSeed seed = shortUrlSeedService.getAvailableSeed(machineInfo);if (seed != null) {int influenceNum = shortUrlSeedService.updateSeedStatus(seed.getId());if (influenceNum > 0) {return seed;}}}
}

这段代码的作用是为了获取一个种子用于短链的生成,在项目上线之初预生成了接近21w个种子,这个代码在线上跑了3年了一直没有问题,直到去年的某一天,21w个种子用光了,seed一直为null,开始死循环,最终导致CPU 100%

还是我之前在文章中提到过的,记住一个原则:如果说面试有必杀技,那么一定是:真实的经历+具体的技术细节

美团一面,你碰到过CPU 100%的情况吗?你是怎么处理的?

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

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

相关文章

centos安装minio文件系统服务器(踩坑版)

centos安装minio文件系统服务器&#xff08;踩坑版&#xff09; 引安装1. 下载2. 启动3. 创建access keys4. 创建buckets 坑 引 本来安装挺简单的&#xff0c;网上的教程一大堆&#xff0c;有些写的也挺详细的。不过自己还是踩到坑了&#xff0c;耽误了个把小时&#xff0c;特…

【分库】分库的核心原则

目录 分库的核心原则 前言 分区透明性与一致性保证 弹性伸缩性与容错性设计 数据安全与访问控制机制 分库的核心原则 前言 在设计和实施分库策略时&#xff0c;遵循一系列核心原则是至关重要的&#xff0c;以确保系统不仅能够在当前规模下高效运行&#xff0c;还能够随着…

单目测距 单目相机测距 图片像素坐标转实际坐标的一种转换方案

需要相机位置固定 原图 红色的点是我们标注的像素点&#xff0c;这些红色的点我们知道它的像素坐标&#xff0c;以及以右下角相机位置为原点的x y 实际坐标数值 通过转换&#xff0c;可以得到整个图片内部其余像素点的实际坐标&#xff0c; 这些红色的点是通过转换关系生成的&…

Python | Leetcode Python题解之第231题2的幂

题目&#xff1a; 题解&#xff1a; class Solution:BIG 2**30def isPowerOfTwo(self, n: int) -> bool:return n > 0 and Solution.BIG % n 0

el-table 动态添加删除 -- 鼠标移入移出显隐删除图标

<el-table class"list-box" :data"replaceDataList" border><el-table-column label"原始值" prop"original" align"center" ><template slot-scope"scope"><div mouseenter"showClick…

JavaWeb(四:Ajax与Json)

一、Ajax 1.定义 Ajax&#xff08;Asynchronous JavaScript And XML&#xff09;&#xff1a;异步的 JavaScript 和 XML AJAX 不是新的编程语言&#xff0c;指的是⼀种交互方式&#xff1a;异步加载。 客户端和服务器的数据交互更新在局部页面的技术&#xff0c;不需要刷新…

Openerstry + lua + redis根据请求参数实现动态路由转发

文章目录 一、需求分析二、准备1、软件安装2、redis-lua封装优化 三、实现1、nginx.conf2、dynamic.lua注意 3、准备两个应用4、访问nginx 一、需求分析 根据用户访问url的参数&#xff0c;将请求转发到对应指定IP的服务器上。 二、准备 1、软件安装 安装openrestyredis&am…

Database数据库 vs Data Warehouse数据仓库 vs Data Mart数据集市 vs Data Lake数据湖

1.DATABASE 数据库 数据库是一个结构化的数据集合&#xff0c;用于存储、管理和检索数据。数据库设计用于支持事务处理&#xff08;OLTP&#xff0c;Online Transaction Processing&#xff09;和日常操作。 数据库通常由数据库管理系统&#xff08;DBMS&#xff09;控制&…

golang json反序列化科学计数法的坑

问题背景 func CheckSign(c *gin.Context, signKey string, singExpire int) (string, error) {r : c.Requestvar formParams map[string]interface{}if c.Request.Body ! nil {bodyBytes, _ : io.ReadAll(c.Request.Body)defer c.Request.Body.Close()if len(bodyBytes) >…

PostgreSQL(二十二)缓冲区管理器

目录 一、缓冲区概述 1、缓冲区结构 2、buffer_tag结构 3、Backend进程读取操作 4、写脏块 二、缓冲区管理器结构 1、第一层&#xff1a;Buffer Table layer&#xff08;缓冲区表层&#xff09; 2、第二层&#xff1a;Buffer Descriptor Layer&#xff08;缓冲区描述层…

秋招Java后端开发冲刺——Mybatis使用总结

一、基本知识 1. 介绍 MyBatis 是 Apache 的一个开源项目&#xff0c;它封装了 JDBC&#xff0c;使开发者只需要关注 SQL 语句本身&#xff0c;而不需要再进行繁琐的 JDBC 编码。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java POJO&#xff08;Plain …

Bertopic环境安装与文本主题聚类

文章目录 1.环境配置(一)安装:anaconda1. 理解:为什么需要anaconda2. 下载anaconda3. 启动anaconda(二)安装:python环境(三)安装:依赖包hdbscan的安装问题解决方案1. 安装build-tools-for-visual-studio2. 安装hdbscan(四)安装transformers、BERTopic等重要依赖包2…

零信任的架构结合模块化沙箱,实现一机两用的解决方案

零信任沙箱是深信达提出的一种数据安全解决方案&#xff0c;它将零信任原则与SDC沙箱技术的优势相结合。零信任原则是一种安全概念&#xff0c;核心思想是“永不信任&#xff0c;总是验证”。它要求对每一个访问请求都进行严格的身份验证和授权&#xff0c;无论请求来源于内部还…

从RL的专业角度解惑 instruct GPT的目标函数

作为早期chatGPT背后的核心技术&#xff0c;instruct GPT一直被业界奉为里程碑式的著作。但是这篇论文关于RL的部分确写的非常模糊&#xff0c;几乎一笔带过。当我们去仔细审查它的目标函数的时候&#xff0c;心中不免有诸多困惑。特别是作者提到用PPO来做强化学习&#xff0c;…

【微信小程序知识点】手机号验证组件

手机验证组件&#xff0c;用于帮助开发者向用户发起手机号申请&#xff0c;必须经过用户同意后&#xff0c;才能获得由平台验证后的手机号&#xff0c;进而为用户提供相应的服务。 手机号验证组件分为两种&#xff1a;手机号快速验证组件以及手机号实时验证组件。 1.手机号快速…

【微信小程序知识点】自定义构建npm

在实际开发中&#xff0c;随着项目的功能越来越多&#xff0c;项目越来越复杂&#xff0c;文件目录也变得很繁琐&#xff0c;为了方便进行项目的开发&#xff0c;开发人员通常会对目录结构进行优化调整&#xff0c;例如&#xff1a;将小程序源码放到miniprogram目录下。 &…

Portainer工具

Portainer是一款免费、开源的Docker的图形化管理工具&#xff0c;其能够提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作&#xff08;包括上传下载镜像&#xff0c;创建容器等操作&#xff09;、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和…

Macos 远程登录 Ubuntu22.04 桌面

这里使用的桌面程序为 xfce, 而 gnome 桌面则测试失败。 1,安装 在ubuntu上&#xff0c;安装 vnc server与桌面程序xfce sudo apt install xfce4 xfce4-goodies tightvncserver 2&#xff0c;第一次启动和配置 $ tightvncserver :1 设置密码。 然后修改配置&#xff1a…

JVM 之对象的结构与创建

1.对象的创建 1.1类加载 当Java 虚拟机遇到一条字节码 new 指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到 一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那 必须先执行相应的类加载过…

C# .net6使用Hangfire

首先我们先来了解什么是Hangfire&#xff1f; Hangfire 是一个用于 .NET 的任务调度库&#xff0c;允许你在后台运行任务&#xff0c;而不需要依赖外部的任务队列服务或复杂的基础设施。它简化了后台任务的创建、调度和管理过程&#xff0c;使得在 .NET 应用程序中处理长期运行…