在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(); } }