一、JAVA实现QPS控制
方法1:解决方案 (假设需要控制在1s内不多于400个请求):
方案描述:
使用数组存储每个请求到来的时间,前400次请求顺利通过,并填满数组。
后续请求到来时,判断当前时间是否比数组中最早的时间晚1s,未晚,则打回,
晚则替换数组中最早的值。循环。
参见:https://blog.youkuaiyun.com/u012104435/article/details/50963698
package com.example.demo.util;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class QpsUtil {
/**
* 接受请求窗口
*/
private long[] accessWindow;
/**
* 窗口大小
*/
private int limit;
/**
* 指针位置
*/
private int curPosition;
/**
* 时间间隔
*/
private long period;
private final Object lock = new Object();
/**
* 1秒内最多400次请求
* @param limit 限制次数 400
* @param period 时间间隔 1
* @param timeUnit 间隔类型 秒
*/
public QpsUtil(int limit, int period, TimeUnit timeUnit) {
if (limit < 0) {
throw new IllegalArgumentException("Illegal Capacity: " + limit);
}
curPosition = 0;
this.period = timeUnit.toMillis(period);
this.limit = limit;
accessWindow = new long[limit];
Arrays.fill(accessWindow, 0);
}
public boolean isPass() {
long curTime = System.currentTimeMillis();
synchronized (lock) {
if (curTime >= period + accessWindow[curPosition]) {
accessWindow[curPosition++] = curTime;
curPosition = curPosition % limit;
return true;
} else {
return false;
}
}
}
public static void main(String[] args) {
QpsUtil util = new QpsUtil(2,1,TimeUnit.SECONDS);
for(;;){
if (util.isPass()){
new Token().run();
}
}
}
}
class Token {
public String run() {
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
System.out.println("server received"+sdf.format(new Date()));
return "reponse";
}
}
方法2:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 流量控制<br>
* 根据给定的入参,来控制调用allocate的次数.
*/
public class BandwidthAllocator
{
/**
* Interval between allocations, in milliseconds.
*/
private static final int INTERVAL = 1000;
/**
* 对象锁
*/
private final Lock lock = new ReentrantLock();
/**
* timestamp
*/
private long timestamp;
/**
* 最大流量
*/
private int maxbps;
private int currentbps;
private int bytesread;
/**
* Creates a new <code>BandwidthAllocator</code> <br>
* that will allow a specific number of times per second to be transferred.
*
* @param bandwidth the maximum number of times per second which should be transmitted
*/
public BandwidthAllocator(int bandwidth)
{
this.maxbps = bandwidth;
this.currentbps = 0;
this.bytesread = 0;
this.timestamp = System.currentTimeMillis();
}
/**
* 流量控制
*/
public void allocate()
{
lock.lock();
try
{
int avaliable = check();
if (avaliable == 0)
{
waitForAvailable();
avaliable = check();
}
update(1);
}
finally
{
lock.unlock();
}
}
private void waitForAvailable()
{
long time = System.currentTimeMillis() - timestamp;
boolean isInterrupted = false;
while (time < INTERVAL)
{
try
{
Thread.sleep(INTERVAL - time);
}
catch (InterruptedException e)
{
isInterrupted = true;
break;
}
time = System.currentTimeMillis() - timestamp;
}
if (isInterrupted)
{
Thread.currentThread().interrupt();
}
}
private int check()
{
long now = System.currentTimeMillis();
if (now - timestamp >= INTERVAL)
{
timestamp = now;
currentbps = bytesread;
bytesread = 0;
return maxbps;
}
else
{
return maxbps - bytesread;
}
}
private void update(int n)
{
bytesread += n;
}
/**
* 获取当前当前的流速
* @return 流速
*/
public int getCurrentbps()
{
return currentbps;
}
/**
* {@inheritDoc}
*/
public String toString()
{
return "CurTPS:" + currentbps + ",MaxTPS:" + maxbps;
}
}
调用:
// 初始化流量
BandwidthAllocator locator = new BandwidthAllocator(contral);
List<***** > list = ***** (bean);
for (***** : list)
{
locator.allocate();
... 外部调用
...
}
2、JAVA实现并发的流控
利用Semaphore实现
可参考 https://blog.youkuaiyun.com/xiangwanpeng/article/details/79728227
这个参考 https://blog.youkuaiyun.com/Zhenxue_Xu/article/details/89293037 没看懂
https://blog.youkuaiyun.com/scherrer/article/details/51867873