java限频_单个用户及Ip请求频率限制思路(附java实现)
> 我們熟悉的限流算法漏桶和令牌桶外,很多情況我們還需要考慮當(dāng)個(gè)用戶(ip)訪問頻率控制,避免被惡意調(diào)用。如果是開放平臺限制一天調(diào)用多少次這種粗放的粒度相對好處理一些。如果需要更小時(shí)間粒度控制,譬如一個(gè)10秒時(shí)間窗口最大只允許訪問10次,相對上述粗放粒度我們還需要考慮性能和邊界兩個(gè)問題。在這里提供一種思路給大家,這個(gè)也是我寫的api網(wǎng)關(guān)訪問頻率控制的代碼,經(jīng)過了線上環(huán)境實(shí)踐。
推薦: jeesuite開發(fā)框架,免費(fèi)開源、一站式解決方案。
思路(以10秒限制10次為例)
定義一個(gè)全局map
key為用戶標(biāo)識(ip or sessionId),
value:List<10秒內(nèi)訪問時(shí)間戳>
private Map> accessDatas = new ConcurrentHashMap<>();
啟動一個(gè)定時(shí)器,用于清除10秒前的訪問時(shí)間
cleanScheduledExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
long currentTime = System.currentTimeMillis();
List < Long > accessPoints = null;
Iterator < String > idsIterator;
if (gloabalScanFlag == 5) {
//清理空記錄
if (cleanNulling = accessDatas.size() > cleanNullSize) {
log.debug("cleanNulling...");
Set < String > keys = accessDatas.keySet();
for (String key: keys) {
List < Long > points = accessDatas.get(key);
if (points.isEmpty()) {
points = null;
accessDatas.remove(key);
}
}
cleanNulling = false;
}
idsIterator = accessDatas.keySet().iterator();
gloabalScanFlag = 0;
} else {
idsIterator = maybeFullIds.iterator();
gloabalScanFlag++;
}
while (idsIterator.hasNext()) {
accessPoints = accessDatas.get(idsIterator.next());
//
removeExpirePoints(accessPoints, currentTime);
}
}
},
1000, 1000, TimeUnit.MILLISECONDS);
移除過期的請求時(shí)間戳記錄
private int removeExpirePoints(List ponits,long currentTimeMillis){
int removeNums = 0;
if(ponits == null || ponits.isEmpty()){
return removeNums;
}
Iterator pointsIterator = ponits.iterator();
while (pointsIterator.hasNext()) {
if(pointsIterator.next().compareTo(currentTimeMillis - timeWindowMillis) <= 0){
pointsIterator.remove();
removeNums++;
}else{
break;
}
}
return removeNums;
}
頻控檢查
/**
* 訪問頻率檢查
* @param identification 用戶標(biāo)識(ip or sessionId)
* @param uri
* @return
* @copyright http://www.jeesuite.com
*/
private boolean requestFrequencyCheck(String identification, String uri) {
while (cleanNulling);
boolean result = false;
long currentTime = System.currentTimeMillis();
List < Long > accessPoints = accessDatas.get(identification);
try {
if (accessPoints == null) {
accessPoints = new Vector < >(permits);
accessDatas.put(identification, accessPoints);
}
int size;
if ((size = accessPoints.size()) < permits) {
if (size >= putFullQueueSize) {
maybeFullIds.add(identification);
}
result = true;
} else {
int removeNums = removeExpirePoints(accessPoints, currentTime);
result = removeNums > 0;
}
return result;
} finally {
accessPoints.add(currentTime);
}
}
總結(jié)
以上是生活随笔為你收集整理的java限频_单个用户及Ip请求频率限制思路(附java实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中volatile的含义_jav
- 下一篇: java 带参数的构造函数_java –