java限频_单个用户及Ip请求频率限制思路(附java实现)
> 我們熟悉的限流算法漏桶和令牌桶外,很多情況我們還需要考慮當個用戶(ip)訪問頻率控制,避免被惡意調用。如果是開放平臺限制一天調用多少次這種粗放的粒度相對好處理一些。如果需要更小時間粒度控制,譬如一個10秒時間窗口最大只允許訪問10次,相對上述粗放粒度我們還需要考慮性能和邊界兩個問題。在這里提供一種思路給大家,這個也是我寫的api網關訪問頻率控制的代碼,經過了線上環境實踐。
推薦: jeesuite開發框架,免費開源、一站式解決方案。
思路(以10秒限制10次為例)
定義一個全局map
key為用戶標識(ip or sessionId),
value:List<10秒內訪問時間戳>
private Map> accessDatas = new ConcurrentHashMap<>();
啟動一個定時器,用于清除10秒前的訪問時間
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);
移除過期的請求時間戳記錄
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 用戶標識(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);
}
}
總結
以上是生活随笔為你收集整理的java限频_单个用户及Ip请求频率限制思路(附java实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中volatile的含义_jav
- 下一篇: java 带参数的构造函数_java –