欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java限流方法常見實(shí)現(xiàn)方案(單機(jī)限流和分布式限流)

 更新時(shí)間:2025年08月25日 10:38:49   作者:hqxstudying  
Java限流用于保護(hù)系統(tǒng)資源,分為單機(jī)(Guava/滑動窗口)和分布式(Redis+Lua)方案,核心算法包括固定窗口、令牌桶、漏桶等,推薦使用Sentinel等成熟框架實(shí)現(xiàn)動態(tài)流量控制,本文介紹Java限流方法常見實(shí)現(xiàn)方案(單機(jī)限流和分布式限流),感興趣的朋友一起看看吧

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

一、核心限流算法

無論哪種方案,底層通?;谝韵滤惴ǎ?/p>

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

二、單機(jī)限流實(shí)現(xiàn)(適用于單實(shí)例服務(wù))

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

Guava 提供了現(xiàn)成的RateLimiter工具類,適合快速實(shí)現(xiàn)單機(jī)限流。

依賴引入

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

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

// 1. 定義限流攔截器
public class RateLimitInterceptor implements HandlerInterceptor {
    // 每秒允許10個(gè)請求(令牌桶算法)
    private final RateLimiter rateLimiter = RateLimiter.create(10.0);
    @Override
    public 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 {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 對指定路徑生效(如所有接口)
        registry.addInterceptor(new RateLimitInterceptor())
                .addPathPatterns("/**");
    }
}

2. 基于滑動窗口的自定義實(shí)現(xiàn)

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

public class SlidingWindowLimiter {
    // 窗口大?。ê撩耄?
    private final long windowSize;
    // 窗口內(nèi)最大請求數(shù)
    private final int maxRequests;
    // 記錄每個(gè)時(shí)間片的請求數(shù)(key:時(shí)間片起始時(shí)間,value:請求數(shù))
    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();
        // 計(jì)算當(dāng)前窗口的起始時(shí)間
        long windowStart = now - windowSize;
        // 移除過期的時(shí)間片
        timeSliceCounts.keySet().removeIf(timestamp -> timestamp < windowStart);
        // 統(tǒng)計(jì)當(dāng)前窗口總請求數(shù)
        int totalRequests = timeSliceCounts.values().stream().mapToInt(Integer::intValue).sum();
        if (totalRequests < maxRequests) {
            // 記錄當(dāng)前時(shí)間片的請求(精確到100ms,可調(diào)整精度)
            long currentSlice = now - (now % 100);
            timeSliceCounts.put(currentSlice, timeSliceCounts.getOrDefault(currentSlice, 0) + 1);
            return true;
        }
        return false;
    }
}
// 使用示例(在Controller中)
@RestController
public class TestController {
    // 10秒內(nèi)最多允許5次請求(按IP限流)
    private final Map<String, SlidingWindowLimiter> ipLimiters = new ConcurrentHashMap<>();
    @GetMapping("/test")
    public String test(HttpServletRequest request) {
        String ip = request.getRemoteAddr();
        // 為每個(gè)IP創(chuàng)建獨(dú)立的限流器
        SlidingWindowLimiter limiter = ipLimiters.computeIfAbsent(ip, 
            k -> new SlidingWindowLimiter(10000, 5));
        if (!limiter.tryAcquire()) {
            return "IP:" + ip + " 請求過于頻繁";
        }
        return "請求成功";
    }
}

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

單機(jī)限流無法跨服務(wù)實(shí)例共享狀態(tài),分布式場景需借助中間件(如 Redis)實(shí)現(xiàn)全局計(jì)數(shù)。

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

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

Lua 腳本(限流邏輯)

-- 限流key(如:接口名:IP)
local key = KEYS[1]
-- 窗口大?。ê撩耄?
local windowSize = tonumber(ARGV[1])
-- 最大請求數(shù)
local maxRequests = tonumber(ARGV[2])
-- 當(dāng)前時(shí)間
local now = tonumber(ARGV[3])
-- 窗口起始時(shí)間
local windowStart = now - windowSize
-- 移除窗口外的請求記錄
redis.call('ZREMRANGEBYSCORE', key, 0, windowStart)
-- 統(tǒng)計(jì)當(dāng)前窗口內(nèi)的請求數(shù)
local currentCount = redis.call('ZCARD', key)
if currentCount < maxRequests then
    -- 記錄當(dāng)前請求時(shí)間戳
    redis.call('ZADD', key, now, now .. ':' .. math.random())
    -- 設(shè)置key過期時(shí)間(避免內(nèi)存泄漏)
    redis.call('EXPIRE', key, windowSize / 1000 + 1)
    return 1  -- 允許請求
