jmeter做压测性能调优:SSL上下文切换导致SSL频繁握手【杭州多测师_王sir】【杭州多测师】...

news2024/9/28 19:25:27
一、问题背景
在使用 JMeter 压测时,发现同一后端服务,在单机 500 并发下,HTTP 和 HTTPS 协议压测 RT 差距非常大。同时观测后端服务各监控指标水位都很低,因此怀疑性能瓶颈在 JMeter 施压客户端。 二、问题分析
切入点:垃圾回收
首先在施压机观察到 CPU 使用率和内存使用率都很高,详细看下各线程 CPU、内存使用情况:
top -Hp {pid}
发现进程的 CPU 使用率将近打满,其中 GC 线程 CPU 使用率很高

再看下 gc 的频率和耗时,发现每秒都有 YoungGC,且累计耗时比较长,因此先从频繁 GC 入手,定位问题。
java/bin/jstat -gcutil {pid} 1000

在压测过程中,对 JMeter 的运行进程做了 HeapDump 后,分析下堆内存:

可以看到 cacheMap 对象占用了 93.3%的内存,而它又被 SSLSessionContextImpl 类引用,分析下源码,可以看出,每个 SSLSessionContextImpl 对象构造时,都会初始化 sessionHostPortCache 和 sessionCache 两个软引用 Cache。因为是软引用,所以在内存不足时 JVM 才会回收此类对象。
// 默认缓存大小private final staticint DEFAULT_MAX_CACHE_SIZE = 20480;

    // package private
    SSLSessionContextImpl() {
        cacheLimit = getDefaultCacheLimit();    // default cache size,这里默认是20480
        timeout = 86400;                        // default, 24 hours// use soft reference// 这里初始化了2个默认大小20480的缓存,是频繁GC的原因
        sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
        sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
    }

    // 获取默认缓存大小privatestaticintgetDefaultCacheLimit() {
        try {
            int defaultCacheLimit = GetIntegerAction.privilegedGetProperty(
                    "javax.net.ssl.sessionCacheSize", DEFAULT_MAX_CACHE_SIZE);

            if (defaultCacheLimit >= 0) {
                return defaultCacheLimit;
            } elseif (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
                SSLLogger.warning(
                    "invalid System Property javax.net.ssl.sessionCacheSize, " +
                    "use the default session cache size (" +
                    DEFAULT_MAX_CACHE_SIZE + ") instead");
            }
        } catch (Exception e) {
            // unlikely, log it for safeif (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
                SSLLogger.warning(
                    "the System Property javax.net.ssl.sessionCacheSize is " +
                    "not available, use the default value (" +
                    DEFAULT_MAX_CACHE_SIZE + ") instead");
            }
        }

        return DEFAULT_MAX_CACHE_SIZE;
    }

通过上述代码,发现 sessionCache 和 sessionHostPortCache 缓存默认大小是 DEFAULT_MAX_CACHE_SIZE,也就是 20480。对于我们压测的场景来说,如果每次请求重新建立连接,那么就根本不需要这块缓存。再看下代码逻辑,发现其实可以通过 javax.net.ssl.sessionCacheSize 来设置缓存的大小,在 JMeter 启动时,添加 JVM 参数-Djavax.net.ssl.sessionCacheSize=1,将缓存大小设置为 1,重新压测验证,观察 GC。
可以看出,YGC 明显变少了,从 1 秒 1 次,变成了 5-6 秒 1 次。那么观察下压测的 RT,结果。。。竟然还是 1800ms,本来 100ms 的服务被压成 1800ms,看来问题不在于 SSLSession 的缓存。再回到 GC 的耗时分析部分,仔细看下,其实 Full GC 只有 1 次,阻塞性的耗时并不多,Young GC 虽然频繁,但阻塞时间很短,也不至于将 SSL 加解密的 CPU 计算时间片全部抢占。看起来压力就是单纯的 SSL 握手次数多,造成了性能瓶颈。


调整思路:为什么频繁 SSL 握手
回到问题背景,我们是在做压力测试,单机会跑很高的并发模拟用户量,出于性能考虑,完全可以一次握手后共享 SSL 连接,后续不再握手,为什么 JMeter 会如此频繁握手呢?
带着这个问题,看了下 JMeter 官方文档,果然有惊喜!
原来 JMeter 有 2 个开关在控制是否重置 SSL 上下文的选项,首先是 https.sessioncontext.shared 控制是否全局共享同一个 SSLContext,如果设为 true,则各线程共享同一个 SSL 上下文,这样对施压机性能压力最低,但不能模拟真实多用户 SSL 握手的情况。
第二个开关 httpclient.reset_state_on_thread_group_iteration 是线程组每次循环是否重置 SSL 上下文,5.0 之后默认为true,也就是说每次循环都会重置 SSL 上下文,看来这就是导致 SSL 频繁握手的原因。

