您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“java如何實現單機接口限流”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“java如何實現單機接口限流”這篇文章吧。
簡單說就是設定某個接口一定時間只接受固定次數的請求,比如/add接口1秒最多接收100次請求,多的直接拒絕,這個問題很常見,場景也好理解,直接上代碼:
/** * 單機限流 */ @Slf4j public class FlowLimit { //接口限流上限值和限流時間緩存 private static Cache<String, AtomicLong> localCache = CacheBuilder.newBuilder().maximumSize(100) .expireAfterWrite(1000, TimeUnit.MILLISECONDS).build(); //每個接口的上限緩存 private static Map<String, Long> maxFlowLimitMap = new ConcurrentHashMap<>(); private static final FlowLimit instance = new FlowLimit(); //這塊的目的是初始化每個接口的上限,下面的變量:apiFlowLimitConfigure //實際使用的時候應該是從db或者其他地方獲取設置的每個接口的限流上限值, //這樣可以動態的調整接口上限,比如直接修改db,不用發布,就可以調整接口限流值 static { new ScheduledThreadPoolExecutor(1, runnable -> { Thread thread = new Thread(runnable, "api-flowLimit-configure"); // thread.setDaemon(true); return thread; }).scheduleAtFixedRate(() -> { try { String apiFlowLimitConfigure = "{\"doAdd\":100}"; //表示/doAdd接口1秒接受100次請求 Map mapObj = JSONObject.parseObject(apiFlowLimitConfigure, Map.class); if(mapObj != null){ mapObj.forEach((key, value) -> { if(value != null){ instance.setMaxFlowLimit(key.toString(), new Long(value.toString())); }else{ log.warn(key + " - 設置接口限流發現限流值為空,設置默認值"); instance.setMaxFlowLimit(key.toString(), 100L); } }); } } catch (Exception e) { log.error("設置接口限流出現異常{}", e); } }, 0, 3, TimeUnit.SECONDS); } public static FlowLimit getInstance() { return instance; } private FlowLimit setMaxFlowLimit(String key, Long maxFlowLimit) { maxFlowLimitMap.put(key, maxFlowLimit); return this; } public Boolean isAvailable(String key) { return checkAvailable(key, 1L); } public Boolean isAvailable(String key, Long incrNum) { return checkAvailable(key, incrNum); } private Boolean checkAvailable(String key, Long incrNum){ Long maxFlowLimit = maxFlowLimitMap.get(key); if (null == maxFlowLimit || maxFlowLimit == 0) { return true; } if (incrAndGet(key, incrNum) <= maxFlowLimit.longValue()) { return true; } else { return false; } } private long incrAndGet(String key, final long n) { try { return localCache.get(key, new Callable<AtomicLong>() { @Override public AtomicLong call() throws Exception { return new AtomicLong(0); } }).addAndGet(n); } catch (Exception e) { log.error(e.getMessage(), e); } return 0; } public long get(String key) { return incrAndGet(key, 0); } }
上面這個就是單機限流邏輯,代碼不難,感覺沒必要使用ConcurrentHashMap,不過感覺無所謂了
這段代碼只需要加在需要限流的接口前面:
@GetMapping("doAdd") public Boolean doAdd(){ FlowLimit instance = FlowLimit.getInstance(); //單例獲取 //查看當前的/doAdd接口是否觸發了限流 Boolean flowLimitFlag = instance.isAvailable("doAdd"); if(!flowLimitFlag){ log.warn("觸發限流,拒絕請求"); return false; } //doAdd() return true; }
調用實例如上
上面這個限流其實是有一定問題的:比如你限定10秒鐘1000次,在第9.9秒的時候,突然進來1000個請求,然后第10.1秒的時候,攻擊者,又進來1000次請求,這樣,0.2秒之內,進來2000次請求。。。
所以這個時候就需要令牌桶或者其他算法了,其他算法后面再寫
以上是“java如何實現單機接口限流”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。