Java JMH做Web负载测试时多线程用户凭证重复获取问题
JMH登录压测场景的现状
- 测试目标:针对目标Web应用开展负载性能测试,通过逐步递增并发用户规模,观测不同负载水平下的系统运行表现,测试基准基于Java生态的JMH框架搭建
- 已完成的核心开发内容:
- 标记
@Benchmark的testLogin测试方法:配置@Threads(3)实现多线程并发执行,方法内覆盖完整流程——WebDriver初始化、登录页面对象实例化、根据计数索引从用户列表读取凭证执行登录、测试结束后关闭驱动 - 标记
@Setup的初始化方法readUsers:从本地users.csv文件解析提取用户名、密码信息,封装为Pair对象存入静态用户列表集合,同时初始化静态计数索引count
- 标记
当前遇到的核心问题
- 被测系统存在刚性访问约束:单个用户同一时间仅允许维持单个会话接入,因此并发执行登录基准逻辑时,必须为每个执行线程分配独立、不重复的用户凭证,否则会触发系统的会话校验逻辑,导致测试结果失真
- 现有实现的缺陷:目前依靠静态共享变量
count作为索引获取用户的方案,在多线程并发场景下存在线程安全问题,多个线程会重复读取到同一用户凭证,完全无法满足单用户单会话的测试要求 - 待落地的需求:需要找到适配JMH运行机制的参数传递方案,为并发执行的登录基准方法传递差异化、无重复的用户凭证
可行的落地解决路径
- 利用JMH内置的线程作用域状态机制替代静态共享计数
- 新建一个类用
@State(Scope.Thread)修饰,作为当前线程的专属存储容器,内部定义字段存储绑定给当前线程的独立用户凭证;搭配全局@State(Scope.Benchmark)作用域下的原子计数器实现无锁的用户分配 - 具体执行逻辑:在Benchmark全局初始化阶段完成
users.csv的解析加载,把所有用户存入全局用户列表;在每个线程的专属初始化阶段(@Setup(Scope.Thread)),调用AtomicInteger.getAndIncrement()从全局用户列表中取走一个独占的用户凭证,存入当前线程的状态容器中,从根源上避免多线程竞争同一个索引的竞态问题
- 新建一个类用
- 彻底移除存在线程安全隐患的静态共享计数
- 删除原实现中作为共享计数器的普通静态
count变量,所有需要全局跨线程协调的计数逻辑全部使用java.util.concurrent.atomic.AtomicInteger实现,规避普通静态变量非原子操作带来的重复读取问题
- 删除原实现中作为共享计数器的普通静态
- 增加前置容量校验
- 在测试启动初始化阶段增加校验逻辑:判断全局用户列表的总容量是否大于等于峰值并发线程数(即压测配置的最大并发规模),如果用户数不足提前抛出异常提示,避免运行过程中出现用户重复分配的问题
内容的提问来源于stack exchange,提问作者mungaih pk
相关产品推荐
相关产品推荐