三、问题验证回归测试
在 jmeter.properties 中将配置每个线程循环时,不重置 SSL 上下文,在 PTS 控制台再次启动压测,RT 直接下降 10 倍。
httpclient.reset_state_on_thread_group_iteration=false
修改前

修改后

源码验证
下面从源码层面分析下 JMeter 是怎么实现循环重置 SSL 上下文的,代码如下:

/**
     *  Whether SSL State/Context should be reset
     *  Shared state for any HC based implementation, because SSL contexts are the same 
     */protectedstatic final ThreadLocal<Boolean> resetStateOnThreadGroupIteration =
            ThreadLocal.withInitial(() -> Boolean.FALSE);


    /**
     * Reset SSL State. <br/>
     * In order to do that we need to:
     * <ul>
     *  <li>Call resetContext() on SSLManager</li>
     *  <li>Close current Idle or Expired connections that hold SSL State</li>
     *  <li>Remove HttpClientContext.USER_TOKEN from {@link HttpClientContext}</li>
     * </ul>
     * @param jMeterVariables {@link JMeterVariables}
     * @param clientContext {@link HttpClientContext}
     * @param mapHttpClientPerHttpClientKey Map of {@link Pair} holding {@link CloseableHttpClient} and {@link PoolingHttpClientConnectionManager}
     */privatevoidresetStateIfNeeded(JMeterVariables jMeterVariables, 
            HttpClientContext clientContext,
            Map<HttpClientKey, Pair<CloseableHttpClient, PoolingHttpClientConnectionManager>> mapHttpClientPerHttpClientKey) {
        if (resetStateOnThreadGroupIteration.get()) {
            // 关闭当前线程对应连接池的超时、空闲连接,重置连接池状态closeCurrentConnections(mapHttpClientPerHttpClientKey);
            // 移除Token
            clientContext.removeAttribute(HttpClientContext.USER_TOKEN);
            // 重置SSL上下文
            ((JsseSSLManager) SSLManager.getInstance()).resetContext();
            // 标记置为false,保证一次循环中,只有第一个采样器走进此逻辑
            resetStateOnThreadGroupIteration.set(false);
        }
    }

    @OverrideprotectedvoidnotifyFirstSampleAfterLoopRestart() {
        log.debug("notifyFirstSampleAfterLoopRestart called "
                + "with config(httpclient.reset_state_on_thread_group_iteration={})",
                RESET_STATE_ON_THREAD_GROUP_ITERATION);
        resetStateOnThreadGroupIteration.set(RESET_STATE_ON_THREAD_GROUP_ITERATION);
    }

在每次基于 Apache HTTPClient4 的 HTTP 采样器执行时,都会调用 resetStateIfNeeded 方法,在进入方法时读取 httpclient.reset_state_on_thread_group_iteration 配置,即 resetStateOnThreadGroupIteration。如果是 true,重置当前线程的连接池状态、重置 SSL 上下文,然后再将 resetStateOnThreadGroupIteration 置为 false。
因为 JMeter 的并发是基于线程实现的,resetStateOnThreadGroupIteration 这个开关放在 ThreadLocal 里,在每次循环开始时,会调用 notifyFirstSampleAfterLoopRestart 方法,重置开关,运行一次后,强制把开关置为 false。这保证了每次循环只有第一个采样器进入此逻辑,也就是每次循环只执行一次。四、总结
本次解决了 JMeter5.0 版本以上压测 HTTPS 协议的性能问题,经验总结如下:
1)如果希望施压机发挥最大性能,可以将 https.sessioncontext.shared 设为 true,这样所有线程会共享同一个 SSL 上下文,不会频繁握手,但是不能模拟真实情况下多用户的场景。
2)如果希望模拟多个用户,不停循环执行某一个动作,也就是一个线程组每次循环模拟同一个用户的行为,可以将 httpclient.reset_state_on_thread_group_iteration 设置为 false,这样也可以很大的提高单机压测 HTTPS 的性能。
3)如果希望每个线程组每次循环模拟不同用户,那需要设置 httpclient.reset_state_on_thread_group_iteration=true,此时压测会模拟多用户频繁 SSL 握手,施压机性能最低,从经验来看,单机上限 50 并发左右。这也是 JMeter5.0 版本之后的默认设置。

