一次Fegin CPU占用过高导致的事故
记录一下
一次应用事故分析、排查、处理
背景介绍
9号上午收到CPU告警,同时业务反馈依赖该服务的上游服务接口响应耗时太长
应用告警-CPU使用率 告警变更
【WARNING】项目XXX,集群qd-aliyun,分区bbbb-prod,应用customer,实例customer-6fb6448688-m47jz, POD实例CPU请求使用率 >= 90.000000% 当前值138.4971051199925%
发生时间:2024/10/09 11:17:33项目XXX,集群qd-aliyun,分区bbbb-prod,应用customer,实例customer-6fb6448688-28pvs, POD实例CPU请求使用率 >= 90.000000% 当前值157.7076205766934%告警已恢复
发生时间: 2024/10/09 11:06:33
恢复时间: 2024/10/09 12:24:33
服务访问量
单实例峰值QPS100左右
为啥要关注QPS,因为QPS100不应该消耗这么多CPU啊,而且请求、响应体都不大。


POD监控
POD配额
- CPU请求 2 Core CPU上限 3 Core
- 内存请求 7GiB 内存上限 9GiB



从图中可以看出
- CPU负载一直很高
- TCP链接及线程数从11点40开始陡峭上升
Arms
看下Trace监控发现,耗时主要是customer通过fegin调用外围接口导致的。

