JAVA限流方法

在 Java 項目中限制短時間內的頻繁訪問(即接口限流),是保護系統資源、防止惡意攻擊或高頻請求導致過載的重要手段。常見實現方案可分為單機限流分布式限流,以下是具體實現方式:

一、核心限流算法

無論哪種方案,底層通常基于以下算法:

  1. 固定窗口計數器:將時間劃分為固定窗口(如 1 秒),統計窗口內請求數,超過閾值則拒絕。
    • 優點:簡單易實現;缺點:窗口交界處可能出現 “突增流量”(如窗口邊緣允許雙倍閾值請求)。
  2. 滑動窗口:將固定窗口拆分為多個小窗口,實時滑動計算請求數,解決臨界問題。
  3. 令牌桶:勻速生成令牌放入桶中,請求需獲取令牌才能處理,支持突發流量(桶內令牌可累積)。
  4. 漏桶:請求先進入桶中,系統以固定速率處理,平滑流量波動(不支持突發流量)。

二、單機限流實現(適用于單實例服務)

1. 基于 Guava 的 RateLimiter(令牌桶算法)

Guava 提供了現成的RateLimiter工具類,適合快速實現單機限流。

依賴引入

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version>
</dependency>

代碼示例(結合 Spring 攔截器)

// 1. 定義限流攔截器
public class RateLimitInterceptor implements HandlerInterceptor {// 每秒允許10個請求(令牌桶算法)private final RateLimiter rateLimiter = RateLimiter.create(10.0);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 嘗試獲取令牌,無令牌則拒絕if (!rateLimiter.tryAcquire()) {response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());response.getWriter().write("請求過于頻繁,請稍后再試");return false;}return true;}
}// 2. 注冊攔截器(Spring配置)
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 對指定路徑生效(如所有接口)registry.addInterceptor(new RateLimitInterceptor()).addPathPatterns("/**");}
}
2. 基于滑動窗口的自定義實現

適合需要更精細控制的場景(如按 IP 限流):

public class SlidingWindowLimiter {// 窗口大小(毫秒)private final long windowSize;// 窗口內最大請求數private final int maxRequests;// 記錄每個時間片的請求數(key:時間片起始時間,value:請求數)private final ConcurrentHashMap<Long, Integer> timeSliceCounts = new ConcurrentHashMap<>();public SlidingWindowLimiter(long windowSize, int maxRequests) {this.windowSize = windowSize;this.maxRequests = maxRequests;}public synchronized boolean tryAcquire() {long now = System.currentTimeMillis();// 計算當前窗口的起始時間long windowStart = now - windowSize;// 移除過期的時間片timeSliceCounts.keySet().removeIf(timestamp -> timestamp < windowStart);// 統計當前窗口總請求數int totalRequests = timeSliceCounts.values().stream().mapToInt(Integer::intValue).sum();if (totalRequests < maxRequests) {// 記錄當前時間片的請求(精確到100ms,可調整精度)long currentSlice = now - (now % 100);timeSliceCounts.put(currentSlice, timeSliceCounts.getOrDefault(currentSlice, 0) + 1);return true;}return false;}
}// 使用示例(在Controller中)
@RestController
public class TestController {// 10秒內最多允許5次請求(按IP限流)private final Map<String, SlidingWindowLimiter> ipLimiters = new ConcurrentHashMap<>();@GetMapping("/test")public String test(HttpServletRequest request) {String ip = request.getRemoteAddr();// 為每個IP創建獨立的限流器SlidingWindowLimiter limiter = ipLimiters.computeIfAbsent(ip, k -> new SlidingWindowLimiter(10000, 5));if (!limiter.tryAcquire()) {return "IP:" + ip + " 請求過于頻繁";}return "請求成功";}
}

三、分布式限流(適用于多實例集群)

單機限流無法跨服務實例共享狀態,分布式場景需借助中間件(如 Redis)實現全局計數。

基于 Redis + Lua 腳本(滑動窗口算法)