五、拓展:阿里云 JMeter 压测阿里云PTS压测工具链接:https://help.aliyun.com/product/29260.html原文链接来自:https://www.cnblogs.com/alisystemsoftware/p/16298095.html
阿里云PTS 压测工具支持原生 JMeter 脚本,并且在 HTTPS 的压测中已将 httpclient.reset_state_on_thread_group_iteration 默认设置为 false,极大提高压测 HTTPS 时施压机性能,节省压测成本。如果模拟最真实的用户访问情况来压测,可以通过修改 JMeter 环境中的自定义 properties 配置,将 httpclient.reset_state_on_thread_group_iteration 设置为 true。

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

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

相关文章

【无标题】大模型时代,视觉推理任务竟然只用语言数据也能学习

原文链接&#xff1a;https://www.techbeat.net/article-info?id4394 作者&#xff1a;seven_ 要让AI模型真正具备智能感知和认知的功能&#xff0c;我们就不得不把视觉分析和自然语言理解二者结合起来进行研究。AI大模型社区的成长为我们带来了很多极具想象力和创造力的新应用…

基于FPGA通过1Gb以太网低延迟传输专业级4K AV信号解决方案

ME10 SoC是全栈AV Over IP片上IP系统(SoC)&#xff0c;通过1Gb网络传输HDMI2.0 4K 4:4:4 的视频、音频和控制数据&#xff0c;ME10 SoC采用一个小的23 x 23毫米BGA封装。ME10主要特色为互通性和优越性能。 IPMX是AV的开放标准和规范的集合&#xff0c;专为专业AV市场开发的IP。…

【并发编程七】C++进程通信——套接字(socket)_80行代码实现一个聊天软件

【并发编程七】进程通信——套接字&#xff08;socket&#xff09;_80行代码实现一个聊天软件一、简介二、相关知识介绍1、winsock1.h、winsock2.h2、如何使用ws2_32.dll3、WSAStartup() 函数4、socket5、bind5、listen6、accept7、connect三、聊天软件的代码如下1、服务端2、客…

QT系列第5节 QT中常用输入控件

QT中经常利用控件来获取用户输入数据&#xff0c;本篇将介绍常用的用户输入控件 目录 (1) QSpinBox (2) QDoubleSpinBox &#xff08;3&#xff09;QSlider &#xff08;4&#xff09; QScrollBar &#xff08;5&#xff09;QProgressBar &#xff08;6&#xff09;QDia…

@MapperScan原理探究

1. 前言 MyBatis在整合Spring的时候&#xff0c;只需要加如下注解&#xff0c;就可以将Mapper实例注册到IOC容器交给Spring管理&#xff0c;它是怎么做到的呢&#xff1f;&#xff1f;&#xff1f; MapperScan("com.xxx.mapper")提出几个问题&#xff1a; Mapper接…

Snipaste的使用

Snipaste截屏软件的使用&#xff1a; 1、开始截屏 第一种方式&#xff1a;快捷键 &#xff08;默认是F1&#xff09;也就是说按一下F1键就会进入截屏状态。 第二种方式&#xff1a;点击软件在任务栏上的图标。 2、选定截屏区域&#xff1a; 进入截屏状态后移动鼠标&#x…

绩效考核管理方案

第一部分 总 则 第一条&#xff1a;目的 1、通过绩效考核&#xff0c;传递组织目标和压力&#xff0c;促使员工提高工作绩效&#xff0c;达到“培养员工、提高员工的工作能力、纠正员工偏差、使之更好地为公司服务&#xff0c;达到公司与个人之间的双赢”的目的。 2、加强公司的…

四、fs文件系统模块

fs模块是Node.js官方提供用来操作文件的模块&#xff0c;属于核心模块&#xff0c;提供了一些列的方法和属性&#xff0c;用来满足用户的操作需求&#xff1b; 引入fs模块 const fs require(fs); fs.readFile() 读取 读取指定的内容&#xff0c;fs.readFile(path[&#xff…

图文排版 之 line-height

