java qps 怎么计算_一种高效的QPS统计方法

本文介绍了一个使用Java实现的QPS(每秒查询率)计算器。通过RollingNumber类,它使用多个时间槽和ReentrantLock来避免锁竞争,提高统计效率。每个时间槽记录通过的事件,并在时间片结束后进行重置。在多线程测试中,该计算器能够处理大量请求并准确计算QPS。
摘要由CSDN通过智能技术生成

importjava.io.Serializable;importjava.util.ArrayList;importjava.util.Collections;importjava.util.HashMap;importjava.util.LinkedHashMap;importjava.util.List;importjava.util.Map;importjava.util.concurrent.CountDownLatch;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.atomic.LongAdder;importjava.util.concurrent.locks.ReentrantLock;/*** @Author: gxj*/

public classQPSCalculator {privateRollingNumber rollingNumber;publicQPSCalculator() {this.rollingNumber = newRollingNumber();

}public voidpass() {

rollingNumber.record();

}private static final classRollingNumber {/*** 槽位的数量*/

private intsizeOfBuckets;/*** 时间片,单位毫秒*/

private intunitOfTimeSlice;/*** 用于判断是否可跳过锁争抢*/

private inttimeSliceUsedToCheckIfPossibleToBypass;/*** 槽位*/

privateBucket[] buckets;/*** 目标槽位的位置*/

private volatileInteger targetBucketPosition;/*** 接近目标槽位最新更新时间的时间*/

private volatileLong latestPassedTimeCloseToTargetBucket;/*** 进入下一个槽位时使用的锁*/

privateReentrantLock enterNextBucketLock;/*** 默认60个槽位,槽位的时间片为1000毫秒*/

publicRollingNumber() {this(60, 1000);

}/*** 初始化Bucket数量与每个Bucket的时间片等

*

*@paramsizeOfBuckets

*@paramunitOfTimeSlice*/

public RollingNumber(int sizeOfBuckets, intunitOfTimeSlice) {this.latestPassedTimeCloseToTargetBucket = System.currentTimeMillis() - (2 *unitOfTimeSlice);this.targetBucketPosition = null;this.sizeOfBuckets =sizeOfBuckets;this.unitOfTimeSlice =unitOfTimeSlice;this.enterNextBucketLock = newReentrantLock();this.buckets = newBucket[sizeOfBuckets];this.timeSliceUsedToCheckIfPossibleToBypass = 3 *unitOfTimeSlice;for (int i = 0; i < sizeOfBuckets; i++) {this.buckets[i] = newBucket();

}

}private voidrecord() {long passTime =System.currentTimeMillis();if (targetBucketPosition == null) {

targetBucketPosition= (int) (passTime / unitOfTimeSlice) %sizeOfBuckets;

}

Bucket currentBucket=buckets[targetBucketPosition];if (passTime - latestPassedTimeCloseToTargetBucket >=unitOfTimeSlice) {if (enterNextBucketLock.isLocked() && (passTime - latestPassedTimeCloseToTargetBucket)

}else{try{

enterNextBucketLock.lock();if (passTime - latestPassedTimeCloseToTargetBucket >=unitOfTimeSlice) {int nextTargetBucketPosition = (int) (passTime / unitOfTimeSlice) %sizeOfBuckets;

Bucket nextBucket=buckets[nextTargetBucketPosition];if(nextBucket.equals(currentBucket)) {if (passTime - latestPassedTimeCloseToTargetBucket >=unitOfTimeSlice) {

latestPassedTimeCloseToTargetBucket=passTime;

}

}else{

nextBucket.reset(passTime);

targetBucketPosition=nextTargetBucketPosition;

latestPassedTimeCloseToTargetBucket=passTime;

}

nextBucket.pass();return;

}else{

currentBucket=buckets[targetBucketPosition];

}

}finally{

enterNextBucketLock.unlock();

}

}

}

currentBucket.pass();

}publicBucket[] getBuckets() {returnbuckets;

}

}private static class Bucket implementsSerializable {private static final long serialVersionUID = -9085720164508215774L;privateLong latestPassedTime;privateLongAdder longAdder;publicBucket() {this.latestPassedTime =System.currentTimeMillis();this.longAdder = newLongAdder();

}public voidpass() {

longAdder.add(1);

}public longcountTotalPassed() {returnlongAdder.sum();

}public longgetLatestPassedTime() {returnlatestPassedTime;

}public void reset(longlatestPassedTime) {this.longAdder.reset();this.latestPassedTime =latestPassedTime;

}

}public static voidmain(String[] args) {try{final QPSCalculator qpsCalculator = newQPSCalculator();int threadNum = 4;

CountDownLatch countDownLatch= newCountDownLatch(threadNum);

List threadList = new ArrayList();for (int i = 0; i < threadNum; i++) {

threadList.add(newThread() {public voidrun() {for (int i = 0; i < 50000000; i++) {

qpsCalculator.pass();

}

countDownLatch.countDown();

}

});

}long startTime =System.currentTimeMillis();for(Thread thread : threadList) {

thread.start();

}

countDownLatch.await();long endTime =System.currentTimeMillis();long totalTime = endTime -startTime;

System.out.print("totalMilliseconds: " +totalTime);

TimeUnit.SECONDS.sleep(1000L);

}catch(Exception e) {

e.printStackTrace();

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值