利用 Redis 的原子性和 Lua 腳本保證限流邏輯的一致性:

Lua 腳本(限流邏輯)

-- 限流key(如:接口名:IP)
local key = KEYS[1]
-- 窗口大小(毫秒)
local windowSize = tonumber(ARGV[1])
-- 最大請求數
local maxRequests = tonumber(ARGV[2])
-- 當前時間
local now = tonumber(ARGV[3])-- 窗口起始時間
local windowStart = now - windowSize-- 移除窗口外的請求記錄
redis.call('ZREMRANGEBYSCORE', key, 0, windowStart)
-- 統計當前窗口內的請求數
local currentCount = redis.call('ZCARD', key)if currentCount < maxRequests then-- 記錄當前請求時間戳redis.call('ZADD', key, now, now .. ':' .. math.random())-- 設置key過期時間(避免內存泄漏)redis.call('EXPIRE', key, windowSize / 1000 + 1)return 1  -- 允許請求
endreturn 0  -- 拒絕請求

Java 代碼調用

@Component
public class RedisRateLimiter {@Autowiredprivate StringRedisTemplate redisTemplate;// 加載Lua腳本private final DefaultRedisScript<Long> limitScript;public RedisRateLimiter() {limitScript = new DefaultRedisScript<>();limitScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("limit.lua")));limitScript.setResultType(Long.class);}/*** 嘗試獲取請求權限* @param key 限流標識(如:"api:test:192.168.1.1")* @param windowSize 窗口大小(毫秒)* @param maxRequests 最大請求數* @return 是否允許*/public boolean tryAcquire(String key, long windowSize, int maxRequests) {Long result = redisTemplate.execute(limitScript,Collections.singletonList(key),String.valueOf(windowSize),String.valueOf(maxRequests),String.valueOf(System.currentTimeMillis()));return result != null && result == 1;}
}// 在Controller中使用
@RestController
public class TestController {@Autowiredprivate RedisRateLimiter redisRateLimiter;@GetMapping("/test")public String test(HttpServletRequest request) {String ip = request.getRemoteAddr();String key = "api:test:" + ip;// 10秒內最多5次請求boolean allowed = redisRateLimiter.tryAcquire(key, 10000, 5);if (!allowed) {return "請求過于頻繁,請稍后再試";}return "請求成功";}
}

四、成熟框架推薦

生產環境中,推薦使用現成的限流框架簡化開發:

  1. Sentinel:阿里開源的流量控制框架,支持限流、熔斷、降級,可通過注解或配置中心動態調整規則。
  2. Resilience4j:輕量級熔斷限流框架,支持令牌桶、滑動窗口等多種算法,適合 Spring Boot 項目。
  3. Spring Cloud Gateway:網關層限流(如基于 Redis 的RequestRateLimiter過濾器),適合在入口層統一限流。

總結