图文排版 之 line-height 设置行盒子的高度. line-height 经常被用来设置多行文本的行间距. 对于块级元素, line-height 制定了行盒子的最小高度. 对于非替换的内联元素, line-height 的值用来计算行盒子的高度. 一般来说, 大家都知道一个 div 的高度默认是由其子元素撑起的, …

史上最全 Java 高频面试合集,命中率高达 95%

进大厂是大部分程序员的梦想&#xff0c;而进大厂的门槛也是比较高的&#xff0c;所以这里整理了一份阿里、美团、滴滴、头条等大厂面试大全&#xff0c;其中概括的知识点有&#xff1a;Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、 Redis、MySQL、Spring、S…

现代控制理论

系统的状态空间表达式的建立 建立系统状态空间表达式的三种方法 &#xff08;1&#xff09;根据系统的方框图列写 &#xff08;2&#xff09;从系统的基本原理推导 &#xff08;3&#xff09;根据传递函数或者高阶微分方程实现 方框图法 有些系统的系统机理还没搞清楚可以使…

nodejs+vue高校教室管理系统

摘 要 1 1 系统概述 4 1.1研究背景 4 1.2研究现状 4 1.3主要内容 5 2 系统开发环境 6 2.3 MySql数据库 6 2.4 B/S结构 7 3 需求分析 8 3.1技术可行性&#xff1a;技术背景 8 3.2经济可行性 8 3.3操作可行性 8 3.4系统设计规则 9 3.5系统流程和逻辑 9 4系统概要设计 13 4.1 概…

Delaunay三角网之分治算法

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Delaunay三角网现有的构网算法有很多种,有学者曾对其中一些算法进行了调查和评估(如下图所示)。结果表明,在少量点时,Lawson的增量插入算法、Lee和Schachter的分治算法以及Fortune的平面扫描算法在速度上大致相…

Hexo+stun主题+Gitee5分钟快速搭建你的个人Blog

环境配置 首先要下载Node.js&#xff0c;然后安装Git&#xff0c;接着注册码云&#xff0c;最后安装Hexo&#xff0c;Hexo安装命令行(cmd 或 gitbash): npm install hexo-cli -g速度慢可以先改一下安装源: npm config set registry https://registry.npm.taobao.orgHexo搭建 目…

Linux调试器-gdb介绍

文章目录gdb的基础使用gdb是什么gdb的使用gdb的下载**l 显示代码****b 行号 :打断点****info b :查看断点****d 断点序号 :删除断点****r :运行调试****n&#xff08;next&#xff09; &#xff1a;逐过程****s&#xff08;step&#xff09;&#xff1a;逐语句****c&#xff08…

程序员接私活的那些事

每日坚持一点点&#xff0c;就离目标近一点。 文章目录怎么在空闲时间获得格外的收入接私活的有哪些途径接私活的途中需要注意什么格外福利怎么在空闲时间获得格外的收入 今天我们就不聊技术问题&#xff0c;咱们聊聊一个有意思的话题—>怎么在空闲的时间获得格外的收益&…

设计模式3 - 结构型模式

23种设计模式分析与见解开篇、UML、软件设计原则https://blog.csdn.net/lili40342/article/details/128358435创建型模式https://blog.csdn.net/lili40342/article/details/128358392结构型模式https://blog.csdn.net/lili40342/article/details/128358313行为型模式https://bl…

UNIAPP实战项目笔记54 登录时用state存储用户信息并持久化用户登录和退出登录功能

UNIAPP实战项目笔记54 登录时用state存储用户信息并持久化用户登录和退出登录功能 登录信息各个页面同步使用的是state 登录信息的持久化使用的是本地存储 打开APP自动初始化本地存储数据到state中 实际案例图片 登录页面数据渲染 代码 login.vue页面 登录成功后显示的页面 &l…

论文阅读 - Social Bot-Aware Graph Neural Network for Early Rumor Detection - CCF B

目录 摘要&#xff1a; 1 绪论 2 问题定义 3 SBAG模型 3.1社交机器人检测 3.2 机器人感知图神经网络 3.2.1基于GCN的用户发布 3.2.2 基于GAT的用户交互 3.2.3文本编码器 3.2.4 输出层 3.3 训练 4 实验 4.1 数据集 4.2 实验设置 4.3 基线 4.4 实验结果 4.4.1 谣言…

对时间序列数据(牛仔裤销售数据集)进行LSTM预测(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 LSTM模型的一个常见用途是对长时间序列数据进行学习预测&#xff0c;例如得到了某商品前一年的日销量数据&#xff0c;我们可以…