临时方案
临时处理方案:扩实例并增加CPU配置。
根因分析
此处略过排查三方接口跟开放平台网关的过程,此处的结论是:依赖的三方接口跟开放平台网关没有问题。
为啥会先排查三方接口跟开放平台网关是因为中Trace上来看是调用三方接口响应时间过长。
从Arms图看可以看出
- CPU耗时集中在fegin调用的Decoder、Encoder
- Decoder、Encoder耗时都集中在
- HttpMessageConverters#getDefaultConverters()=>
- WebMvcConfigurationSupport#addDefaultHttpMessageConverters=>
- …(具体调用链看下方摘要)
feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(Object[]) (14.37%, 1.43 minutes)
feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.reesolve(Object[], RequestTemplate, Map) (14.37%, 1.43minutes)
org.springframework.cloud.openfeign.support.SpringEndcoder.encode(Object, Type, RequestTemplate) (14.28%,1.42 minutes)
com.jiankunking.common.core.feign.FeignClientsConfig$$ambda$938.56729293.get0bject() (13.98%, 1.39 minutes
com.jiankunking.common.core.feign.FeignClientsConfig.lambda$feignEncoder$2() (13.98%, 1.39 minutees)
org.springframework.boot.autoconfigure.http.HttpmessaageConverters.<init>(HttpMessageConverter[]) (12.03%,1.19 minutes)
prg.springframework.boot.autoconfigure.http.Http.HttpMessageConverters.<init>(Collection) (12.03%, 119 minutes)
org.springframework.boot.autoconfigure.http.HttpmessaageConverters.<init>(boolean, Collection) (12.03%, 1.19 minutes)
prg.springframework.boot.autoconfigure.http.Http.HttpMessageConverters.getDefaultConverters()(12.02%, 1.19 minutes
org.springframework.boot.autoconfigure.http.HttpmessageConverters$1.defaultMessageConverters() (12.02%, 119 minutes)
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.getMessageConverters() (12.02%, 1.19 minutes)
org.springframework.web.servlet.config.annotation. WebMvcConfigurationSupport.addDefaultHttpMessageConverters(List) (12.02%, 1
org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.build() (5.93%, 0.59 minutes)
org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.configure(ObjectMapper)(5.91%, 0.59 minutes)
org.springframework.http.converter.json.Jackson2Objec:tMapperBuilder.registerWellKnownModulesIfAvailable(Map)(5.89%,0.58 min
org.springframework.util.ClassUtils.forName(String, CClassLoader)(5.84%, 0.58 minutes)
java.lang.Class.forName(String, boolean, Classloader) (5.83%, 0.58 minutes)
java.lang.Class.forName0(String, boolean, ClassLoader, Class) (5.83%, 0.58 minutes)
......
自定义Encoder、Decoder
Encoder
看下jiankunking.common.core.feign.FeignClientsConfig中的Encoder
public Encoder feignEncoder() {ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(new RMappingJackson2HttpMessageConverter());return new SpringEncoder(objectFactory);}public class RMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {public RMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {super(objectMapper);List<MediaType> mediaTypes = new ArrayList<>();mediaTypes.add(MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE));mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8"));setSupportedMediaTypes(mediaTypes);}RMappingJackson2HttpMessageConverter() {List<MediaType> mediaTypes = new ArrayList<>();mediaTypes.add(MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE));mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8"));setSupportedMediaTypes(mediaTypes);}}
Decoder
看下jiankunking.common.core.feign.FeignClientsConfig中的Decoder
public Decoder feignDecoder() {HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);return new ResponseEntityDecoder(new RSpringDecoder(objectFactory));}public ObjectMapper customObjectMapper() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.registerModule(new StringToDateModule());objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);return objectMapper;}
Google了一下:‘spring feign encode jackson cpu usage high’
=> https://segmentfault.com/a/1190000043037032
=> https://mp.weixin.qq.com/s/RuqltkN9VdVQ1K3GKuJ-Gw
=> https://meantobe.github.io/2019/12/21/ClassLoader/
源码分析
查看registerWellKnownModulesIfAvailable处的代码
@SuppressWarnings("unchecked")private void registerWellKnownModulesIfAvailable(Map<Object, Module> modulesToRegister) {try {Class<? extends Module> jdk8ModuleClass = (Class<? extends Module>)ClassUtils.forName("com.fasterxml.jackson.datatype.jdk8.Jdk8Module", this.moduleClassLoader);Module jdk8Module = BeanUtils.instantiateClass(jdk8ModuleClass);modulesToRegister.put(jdk8Module.getTypeId(), jdk8Module);}catch (ClassNotFoundException ex) {// jackson-datatype-jdk8 not available}try {Class<? extends Module> javaTimeModuleClass = (Class<? extends Module>)ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", this.moduleClassLoader);Module javaTimeModule = BeanUtils.instantiateClass(javaTimeModuleClass);modulesToRegister.put(javaTimeModule.getTypeId(), javaTimeModule);}catch (ClassNotFoundException ex) {// jackson-datatype-jsr310 not available}// Joda-Time present?if (ClassUtils.isPresent("org.joda.time.LocalDate", this.moduleClassLoader)) {try {Class<? extends Module> jodaModuleClass = (Class<? extends Module>)ClassUtils.forName("com.fasterxml.jackson.datatype.joda.JodaModule", this.moduleClassLoader);Module jodaModule = BeanUtils.instantiateClass(jodaModuleClass);modulesToRegister.put(jodaModule.getTypeId(), jodaModule);}catch (ClassNotFoundException ex) {// jackson-datatype-joda not available}}// Kotlin present?if (KotlinDetector.isKotlinPresent()) {try {Class<? extends Module> kotlinModuleClass = (Class<? extends Module>)ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", this.moduleClassLoader);Module kotlinModule = BeanUtils.instantiateClass(kotlinModuleClass);modulesToRegister.put(kotlinModule.getTypeId(), kotlinModule);}catch (ClassNotFoundException ex) {if (!kotlinWarningLogged) {kotlinWarningLogged = true;logger.warn("For Jackson Kotlin classes support please add " +"\"com.fasterxml.jackson.module:jackson-module-kotlin\" to the classpath");}}}}
可以看到其逻辑为若classpath中有JodaTime的LocalDate,则加载Jackson对应的JodaModule.LaunchedURLClassLoader.
为啥没有怀疑jdk8ModuleClass、javaTimeModuleClass这两个地方呢?因为common包中已经依赖了下面两个包
compile "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${v.jacksonDatatype}"compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${v.jacksonDatatype}"
那么解决方案就很清晰了
解决方案
避免ClassLoader反复加载
将这个依赖添加到工程中。加载一次后,再次调用可以通过findLoadedClass获得,减少加载类导致的资源消耗。
<dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-joda</artifactId><version>x.x.x</version>
</dependency>
避免HttpMessageConverters重复初始化
public Decoder feignDecoder() {HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(false, Collections.singletonList(jacksonConverter));return new ResponseEntityDecoder(new RSpringDecoder(objectFactory));}public Encoder feignEncoder() {HttpMessageConverter jacksonConverter = new RMappingJackson2HttpMessageConverter(customObjectMapper());ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(false, Collections.singletonList(jacksonConverter));return new SpringEncoder(objectFactory);}
总结
大家在自定义 Feign 的编解码器时,如果用到了 SpringEncoder / SpringDecoder,应避免 HttpMessageConverters 的重复初始化。如果不需要使用那些默认的 HttpMessageConverter,可以在初始化 HttpMessageConverters 时将第一个入参设置为 false,从而不初始化那些默认的 HttpMessageConverter。
相关文章:
一次Fegin CPU占用过高导致的事故
记录一下 一次应用事故分析、排查、处理 背景介绍 9号上午收到CPU告警,同时业务反馈依赖该服务的上游服务接口响应耗时太长 应用告警-CPU使用率 告警变更 【WARNING】项目XXX,集群qd-aliyun,分区bbbb-prod,应用customer,实例customer-6fb6448688-m47jz, POD实例CP…...
【Go初阶】两万字快速入门Go语言
初见golang语法 package mainimport "fmt"func main() {/* 简单的程序 万能的hello world */fmt.Println("Hello Go")} 第一行代码package main定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main…...
【React】使用 react hooks 需要遵守的原则
1)只能在顶层调用Hooks 这是指你不能在循环、条件语句或嵌套函数中调用Hooks。确保每次组件渲染时,Hooks的调用顺序保持一致。因此,你应该始终在React函数组件的最顶层调用Hooks。 React依赖于Hooks的调用顺序。如果这些调用在不同的渲染中顺…...
Python编程:创意爱心表白代码集
在寻找一种特别的方式来表达你的爱意吗?使用Python编程,你可以创造出独一无二的爱心图案,为你的表白增添一份特别的浪漫。这里为你精选了六种不同风格的爱心表白代码,让你的创意和情感通过代码展现出来。 话不多说,咱…...
腾讯IM SDK:TUIKit发送多张图片
一、问题描述 在使用腾讯IM DEMO(https://github.com/TencentCloud/chat-uikit-vue.git)时发现其只支持发送一张图片: 二、解决方案 // src\TUIKit\components\TUIChat\message-input-toolbar\image-upload\index.vue<inputref"inp…...
《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战
在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡(一台机器上只有一块GPU)还是单机多卡(一台机器上有多块GPU)的硬件配置上启动ChatGLM3-6B模型,其前置环境配置和项目文件是相同的。如果大家对配置过程还…...
Python 脚本来自动发送每日电子邮件报告
安装必要的库 我们将使用 smtplib 发送邮件,以及 email.mime 来创建电子邮件内容。另外,为了让脚本自动定时运行,可以使用操作系统的计划任务工具(如 Linux 的 cron 或 Windows 的 Task Scheduler)。 创建邮件内容 使…...
大语言模型与ChatGPT:深入探索与应用
文章目录 1. 前言2. 大语言模型的概述2.1 什么是大语言模型?2.2 Transformer架构的核心2.3 预训练与微调 3. ChatGPT的架构与技术背景3.1 GPT模型的演进3.2 ChatGPT的工作原理 4. ChatGPT的实际应用4.1 日常对话助手4.2 内容生成与写作4.3 编程辅助4.4 教育与学习辅…...
【从零开始的LeetCode-算法】3164.优质数对的总数 II
给你两个整数数组 nums1 和 nums2,长度分别为 n 和 m。同时给你一个正整数 k。 如果 nums1[i] 可以被 nums2[j] * k 整除,则称数对 (i, j) 为 优质数对(0 < i < n - 1, 0 < j < m - 1)。 返回 优质数对 的总数。 示…...
FastDFS VS MinIO:文件存储与对象存储的抉择(包含SpringBoot集成FastDFS范例)
FastDFS vs MinIO:文件存储与对象存储的抉择(包含SpringBoot集成FastDFS范例) 我坐在窗边,随着飞机穿过云层,在云层之上滑翔。可以清晰的看到飞机在天空留下的痕迹,不知道那是蔚蓝中的纯白,还是…...
【Redis】缓存预热、雪崩、击穿、穿透、过期删除策略、内存淘汰策略
Redis常见问题总结: Redis常见问题总结Redis缓存预热Redis缓存雪崩Redis缓存击穿Redis缓存穿透 Redis 中 key 的过期删除策略数据删除策略 Redis内存淘汰策略一、Redis对过期数据的处理(一)相关配置(二)内存淘汰流程&a…...
【LeetCode】每日一题 2024_10_15 三角形的最大高度(枚举、模拟)
前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动! 题目:三角形的最大高度 代码与解题思路 久违的简单题 这道题读完题目其实不难想到有两条路可以走: 1、题目很明显只有两种情况,枚举是第一个球是红球还是蓝球这两种情…...
2024版最新网络安全工程师入门教程(非常详细)从零基础入门到精通,看完这一篇就够了
前言 想要成为网络安全工程师,却苦于没有方向,不知道从何学起的话,下面这篇 网络安全入门 教程可以帮你实现自己的网络安全工程师梦想,如果想学,可以继续看下去,文章有点长,希望你可以耐心看到…...
vue中关于router.beforeEach()的用法
router.beforeEach()是Vue.js中的路由守卫,用于在路由跳转前进行校验、取消、重定向等操作。 基本使用: const router new VueRouter({ ... })router.beforeEach((to, from, next) > {// ... }) to: 即将要进入的目标路由对象 from: 当前导航正要…...
C++模板初阶,只需稍微学习;直接起飞;泛型编程
🤓泛型编程 假设像以前交换两个函数需要,函数写很多个或者要重载很多个;那么有什么办法实现一个通用的函数呢? void Swap(int& x, int& y) {int tmp x;x y;y tmp; } void Swap(double& x, double& y) {doubl…...
【数据结构 | 红黑树】红黑树的性质和插入结点时的调整
文章目录 红黑树红黑树插入时的调整?1. 插入结点是根结点2. 插入结点的叔叔是红色3. 插入结点的叔叔是黑色LL 型RR型LR型RL型 红黑树 前提:二叉搜索树(左 < 根 < 右)—— 左根右根和**叶子(NULL)**都…...
mysql学习教程,从入门到精通,SQL导入数据(44)
1.SQL 导出数据 以下是一个关于如何使用 SQL 导出数据的示例。这个示例将涵盖从一个关系数据库管理系统(如 MySQL)中导出数据到 CSV 文件的基本步骤。 1.1、前提条件 你已经安装并配置好了 MySQL 数据库。你有访问数据库的权限。你知道要导出的表名。…...
【SpringAI】(二)让你的Java程序接入大模型——适合Java宝宝的大模型应用开发
开始之前,如果你对大模型完全没了解过,建议阅读之前的大模型入门文章: 【SpringAI】(一)从实际场景入门大模型——适合Java宝宝的大模型应用开发 那么今天就开始写一个基于Spring AI程序的HelloWord!将大模型接入到咱…...
音频剪辑在线工具 —— 让声音更精彩
你是否曾梦想过拥有自己的声音创作空间,却苦于复杂的音频编辑软件?接下来,让我们一同揭开这些音频剪辑在线工具的神秘面纱,看看它们如何帮助你实现从录音到发布的无缝衔接。 1.福昕音频剪辑 链接直达>>https://www.foxits…...
http短连接和长连接
参考短连接和长连接 短连接:客户端向服务器每进行一次Http操作,都需建立一次连接,任务完成后,断开连接;长连接:建立长连接后,传输数据的连接将不会中断,客户端每次访问服务器时都会…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
