记一次线上jVM调优

news2024/11/26 4:52:54

文章目录

  • 问题描述
  • 问题分析
  • 尝试优化业务代码
  • 优化方案
  • 修改后代码
  • 补充点

问题描述

部门调整,接手一个新项目,为方便后续描述叫user-web,随后推动IT降本,要求根据实际业务量调整服务器实例数量和配置,调整前服务器配置为42实例x16核40g,降本方向主要为减少实例数和CPU数,参考的一个标准是近7日cpu的一个使用率调整到30%。调整前服务使用率为15%,通过几次调整后配置为4实例x8核12G,调整后在业务高峰期向外提供的rpc接口getUserInfo开始出现偶尔超时,该服务也只提供了一个rpc接口,中间随着服务器配置降低,接口超时数量开始稳定增多,后续增加到每天上百个,并且稳定出现,RT超过1s。

问题分析

引起接口超时原因有很多,正常getUserInfo接口调用时间都在5ms以内,rpc配置timeout是1s,峰值qps为60,首先这个问题每天都稳定出现,先排除网络抖动,最近又没有对项目做过任何代码修改,应该不是新引入的问题,唯一变化就是调整了服务器配置,考虑应该是资源不够用导致的。

观察服务运行时大盘,首先,观察最近30天整个服务的qps并没大的变化,发生超时的时间时业务高峰期,考虑是配置调整后资源过低,满足不了当前业务量。观察cpu使用率,峰值也在30%一下,应该不是cpu的影响,本身服务也确定不是计算密集型,符合认知,那就是可能是内存不够,内存不足,GC时STW单次时间过长或者频率过高,进而导致向外提供rpc超时,第一直觉是直接扩内存,直接翻倍,增加到16G,观察一天,依然有很多调用超时,并且对应超时时间短,内存占用率会有所波动,怀疑是有一些大对象,导致业务高峰期内存占用率过高,GC压力过大,GC的STW增加。

单台机器内存8G,堆内存占总内存3/4,8G,使用率在80%,堆外内存300M,代码中并没有使用堆外内存,应该不是堆外内存问题,堆内存也并没有持续升高,排除内存泄漏,进一步考虑是内存不够GC时STW单次时间过长或者GC频率过高引起的接口超时。

首先观察下使用的GC参数,使用的G1垃圾回收器,设置的最大停顿时间是200ms
在这里插入图片描述

下载gc日志,并筛选出GC时间比较长的日志,为了便于说明问题和正常服务gc日志进行了对比,:
超时接口提供方服务gc日志:
在这里插入图片描述
正常服务gc日志:
在这里插入图片描述

对比二者发现:

1、GC pause (G1 Evacuation Pause) (young)首先这是一次停顿应用程序(STOP)的年轻代垃圾回收,由to-space exhausted触发,回收后,Edgn 对象被清理从5252→0, 整个堆使用率显著降低,从 Heap: 8687.8M(9216.0M)->3048.5M(9216.0M),这是一次有效的垃圾回收。

2、正常gc耗时10ms,异常gc耗时是700ms+,相差70倍使用多线程并行回收垃圾(Parallel time)和拷贝对象到目标区域空间不足触发Full GC(Evacuation Failure)时主要的两部分耗时,其中对象拷贝有事并行垃圾回收阶段最耗时部分,这表明有很多大的存活对象要进行拷贝,这些对象在业务高峰,并大量创建,导致空间不够用。

尝试优化业务代码

观察整个服务的运行大盘,发现在发生问题的同一时间段,有个接口耗时较高,然后接口调用日志链,最终发现了出问题的代码:

 private LoadingCache<Integer, List<TVideo>> sortedShowVideoLoadingCache = Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).maximumSize(1000)
                    .build(new CacheLoader<Integer, List<TVideo>>() {

                        @Override
                        public List<TVideo> load(@NonNull Integer albumId) throws Exception {
                            return myVideoProxy.getSortedShowVideosByAlbumId(albumId);
                        }
                    });
 
 。。。
 
 public List<TVideo> getShowVieosByAlbumId(int albumId) {
        log.info("sortedShowVideoLoadingCache.size={}", sortedShowVideoLoadingCache.estimatedSize());
        List<TVideo> videos = sortedShowVideoLoadingCache.get(albumId);
        if (songs != null) {
           return JsonUtils.readValue(JsonUtils.writeValue(videos), new TypeReference<List<TVideo>>() {
            });// 问题语句
        }
        return videos;
    }