end
return 0  -- 拒絕請求

Java 代碼調(diào)用

@Component
public class RedisRateLimiter {
    @Autowired
    private 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);
    }
    /**
     * 嘗試獲取請求權(quán)限
     * @param key 限流標(biāo)識(如:"api:test:192.168.1.1")
     * @param windowSize 窗口大?。ê撩耄?
     * @param maxRequests 最大請求數(shù)
     * @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 {
    @Autowired
    private RedisRateLimiter redisRateLimiter;
    @GetMapping("/test")
    public String test(HttpServletRequest request) {
        String ip = request.getRemoteAddr();
        String key = "api:test:" + ip;
        // 10秒內(nèi)最多5次請求
        boolean allowed = redisRateLimiter.tryAcquire(key, 10000, 5);
        if (!allowed) {
            return "請求過于頻繁,請稍后再試";
        }
        return "請求成功";
    }
}

四、成熟框架推薦

生產(chǎn)環(huán)境中,推薦使用現(xiàn)成的限流框架簡化開發(fā):

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

總結(jié)

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

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

到此這篇關(guān)于JAVA限流方法的文章就介紹到這了,更多相關(guān)java限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用itext導(dǎo)出PDF文本絕對定位(實(shí)現(xiàn)方法)

    java使用itext導(dǎo)出PDF文本絕對定位(實(shí)現(xiàn)方法)

    下面小編就為大家?guī)硪黄猨ava使用itext導(dǎo)出PDF文本絕對定位(實(shí)現(xiàn)方法)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • springboot項(xiàng)目接入天貓精靈語音功能

    springboot項(xiàng)目接入天貓精靈語音功能

    小編最近接手一個(gè)項(xiàng)目,涉及到天貓精靈的語音功能,今天小編通過本文給大家分享下springboot項(xiàng)目接入天貓精靈語音功能的詳細(xì)過程及實(shí)例代碼,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • java常用工具類 Date日期、Mail郵件工具類

    java常用工具類 Date日期、Mail郵件工具類

    這篇文章主要為大家詳細(xì)介紹了java常用工具類,包括Date日期、Mail郵件工具類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • java對象序列化與反序列化的默認(rèn)格式和json格式使用示例

    java對象序列化與反序列化的默認(rèn)格式和json格式使用示例

    這篇文章主要介紹了java對象序列化與反序列化的默認(rèn)格式和json格式使用示例,需要的朋友可以參考下
    2014-02-02
  • java編寫貪吃蛇小游戲

    java編寫貪吃蛇小游戲

    貪吃蛇是經(jīng)典手機(jī)游戲,既簡單又耐玩。通過控制蛇頭方向吃蛋,使得蛇變長,從而獲得積分。今天我們就來用java來實(shí)現(xiàn)下貪吃蛇小游戲,有需要的小伙伴可以參考下
    2015-03-03
  • springboot結(jié)合JWT實(shí)現(xiàn)單點(diǎn)登錄的示例

    springboot結(jié)合JWT實(shí)現(xiàn)單點(diǎn)登錄的示例

    本文主要介紹了springboot結(jié)合JWT實(shí)現(xiàn)單點(diǎn)登錄的示例,包括生成Token、驗(yàn)證Token及使用Redis存儲Token,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-01-01
  • SpringBoot+Redis使用AOP防止重復(fù)提交的實(shí)現(xiàn)

    SpringBoot+Redis使用AOP防止重復(fù)提交的實(shí)現(xiàn)

    本文主要介紹了SpringBoot+Redis使用AOP防止重復(fù)提交的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • SpringMVC中的異常處理機(jī)制詳解

    SpringMVC中的異常處理機(jī)制詳解

    SpringMVC提供了基于xml和基于注解的異常處理機(jī)制,一般情況下兩者都要進(jìn)行配置,xml異常處理機(jī)制主要用于處理xml方式產(chǎn)生的異常,注解異常處理機(jī)制主要用于處理基于注解方式產(chǎn)生的異常,這篇文章主要介紹了SpringMVC中的異常處理機(jī)制,需要的朋友可以參考下
    2024-05-05
  • 圖文詳解SpringBoot中Log日志的集成

    圖文詳解SpringBoot中Log日志的集成

    這篇文章主要給大家介紹了關(guān)于SpringBoot中Log日志的集成的相關(guān)資料,文中通過實(shí)例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12
  • springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案

    springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案

    這篇文章主要介紹了springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02

最新評論