性能测试概念再理解——集合点
2016-12-23 11:23
183 查看
什么是集合点
集合点可以简单得理解为一种控制虚拟用户行为的机制,该机制可以达到在一定时间范围内将一定数量的虚拟用户阻挡在一个操作行为点前的位置进行互相等待,在条件(达到虚拟用户数量或超时)到达后唤醒全部等待中的虚拟用户,从而达到使得一定数量的虚拟用户可以同时进入下一个操作行为点的目的。往往其使用初衷是为了实现最大意义上的并发来考察系统应对此种极端情况的表现。
JMeter中所提供的SyncTimer(同步计时器),就是内部利用CyclicBarrier来控制阻塞和释放全部运行线程的逻辑行为,从而达到“集合点”的目的,参考以下代码:
private static final class BarrierWrapper implements Cloneable { private CyclicBarrier barrier; public BarrierWrapper() { this.barrier = null; } public BarrierWrapper(int parties) { this.barrier = new CyclicBarrier(parties); } public synchronized void setup(int parties) { if(this.barrier== null) { this.barrier = new CyclicBarrier(parties); } } public int await() throws InterruptedException, BrokenBarrierException{ return barrier.await(); } public int await(long timeout, TimeUnit timeUnit) throws InterruptedException, BrokenBarrierException, TimeoutException { return barrier.await(timeout, timeUnit); } public void reset() { barrier.reset(); } @Override protected Object clone() { BarrierWrapper barrierWrapper= null; try { barrierWrapper = (BarrierWrapper) super.clone(); barrierWrapper.barrier = this.barrier; } catch (CloneNotSupportedException e) { //Cannot happen } return barrierWrapper; } }
利用内部静态类BarrierWrapper包裹实现了CyclicBarrier类的全部方法,并确保了使用延时加载方式初始化一个真正的CyclicBarrier对象。
Timer实际上通过delay()方法实现控制,参考以下代码:
@Override public long delay() { if(getGroupSize()>=0) { int arrival = 0; try { if(timeoutInMs==0) { arrival = this.barrier.await(); } else if(timeoutInMs > 0){ arrival = this.barrier.await(timeoutInMs, TimeUnit.MILLISECONDS); } else { throw new IllegalArgumentException("Negative value for timeout:"+timeoutInMs+" in Synchronizing Timer "+getName()); } } catch (InterruptedException e) { return 0; } catch (BrokenBarrierException e) { return 0; } catch (TimeoutException e) { LOGGER.warn("SyncTimer "+ getName() + " timeouted waiting for users after:"+getTimeoutInMs()+"ms"); return 0; } finally { if(arrival == 0) { barrier.reset(); } } } return 0; }
每个线程到达这里都会执行this.barrier.await()来等待其他线程,直到到达你所配置的等待用户值或者超时值(timeoutInMs)时完成释放,这时arrival会等于0,从而使用barrier.reset()对barrier进行重置,为下一批进入的线程设置阻塞。
达到增压的目的了吗?
集合点真的可以达到对系统增加压力的效果吗?事实是不一定的(这种情况一般出现在ThinkTime和KeyTime被置0的前提下),这和你对其的使用方法和系统本身的构造息息相关,遇到的真实情况可能是在某个操作行为点上加了集合点后,整个事务性能变得更好了,这听起来有点不可思议,但你可以尝试分析一下原因:
(1)当用户同时起步向前的时候,系统可以更加轻松的应对
混乱场面下的用户可能会各自处在不同的业务操作点下,有些在查询,有些在插入,有些在更新,这会对数据库的事务完整性控制提出要求,数据库会通过读提交、可重读或同步序列的方式,利用表级锁、行级锁来避免脏读和幻读的出现从而避免破坏ACID,在这种情况下必定会产生大量的锁竞争,对性能会产生一定损耗。
但在用户同步调的进行业务操作时,往往会大幅度的降低这种锁竞争的局面,另外,这种情况下更加适合于缓存这种利器效果的发挥,这对系统来说会省下了不少力气。
(2)集合点的出现会明显缓解服务端所直接承受的压力
单独业务点上虽然看似集合后压力增大了,但是这个要分析具体情况,首先,在释放阻塞之前,用户会处于互相等待的状态中,往往会有一些表现不尽如人意的用户拖了后腿,于是工具会陷入漫长的阻塞状态中,对服务端的压力逐渐减小,服务端的压力得到明显缓解,从而得到了喘息和休整的机会。
(3)测试工具统计结果中会加入等待时所产生的数据
用户都在集合点互相等待会导致TPS直线下降,原因是测试工具一般会把这段时间所产生的数据也算到统计中,这就会造成在最终使用这份工具生成测试结果时的一些困扰,需要利用原始值进一步加工。
正确使用集合点
首先,不是特别建议你在测试场景的设计中加入集合点,实际上在忽略ThinkTime和KeyTime的情况下,已经可以叫并发测试了,而且效果也完全达到了预期。如果想使用集合点,你要有十分充足的需求作为导向。另外,建议将大事务拆解为更加短小精悍的几个小事务,并且通过分组运行调节这些事务之间的关系,比如一个组可以跑整个大事务或一些组按事务混合比跑其中几个小事务串儿作为持续不断的压力背景,在这种情况下精选几个关键性业务下的事务组合放入集合点,一个一个的在压力背景环境下下运行测试,重点关注它们的真正并发表现。
一些其他用途
(1)处理业务流或数据流上下游关系当业务流或数据流继承关系要求耦合性非常高时,比如下游所需要处理的业务或数据必须依赖于上游所有或一定量用户完成相应业务处理或产生数据的基础上,可以利用集合点达到正确处理这类关系的效果。
(2)流控
当配合一些逻辑判断脚本或工具组件时,通过判断是否在一些特殊条件满足的情况下启动集合点,可以达到用户流量控制的效果。
简书浏览地址:http://www.jianshu.com/p/f84c9d7ad87e