  • 單機服務:優先使用 Guava 的RateLimiter或自定義滑動窗口(簡單場景)。
  • 分布式服務:必須基于 Redis 等中間件實現全局限流,配合 Lua 腳本保證原子性。
  • 復雜場景:直接集成 Sentinel 等成熟框架,減少重復開發并支持動態配置。

根據業務需求(如限流粒度:IP / 用戶 / 接口、是否允許突發流量)選擇合適的方案即可。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94294.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94294.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94294.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

性能比拼: .NET (C#) vs. Fiber (Go)

本內容是對知名性能評測博主 Anton Putra .NET (C#) vs. Fiber (Go): Performance (Latency - Throughput - Saturation - Availability) 內容的翻譯與整理, 有適當刪減, 相關指標和結論以原作為準 在本視頻中&#xff0c;我們將對比 C# 與 .NET 框架和 Golang 的表現。在第一個…

信譽代幣的發行和管理機制是怎樣的?

信譽代幣的發行與管理機制是區塊鏈技術與經濟模型深度融合的產物&#xff0c;其核心在于通過代碼和社區共識構建可量化、可驗證的信任體系。以下從技術架構、經濟模型、治理機制三個維度展開分析&#xff0c;并結合具體案例說明&#xff1a;一、發行機制&#xff1a;行為即價值…

神經網絡|(十二)概率論基礎知識-先驗/后驗/似然概率基本概念

【1】引言 前序學習進程中&#xff0c;對貝葉斯公式曾經有相當粗糙的回歸&#xff0c;實際上如果我們看教科書或者網頁&#xff0c;在講貝葉斯公式的時候&#xff0c;會有幾個名詞反復轟炸&#xff1a;先驗概率、后驗概率、似然概率。 今天就來把它們解讀一下&#xff0c;為以…

使用UE5開發《紅色警戒3》類戰略養成游戲的硬件配置指南

從零開始&#xff0c;學習 虛幻引擎5&#xff08;UE5&#xff09;&#xff0c;開始游戲開發之旅&#xff01;本文章僅提供學習&#xff0c;切勿將其用于不法手段&#xff01;開發類似《紅色警戒3》級別的戰略養成游戲&#xff0c;其硬件需求遠超普通2D或小型3D項目——這類游戲…

Vue2+Vue3前端開發_Day12-Day14_大事件管理系統

參考課程: 【黑馬程序員 Vue2Vue3基礎入門到實戰項目】 [https://www.bilibili.com/video/BV1HV4y1a7n4] ZZHow(ZZHow1024) 項目收獲 Vue3 composition APIPinia / Pinia 持久化處理Element Plus&#xff08;表單校驗&#xff0c;表格處理&#xff0c;組件封裝&#xff09…

[ACTF新生賽2020]明文攻擊

BUUCTF在線評測BUUCTF 是一個 CTF 競賽和訓練平臺&#xff0c;為各位 CTF 選手提供真實賽題在線復現等服務。https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]%E6%98%8E%E6%96%87%E6%94%BB%E5%87%BB下載查看&#xff0c;一個壓縮包和一張圖片。壓縮包需要密…

關于日本服務器的三種線路講解

租用日本服務器時&#xff0c;哪種線路選擇更適合?當初次接觸跨境業務的站長們著手租用日本服務器時&#xff0c;會發現不同服務商提供的網絡線路五花八門&#xff0c;從陌生的運營商名稱到復雜的技術參數&#xff0c;常常使其感到眼花繚亂。為了幫助大家理清思路&#xff0c;…

【大白話解析】 OpenZeppelin 的 MerkleProof 庫:Solidity 默克爾證明驗證工具全指南??(附源代碼)

?? 一、Merkle Tree 是什么?為什么要驗證它? 想象你有一個名單,比如: ["Alice", "Bob", "Charlie", "Dave"] 你想讓別人驗證:“我(比如 Alice)是不是在這個名單里?”,但不想把整個名單都放在區塊鏈上(太貴!)。 于是你…

機械學習綜合練習項目

數據集合完整項目文件已經上傳一、項目介紹案例介紹 案例是針對“紅酒.csv”數據集&#xff0c;在紅葡萄酒質量分析的場景 中&#xff0c;利用多元線性回歸來探索紅葡萄酒的不同化學成分如何共同 影響其質量評分。在建立線性回歸模型之后&#xff0c;當給出了紅葡萄酒 的新的一…

第3篇:配置管理的藝術 - 讓框架更靈活

前言 在前一章中&#xff0c;我們設計了強大的注解API。本章將深入探討配置管理系統的設計&#xff0c;學習如何將注解中的聲明式配置轉換為運行時可用的配置對象。 配置管理的核心挑戰 在我們的框架中&#xff0c;配置來源有三個層級&#xff1a;主要挑戰&#xff1a; &#x…

發版混亂怎么規范

你是否經歷過這種場景&#xff1a;臨到發版&#xff0c;一堆功能代碼擠在一起&#xff0c;測試分不清范圍&#xff0c;修復一個Bug可能引發三個新Bug&#xff1f;發布過程像一場豪賭&#xff1f;問題的核心往往在于分支策略和流程的混亂。今天&#xff0c;我們就來建立一套在絕…

【golang長途旅行第30站】channel管道------解決線程競爭的好手

channel 為什么需要channel 使用全局變量加鎖同步來解決goroutine的競爭&#xff0c;可以但不完美難以精確控制等待時間?&#xff08;主線程無法準確知道所有 goroutine 何時完成&#xff09;。全局變量容易引發競態條件?&#xff08;即使加鎖&#xff0c;代碼復雜度也會增加…

蘋果XR芯片介紹

蘋果的 XR 芯片技術主要體現在 A 系列、M 系列處理器以及專為空間計算設計的 R1 協處理器中。以下從技術架構、產品迭代和綜合對比三個維度展開分析&#xff1a;一、技術架構解析1. A 系列芯片&#xff08;以 A12 Bionic 為例&#xff09;制程工藝&#xff1a;7nm&#xff08;臺…

達夢數據庫巡檢常用SQL(三)

達夢數據庫巡檢常用SQL(三) 數據庫SQL運行檢查 數據庫SQL運行檢查 死鎖的事務情況: SELECT TO_CHAR(HAPPEN_TIME,YYYY-MM-DD HH24:MI:SS) HAPPEN_TIME,SQL_TEXT FROM V$DEADLOCK_HISTORY WHERE HAPPEN_TIME >DATEADD(DAY,-30,

基于SpringBoot的校園周邊美食探索及分享平臺

1. 項目簡介 項目名稱&#xff1a;校園周邊美食探索及分享平臺 項目背景&#xff1a;針對校園師生對周邊美食信息的需求&#xff0c;構建一個集美食推薦、鑒賞、評論互動及社交功能于一體的平臺&#xff0c;幫助用戶發現優質美食資源并進行分享交流。 主要目標&#xff1a; 提供…

Go數據結構與算法-常見的排序算法

雖然看過別人寫了很多遍&#xff0c;而且自己也寫過很多遍&#xff08;指的是筆記&#xff09;&#xff0c;但是還是要寫的就是排序算法。畢竟是初學Go語言&#xff0c;雖然之前寫過&#xff0c;但是還是打算再寫一遍。主要包括插入排序、選擇排序、冒泡排序、快速排序、堆排序…

第 6 篇:目標規則與負載均衡 - `DestinationRule` 詳解

系列文章:《Istio 服務網格詳解》 第 6 篇:目標規則與負載均衡 - DestinationRule 詳解 本篇焦點: 深入理解 DestinationRule 的核心作用:定義流量在到達目的地之后的行為。 詳細剖析其三大核心功能:服務子集 (Subsets), 流量策略 (Traffic Policy), TLS 設置。 動手實戰…

一個簡潔的 C++ 日志模塊實現

一個簡潔的 C 日志模塊實現 1. 引言 日志功能在軟件開發中扮演著至關重要的角色&#xff0c;它幫助開發者追蹤程序執行過程、診斷問題以及監控系統運行狀態。本文介紹一個使用 C 實現的輕量級日志模塊&#xff0c;該模塊支持多日志級別、線程安全&#xff0c;并提供了簡潔易用…

C語言---數據類型

文章目錄數據類型分類1. 基本類型 (Basic Types)a. 整數類型 (Integer Types)char (字符型)int (整型)short (短整型)long (長整型)long long (C99標準引入)圖片匯總b. 浮點類型 (Floating-Point Types)float (單精度浮點型)double (雙精度浮點型)long double (長雙精度浮點型)…

本搭建烏云漏洞庫

1.下載鏡像站文件&#xff0c;并拖入虛擬機 2.將bugs.rar解壓至網站根目錄下 /var/www/html 3.配置bugs/conn.php 4.在bugs下創建upload目錄&#xff0c;將10-14、15-a、15-b、16壓縮包文件解壓到該upload目錄 5.把wooyun.rar解壓到 /mysql/data/wooyun目錄下 6.配置hosts文件后…