记一次 JVM 参数调整导致 ShardingSphere-Proxy 性能下降的问题排查过程

news2024/11/25 8:10:43

问题现象

在性能测试中,分别对两个版本差异间隔一天的 ShardingSphere-Proxy 做性能测试,发现版本更新的 Proxy 比旧的 Proxy 在 TPC-C 场景下峰值 tpmC 下降了 7% 左右。

排查过程

在性能测试期间,使用 async-profiler 分别对两个进程进行采样。

火焰图未发现明显代码路径异常

使用 IDEA 对比火焰图差异,发现性能下降的 Proxy 在 I/O 相关调用的比例略微减少(绿色部分),在 ShardingSphere 计算逻辑的比例略微增加(红色部分)。
在这里插入图片描述
但是,从火焰图看并没有发现性能下降的 Proxy 有什么新增的逻辑。

CPU 使用率存在细微差异

async-profiler 采样期间,每秒会读取一次 JVM 进程的用户态/内核态的 CPU 使用率,以及系统 CPU 使用率。

有时候,从 CPU 使用率的细微差异可以发现一些异常。

性能正常的 ShardingSphere-Proxy

在这里插入图片描述

性能下降的 ShardingSphere-Proxy

在这里插入图片描述

性能正常的 Proxy 进程 JVM User 使用率更低,JVM System 更高;性能异常的 Proxy 进程 JVM User 使用率略高,JVM System 略低。
这个现象和上一节火焰图对比差异能够对应上,看起来性能异常的 Proxy 在 ShardingSphere 的计算逻辑上 CPU 消耗更多。

但这还不能确定性能问题的原因,还需要更多信息。

从 Java 进程启动时的 Warning 信息中发现端倪

在同一个环境下,分别对两个 ShardingSphere-Proxy 执行 start.sh -v 查看版本时,发现其中一个 Proxy 的脚本执行后 JVM 给出了两行警告信息,另一个 Proxy 却没有警告信息。

+ /tmp/shardingsphere-proxy/bin/start.sh -v
/usr/local/openjdk-17/bin/java
we find java version: java17, full_version=17.0.2, full_path=/usr/local/openjdk-17/bin/java
OpenJDK 64-Bit Server VM warning: UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing (-XX:-UseAdaptiveSizePolicy -XX:-UseAdaptiveNUMAChunkSizing)
OpenJDK 64-Bit Server VM warning: Failed to reserve and commit memory. req_addr: 0x0000000400000000 bytes: 17179869184 page size: 2097152 (errno = 12).
ShardingSphere-5.3.3-SNAPSHOT
Branch: master

注意:虽然 Proxy 启动参数指定了 -XX:LargePageSizeInBytes=128m,但如果没有直接指定或间接(AggressiveHeap)指定 -XX:+UseLargePages,实际上没有效果。

https://github.com/openjdk/jdk17u-dev/blob/9b895233315c21920edc7ba48915afdc0a5c220a/src/hotspot/os/linux/os_linux.cpp#L3843-L3849
在这里插入图片描述

查看两个 Proxy 的 JVM 参数,发现参数唯一差异在于,性能正常的 Proxy 指定了 -XX:+AggressiveHeap,而性能较差的没有。
在这里插入图片描述

在这里插入图片描述

给性能较差的 Proxy 加上 -XX:+AggressiveHeap 并重新测试性能后,发现性能恢复到正常水平。

JVM 参数 AggressiveHeap 原理是什么?

ShardingSphere-Proxy 启用了 AggressiveHeap

ShardingSphere-Proxy 的启动脚本 start.sh 会根据使用的 JRE 版本,适当增加可以提升性能的参数。笔者曾经在 start.sh 中增加了一些适用于 Java 11 和 Java 17 的 JVM 参数以提高 ShardingSphere-Proxy 的性能,其中有一项就是 -XX:+AggressiveHeap

https://github.com/apache/shardingsphere/pull/15117

在这里插入图片描述

AggressiveHeap 是什么?

AggressiveHeap 这个参数比较冷门,能够搜到的资料非常有限,且搜索结果基本没有解释这个参数原理,而且有些博客对这个参数的理解存在偏差。

AggressiveHeap 是从 JDK 10 引入的一个参数,参数的解释就一句话:

Optimize heap options for long-running memory intensive apps

https://github.com/openjdk/jdk17u-dev/blob/9b895233315c21920edc7ba48915afdc0a5c220a/src/hotspot/share/gc/shared/gc_globals.hpp#L303-L304

在这里插入图片描述

这要如何理解?

解读 JDK 17 AggressiveHeap 源码

文档没说清楚,看源码是理解这个参数最直观准确的方式。

https://github.com/openjdk/jdk17u-dev/blob/9b895233315c21920edc7ba48915afdc0a5c220a/src/hotspot/share/runtime/arguments.cpp#L1789-L1895

