记一次 JMeter 压测 HTTPS 性能问题

作者:拂衣
问题背景
Cloud Native
问题分析
Cloud Native
top -Hp {pid}

java/bin/jstat -gcutil {pid} 1000
 
// 默认缓存大小private final static int DEFAULT_MAX_CACHE_SIZE = 20480;// package privateSSLSessionContextImpl() {cacheLimit = getDefaultCacheLimit(); // default cache size,这里默认是20480timeout = 86400; // default, 24 hours// use soft reference// 这里初始化了2个默认大小20480的缓存,是频繁GC的原因sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout);sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout);}// 获取默认缓存大小private static int getDefaultCacheLimit() {try {int defaultCacheLimit = GetIntegerAction.privilegedGetProperty("javax.net.ssl.sessionCacheSize", DEFAULT_MAX_CACHE_SIZE);if (defaultCacheLimit >= 0) {return defaultCacheLimit;} else if (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;}


问题验证
Cloud Native
httpclient.reset_state_on_thread_group_iteration=false


/*** Whether SSL State/Context should be reset* Shared state for any HC based implementation, because SSL contexts are the same*/protected static final ThreadLocalresetStateOnThreadGroupIteration = ThreadLocal.withInitial(() -> Boolean.FALSE);/*** Reset SSL State.* In order to do that we need to:**Call resetContext() on SSLManager *Close current Idle or Expired connections that hold SSL State *Remove HttpClientContext.USER_TOKEN from {@link HttpClientContext} ** @param jMeterVariables {@link JMeterVariables}* @param clientContext {@link HttpClientContext}* @param mapHttpClientPerHttpClientKey Map of {@link Pair} holding {@link CloseableHttpClient} and {@link PoolingHttpClientConnectionManager}*/private void resetStateIfNeeded(JMeterVariables jMeterVariables,HttpClientContext clientContext,Map> mapHttpClientPerHttpClientKey) { if (resetStateOnThreadGroupIteration.get()) {// 关闭当前线程对应连接池的超时、空闲连接,重置连接池状态closeCurrentConnections(mapHttpClientPerHttpClientKey);// 移除TokenclientContext.removeAttribute(HttpClientContext.USER_TOKEN);// 重置SSL上下文((JsseSSLManager) SSLManager.getInstance()).resetContext();// 标记置为false,保证一次循环中,只有第一个采样器走进此逻辑resetStateOnThreadGroupIteration.set(false);}}@Overrideprotected void notifyFirstSampleAfterLoopRestart() {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);}
总结
Cloud Native
如果希望施压机发挥最大性能,可以将 https.sessioncontext.shared 设为 true,这样所有线程会共享同一个 SSL 上下文,不会频繁握手,但是不能模拟真实情况下多用户的场景。 如果希望模拟多个用户,不停循环执行某一个动作,也就是一个线程组每次循环模拟同一个用户的行为,可以将 httpclient.reset_state_on_thread_group_iteration 设置为 false,这样也可以很大的提高单机压测 HTTPS 的性能。 如果希望每个线程组每次循环模拟不同用户,那需要设置 httpclient.reset_state_on_thread_group_iteration=true,此时压测会模拟多用户频繁 SSL 握手,施压机性能最低,从经验来看,单机上限 50 并发左右。这也是 JMeter5.0 版本之后的默认设置。 
阿里云 JMeter 压测
Cloud Native
零运维成本支持分布式压测,即压即用 压测中查看秒级监控,实时观测系统性能水位 支持 RPS 模式,直观衡量系统吞吐量 全球地域发起百万级并发流量,模拟真实用户分布 支持阿里云 VPC 压测,一键打通云上内网环境 支持 JMeter 客户端插件,本地快速发起云端压测 
评论