问题语句分析:JsonUtils.readValue(JsonUtils.writeValue(videos), new TypeReference<List>() {});
问题1: 采集json序列化方式效率低,导致整个调用链路RT升高,和监控观察一一致,p99为2.5s;

问题2:创建了一遍多余对象,JsonUtils.writeValue(videos)创建了一个大的字符串,这个其实最后并没有返回,作为中间结果,依然占用了大量的空间,本省整个调用链路多次调用getShowVieosByAlbumId,创建的TVideo有一千多个,翻倍之后空间还是很可观的,同时由于使用序列化方式表抵销,导致在2.5s创建的这三个对象都无法释放。

优化方案

使用更高效序列化技术Hessian协议,将从rpc结果序列化为字节流,每次需要的时候,直接反序列化出来就是全新的对象。

修改后代码

 private LoadingCache<Integer, List<TVideo>> sortedShowVideoLoadingCache = ConanCaffeineUtil.toSerializedLoadingCache(
				 Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).maximumSize(1000)
                    .build(new CacheLoader<Integer, List<TVideo>>() {

                        @Override
                        public List<TVideo> load(@NonNull Integer albumId) throws Exception {
                            return myVideoProxy.getSortedShowVideosByAlbumId(albumId);
                        }
                    }));
                    
                    
 public List<TVideo> getShowVieosByAlbumId(int albumId) {
       return sortedAllSongLoadingCache.get(albumId);
    }

优化后getShowVieosByAlbumId的RTp99下降到500ms,机器配置内存减少到8G,GC正常,没有再出现过超时。

补充点

1、其实刚开始是通过grafana对应监控大盘看接口调用时间,发现整个接口调用都是在50ms内,其实grafana统计是p99,本省超时接口数量又不多,所就看不到有长RT调用,最后通过报错日志trace调用链,观察每步调用时间。

2、中间调整了实例数、cpu核数和内存大小,cpu使用率过高会造成服务卡顿,内存不足,造成频繁gc和单次STW过长,都有可能引起提供接口超时,都需要考虑。

3、堆内存由jvm控制申请和释放,堆外内存操作系统使用,开发人员也可以手动申请堆外内存,但是不建议,容易因无忘记释放而造成内容泄漏。

4、G1的GC时间可控参数
5、G1的垃圾回收模式由几种,有什么区别?G1回收模型由Young GC、Mixed GC和Ful GC,

Young GC只回收年轻代区域(edgn,Survior)空间,仅年轻代空闲空间不足、老年代空间充足,Mixed GC除了回收年轻代,因为老年代因空间不够也需要回收,这两者都是小范围的,当复制空间不足(to-space exhausted),并多次尝试小范围回收空间依然不够时,可能会触发Ful GC,对整个堆的空间进行回收和整理,回收时间更长。

6、普通Young GC和由to-space exhausted引起的Young GC区别是,后者为了获得更多的空间,可能会执行多次额外的GC周期,停顿时间一般会大于设定的希望停顿时间。

7、G1垃圾回收器为什么将堆内存分为大小不同的块?一是提高收集的效率,多个回收线程在不同区域独立执行,二是根据需要灵活调整老年代和新生代的比例,三是更准确控制每次停顿的时间,根据历史垃圾回收记录,根据设置的最大停顿时间,使用预测模型,增量进行垃圾回收,四减少内存碎片化,每次收集之后,将对象移动到一个或者多个区域,留下来的都是大片连续可用的空间。

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

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

相关文章