源码较长,本文中不贴出。
总结一下,启用 AggressiveHeap 实际上不对应某一个具体的能力,而是让 JVM 自动设置一组 JVM 参数,大致如下:

  • 如果没有指定 -Xmx,则指定并固定堆内存大小为 Min(物理内存 / 2, 物理内存 - 160 MB)
  • 如果没有指定新生代比例,则设置 -XX:NewSize=堆内存的 3/8 -XX:MaxNewSize=堆内存的 3/8
  • 非 BSD 和 AIX 环境下,则启用 -XX:+UseLargePages
  • -XX:BaseFootPrintEstimate=堆内存大小,这个参数看起来和 ParallelGC 有关,笔者尚未进一步研究;
  • 固定 TLAB 空间为 256 KB -XX:TLABSize=262144 -XX:-ResizeTLAB
  • -XX:YoungPLABSize=262144(默认 8192);
  • -XX:OldPLABSize=8192(默认 1024);
  • 自 JDK 9 起,默认的 GC 为 G1,但 AggressiveHeap 会使用 ParallelGC -XX:+UseParallelGC
  • -XX:ThresholdTolerance=100(默认值 10),可能与回收频率控制有关,笔者尚未进一步研究;
  • 禁用 Full GC 前对新生代执行回收 -XX:-ScavengeBeforeFullGC

总结

为什么其中一个 Proxy 移除了 AggressiveHeap?

笔者询问了 Proxy 移除 AggressiveHeap 的原因,大致如下:

  • 目前 ShardingSphere-Proxy 在容器环境下(环境变量 IS_DOCKER 不为空),会不指定 -Xmx -Xms -Xmn 等指定堆内存的参数,而是使用百分比的方式指定内存使用。 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -XX:MaxRAMPercentage=80.0
  • 在实际容器环境中部署发现:使用 ShardingSphere-Proxy 镜像,容器可用内存 16GB,但 JVM 进程的堆内存只有 8GB,与参数指定的 80% 相差较大。移除 AggressiveHeap 后,JVM 堆内存接近可用内存 80%。

https://github.com/apache/shardingsphere/blob/b483b4ca96a87012ed12bc398fa34db35ef7ab11/distribution/proxy/src/main/resources/bin/start.sh#L78-L82
在这里插入图片描述
AggressiveHeap 仅考虑了是否指定了堆内存的具体大小,通过 MaxRAMPercentage 指定内存使用百分比不在 AggressiveHeap 的考虑范围之内,因此,AggressiveHeap 的逻辑会覆盖 MaxRAMPercentage 指定的上限。

琐碎想法

笔者认为,通过百分比设置 ShardingSphere-Proxy 的内存不是一个非常稳妥的办法。笔者曾经接触过部署在 Kubernetes 上的一些 Java 项目是通过环境变量设置 JVM 参数,指定明确的堆内存大小也许是个更合适的方式。

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

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

相关文章

根据aop实现自定义缓存注解

