在WEB服务器端,每日的访问量巨大。在非生产环境需要对服务器进行压力测试,一般使用后台线程和Sleep方式来模拟线上的压力。这里使用ScheduledExecutorService实现一种简单的QPS测试代码。
QpsProxy:
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 若Runable执行的时间超过 MAX_QPS / qps,则实际的QPS会低于实际的值。
*/
public class QpsProxy {
private final Logger logger = LoggerFactory.getLogger(QpsProxy.class);
private final static int MAX_QPS = 1000;
private ScheduledExecutorService scheduledExecutorService;
private long qps = NumberUtils.LONG_ONE;
private Runnable runnable;
private long delay2Start = NumberUtils.INTEGER_ZERO;
private int threads = 10;
public QpsProxy() {
}
public ScheduledExecutorService getScheduledExecutorService() {
return scheduledExecutorService;
}
public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
this.scheduledExecutorService = scheduledExecutorService;
}
public long getQps() {
return qps;
}
public void setQps(long qps) {
Preconditions.checkArgument(qps < MAX_QPS , "设置的qps超过上限值:" + MAX_QPS);
this.qps = qps;
}
public Runnable getRunnable() {
return runnable;
}
public void setRunnable(Runnable runnable) {
this.runnable = runnable;
}
public long getDelay2Start() {
return delay2Start;
}
public void setDelay2Start(long delay2Start) {
this.delay2Start = delay2Start;
}
public int getThreads() {
return threads;
}
public void setThreads(int threads) {
this.threads = threads;
}
public void start() {
Preconditions.checkNotNull(runnable, "请设置执行的任务");
long period = (long) Math.floor((double) MAX_QPS / qps);
logger.info("间隔周期:{}ms", period);
scheduledExecutorService = Executors.newScheduledThreadPool(threads);
scheduledExecutorService.scheduleAtFixedRate(runnable, delay2Start,
period, TimeUnit.MILLISECONDS);
}
public void stop() {
Preconditions.checkNotNull(scheduledExecutorService, "任务未开始");
scheduledExecutorService.shutdown();
}
}
构建工具:
import com.google.common.base.Preconditions;
public class QpsProxyBuilder {
private QpsProxy qpsProxy = new QpsProxy();
public static QpsProxyBuilder newBuilder() {
return new QpsProxyBuilder();
}
public QpsProxyBuilder withDelay2Start(long delay2TimeByMillisSeconds) {
Preconditions.checkArgument(delay2TimeByMillisSeconds > 0);
qpsProxy.setDelay2Start(delay2TimeByMillisSeconds);
return this;
}
public QpsProxyBuilder withQps(long qps) {
Preconditions.checkArgument(qps > 0);
qpsProxy.setQps(qps);
return this;
}
public QpsProxyBuilder withRunnable(Runnable runnable) {
Preconditions.checkNotNull(runnable);
qpsProxy.setRunnable(runnable);
return this;
}
public QpsProxyBuilder withThreads(int threads) {
Preconditions.checkNotNull(threads > 0);
qpsProxy.setThreads(threads);
return this;
}
public QpsProxy build() {
return qpsProxy;
}
}
测试代码:
import com.qunar.hotel.qps.QpsProxy;
import com.qunar.hotel.qps.QpsProxyBuilder;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class qps {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void testBasic() throws InterruptedException {
QpsProxy proxy = QpsProxyBuilder.newBuilder().withQps(100).withThreads(1).withDelay2Start(4000).withRunnable(new Runnable() {
private int counter = 0;
@Override
public void run() {
logger.info("{}-{}:{}", Thread.currentThread().getName(), System.nanoTime(), counter++);
}
}).build();
proxy.start();
Thread.currentThread().sleep(5020L);
proxy.stop();
}
}