docker命令docker desktop 安装 xiaomimi8/awvs14-log4j-2022 详细图文教程

docker命令docker desktop 安装 xiaomimi8/awvs14-log4j-2022 详细图文教程 1. 拉取镜像 通过命令拉取 # 拉取镜像 docker pull xiaomimi8/awvs14-log4j-2022 # 查看镜像 docker images通过doker desktop直接查看镜像 2. 启动镜像 通过命令启动 docker run -it -d -p 13…

SpringBoot购物网站

摘要 随着信息技术的高速发展&#xff0c;二十一世纪的网络技术和网络应用正在快速融入人们的生活&#xff0c;并且由于网络服务以及网络应用日渐普及&#xff0c;人们对于现在生活的需求也随之增长&#xff0c;而网上购物的便捷对人们的吸引力越来越大&#xff0c;购物网站可…

阿里云 邮件系统DNS域名解析 搭配 postfix+dovecot 邮件服务器

1 创建邮箱域名A记录(一般邮箱客户端&#xff0c;增加pop,imap,stmp 3条记录) 登录阿里云控制台--云解析DNS 2 MX记录 3 SPF记录

STM32高级控制定时器(STM32F103):PWM输出模式

目录 概述 1 PWM模式介绍 2 PWM类型 2.1 PWM边缘对齐模式 2.2 PWM中心对齐模式 3 使用STM32Cube配置PWM 3.1 STM32Cube配置参数 3.2 生成Project 4 设置PWM占空比 4.1 函数介绍 4.3 函数源码 5 测试代码 5.1 编写测试代码 5.2 函数源码 6 运行代码 概述 本文主…

微信小程序-界面提示框和消息

一.Loading加载框 小程序提供了wx.showLoading用来在加载界面的时候使用&#xff0c;比如加载图片和数据的时候可以使用。 常常和wx.hideLoading()配合使用&#xff0c;否则加载框一直存在。 其效果如下&#xff1a; 代码如下&#xff1a; //显示加载消息wx.showLoading({//提…

编译原理:代替LR的MP:2.遇到的问题

用指针加速 MP是multi-pass&#xff0c;多遍分析法&#xff0c;它是从“先乘除后加减”中得来的灵感。在实践中&#xff0c;发现C语言优先级有15级&#xff0c;如果将源代码处理15遍&#xff0c;每一遍都从头开始找&#xff0c;势必很慢。所以&#xff0c;有了用指针加速的想法…

Vue58-组件的自定义事件_总结

一、需求 父组件App收到子组件student传过来的数据&#xff0c;要在页面上呈现&#xff01; name是App的子组件student&#xff0c;通过自定义事件传过来的。 计算属性&#xff0c;得有原数据才能计算&#xff01;计算的属性要是已经存在的&#xff1a;data里面有的、props里面…

【CSS in Depth2精译】1.1.1 样式表来源

您添加到网页的样式表并非浏览器呈现样式的唯一来源。样式表有三种不同的类型或来源。您添加到页面的样式称为 作者样式&#xff08;author styles&#xff09;&#xff1b;此外还有 用户样式&#xff08;user styles&#xff09;&#xff0c;即终端用户设置的自定义样式&#…

font-spider按需生成字体文件

font-spider可以全局安装,也可以单个项目内安装,使用npm run xxxx的形式 npm i font-spider "dev": "font-spider ./*.html" <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&…

树莓派pico入坑笔记,快捷键键盘制作

使用usb_hid功能制作快捷键小键盘&#xff0c;定义了6个键&#xff0c;分别是 ctrlz ctrlv ctrlc ctrla ctrlw ctrln 对应引脚 board.GP4, board.GP8, board.GP13 board.GP28, board.GP20, board.GP17 需要用到的库&#xff0c;记得复制进单片机存储里面 然后是main主程…

《STM32 HAL库》RCC 相关系列函数详尽解析—— HAL_RCC_OscConfig()

观前提示&#xff1a;函数完整代码在文末&#xff0c;本文梳理了函数HAL_RCC_OscConfig()的主要逻辑和实现方法f105时钟树详解图 HAL_RCC_OscConfig() 函数介绍&#xff1a; 此函数是一个用于初始化RCC&#xff08;Reset and Clock Control&#xff09;振荡器&#xff08;Osc…

java8实战1(让方法参数具备行为能力)

客户需求是查出颜色为green的苹果 客户需求变成查出颜色为red的苹果 假设现在客户需求又变了,找出黄色的呢?你想查什么颜色直接做为参数输入 让调用者输入颜色参数 问题是现在客户想把重量做为条件,来筛选苹果集合 这就为难了,客户需求随时会变 观察以上例子,发现有个共同…

云计算 | (四)基本云安全

文章目录 📚基本云安全🐇云安全背景🐇基本术语和概念⭐️风险(risk)⭐️安全需求🐇威胁作用者⭐️威胁作用者(threat agent)⭐️匿名攻击者(anonymous attacker)⭐️恶意服务作用者(malicious service agent)⭐️授信的攻击者(trusted attacker)⭐️恶意的内部人员(mal…

电子竞赛2——波形发生器

设计要求&#xff1a;输入—12v电压&#xff0c;产生5v&#xff0c;1khz的正弦波&#xff0c;方波&#xff0c;三角波&#xff0c;锯齿波&#xff0c;并通过按键依次切换。 设计思想&#xff1a;用放大器组成振荡器电路&#xff0c;生成1KHZ的方波和三角波&#xff0c;通过调整…

ChatGPT提效:告别CRUD

前言 随着AIGC的发展以及大语言模型的成熟&#xff0c;各种AI应用眼花缭乱&#xff0c;以至于我们看到各种新奇的应用都会产生焦虑&#xff0c;我有一天会不会被淘汰&#xff1f;且看后文分析。AIGC的发展与逐渐成熟已经是无可逆转的局势&#xff0c;既然我们打不过为何不加入…

MinIO Enterprise Cache:实现超性能的分布式 DRAM 缓存

随着计算世界的发展和 DRAM 价格的暴跌&#xff0c;我们发现服务器配置通常配备 500GB 或更多的 DRAM。当您处理大型部署时&#xff0c;即使是那些具有超高密度 NVMe 驱动器的部署&#xff0c;这些服务器上的服务器数量乘以 DRAM 也会迅速增加&#xff0c;通常达到几 TB。该 DR…

IO系列(十) -TCP 滑动窗口原理介绍(上)

一、摘要 之前在上分享网络编程知识文章的时候&#xff0c;有网友写下一条留言&#xff1a;“可以写写一篇关于 TCP 滑动窗口原理的文章吗&#xff1f;”。 当时没有立即回复&#xff0c;经过查询多方资料&#xff0c;发现这个 TCP 真的非常非常的复杂&#xff0c;就像一个清…

3D Gaussian Splatting Windows安装

1.下载源码 git clone https://github.com/graphdeco-inria/gaussian-splatting --recursive 2.安装cuda NVIDIA GPU Computing Toolkit CUDA Toolkit Archive | NVIDIA Developer 3.安装COLMAP https://github.com/colmap/colmap/releases/tag/3.9.1 下载完成需要添加环…

pycharm git配置

PyCharm 是一个强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它内置了 Git 集成&#xff0c;使得版本控制变得非常方便。以下是 PyCharm 中配置 Git 的基本步骤&#xff1a; 安装Git: 在开始之前&#xff0c;请确保已经在您的系统上安装了 Git。您可以通过官方网…

小规模自建 Elasticsearch 的部署及优化

本文将详细介绍如何在 CentOS 7 操作系统上部署并优化 Elasticsearch 5.3.0,以承载千万级后端服务的数据采集。要使用Elasticsearch至少需要三台独立的服务器,本文所用服务器配置为4核8G的ECS云服务器,其中一台作为 master + data 节点、一台作为 client + data 节点、最后一…