根据aop实现自定义缓存注解 自定义注解 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.TimeUnit;/*** author: yanche…

ESP32通过Arduino导出编译bin文件并进行量产烧录

ESP32通过Arduino导出编译bin文件并进行量产烧录 文章目录 ESP32通过Arduino导出编译bin文件并进行量产烧录Arduino导出编译的bin文件方法一:通过Arduino IDE提供的工具导出编译文件方法二:到编译生成的临时文件目录进行查找 弄清楚Arduino的编译烧录过程…

Unity3D:工具栏

推荐:将 NSDT场景编辑器 加入你的3D工具链 3D工具集: NSDT简石数字孪生 工具栏 在 Unity Editor 顶部可以看到工具栏。 工具栏不是窗口,是 Unity 界面中唯一无法重新排列的部分。 有关场景视图中的其他工具,请参阅叠加。 工具栏…

记录一次使用thinkphp5分页器获取数据

// 输出当前页 $nowPage $data->currentPage(); // 输出总条数 $total $data->total(); // 输出当前页条数 $listRows $data->listRows();db(tablename)->where("id > 0")->paginate(10,true,[page>4]); //每页显示10条记录,且打…

C#(五十一)之特性

特性是用于为程序元素添加额外信息的一种机制。比如记录文件修改时间、提示某方法已经过期等。方法、变量、属性、类、接口、结构体以及程序及都是程序元素 Obsolete第二个参数设置为true,调用此方法会产生警告并引起编译器报错 百度了一下C#还有其他的特性以及自定义特性&am…

基于ssm实现图书商城(spring+springmvc+mybatis)

一、项目功能 前台 图书基本展示,包括推荐图书展示和类图书类型展示.推荐图书包括条幅推荐,热销推荐和新品推荐.按照图书类型展示商品.图书详细信息展示.图书加入购物车.修改购物车内图书信息,例如数量等.用户登录.用户注册.修改个人信息,包括密码和收获信息.购物车付款.用户…

前置声明、源文件include、编译链接顺序问题

TestB.h (前置声明,无需在源文件include)重点: 1.前置声明用在指针变量使用,无需在头文件或源文件include 2.继承或者普通变量在头文件使用的时候(除非所有的编译顺序都正确,才能在源文件include),最好不要在源文件i…

汇编语言基础--内中断

在8086CPU实模式下有如下内存布局: 我们看到在000-3FF的位置是放着中断向量表。 里面放的其实是4个字节的地址(地址处放着对应的中断处理函数)。我们知道在8086实模式下,是通过cs:ip来找到要执行的指令。cs是2个字节,i…

chat2DB使用教程

1. chat2DB简介 1-1. 简介 ​ chat2DB是一款有开源免费的多数据库客户端工具,支持windows、mac本地安装,也支持服务器端部署,web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2DB集成了AIGC的能力,能够将自然语…

Squid 缓存代理--反向代理

Squid 缓存代理–反向代理 反向代理:如果Squid反向代理服务器中缓存了该请求的资源,则将该请求的资源直接返回给客户端:否则反向代理服务器将向后台的WEB服务器请求资源,然后将请求的应答返回给客户端,同时也将应答缓…

VMware 虚拟磁盘格式

1.如果必须用FT , 只能选eagerzeroedthick 2.如果追求最佳应用性能不考虑空间占用 , 选eagerzeroedthick 3.如果希望最大成都的利用空间,并且对磁盘的增长是可控的,可以选thin格式 4.如果不希望空间的过量分配(oversubsribe)造…

OpenStack组件的基本使用

OpenStack组件的基本使用 Keystone命令行的方式项目用户角色 图形化界面方式项目用户角色 Glance命令行操作镜像上传下载管理镜像开放镜像权限转换镜像格式 图形化界面 Nova和Neutron命令行的方式实例类型密钥对安全组创建网络创建云主机启动关闭云主机 图形化界面创建实例类型…

【数据结构与算法】二叉树中从每个叶子结点到根结点的路径

题目 Qestion: 输出二叉树中从每个叶子结点到根结点的路径 数据结构与定义 #include <stdio.h> #include <stdlib.h>typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right; } TreeNode;二叉树形状 核心代码 void LeafToRoot(TreeNod…

[网络安全提高篇] 一二一.恶意软件动态分析Cape沙箱Report报告的API序列批量提取详解

终于忙完初稿,开心地写一篇博客。 “网络安全提高班”新的100篇文章即将开启,包括Web渗透、内网渗透、靶场搭建、CVE复现、攻击溯源、实战及CTF总结,它将更加聚焦,更加深入,也是作者的慢慢成长史。换专业确实挺难的,Web渗透也是块硬骨头,但我也试试,看看自己未来四年究…

HIve中的查询语句

文章目录 Hive中的查询语句1. 基础语法2. 基本查询&#xff08;Select…From&#xff09;2.1 数据准备&#xff08;0&#xff09;原始数据&#xff08;1&#xff09;创建部门表&#xff08;2&#xff09;创建员工表&#xff08;3&#xff09;导入数据 2.2 全表和特定列查询1&am…

【对象存储】那些事

最近在某个项目中使用了对象存储。以前看过一个新闻&#xff1a;某公司的对象存储被盗刷&#xff0c;一夜之间账户欠费几十万&#xff01;我们这点小买卖可经不起这么折腾&#xff01;所以下功夫研究了下&#xff0c;防患于未然。 说到防盗刷&#xff0c;我们还得了解对象存储是…

Jmeter使用之:怎么编写扩展函数(二)

目录 前言&#xff1a; 1、实现function的类的package声明必须包含".functions" 2、需要继承org.apache.jmeter.functions.AbstractFunction&#xff0c;并且实现相应的方法。 第一步&#xff1a;eclipse 导入jmeter目录&#xff1a;apache-jmeter-2.13libext下的…

【SLAM学习】FAST-LIO配置

本文主要记录如何配置FAST-LIO Eigen库 Eigen库安装&#xff1a; sudo apt install libeigen3-dev 查看Eigen版本&#xff1a; $ pkg-config --modversion eigen3 PCL库 PCL库安装&#xff1a; sudo apt install libpcl-dev 也可以指定版本安装&#xff1a; sudo apt …

AVS3:角度加权预测AWP

在一般的视频编码标准中帧间预测有两种方式&#xff1a;单向预测和双向预测。一般是将图像划分为矩形&#xff08;正方形&#xff09;块然后到参考帧中去搜索和它最接近的块作为预测块&#xff0c;单向预测只有一个预测块&#xff0c;而双向搜索会有2个预测块&#xff0c;将2个…

基于Java医院住院综合服务管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…