最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實現網絡限速的詳細步驟

 更新時間:2026年06月11日 09:13:49   作者:小碼哥_常  
本文詳細介紹了網絡限速的重要性及常見限速策略,如固定窗口計數器、滑動窗口計數器、令牌桶算法和漏桶算法,并重點講解了如何在SpringBoot中使用AOP和令牌桶算法實現網絡限速,通過自定義注解、面向切面編程和測試驗證等步驟,需要的朋友可以參考下

 概述

本文介紹在 Spring Boot 3 中實現多維度網絡帶寬限速的完整方案。基于令牌桶算法手動實現核心邏輯,通過自定義 HandlerInterceptor 攔截請求、HttpServletResponseWrapper 包裝響應流、RateLimitedOutputStream 控制輸出速率,實現對文件下載、視頻流等場景的精確速度控制。

為什么需要帶寬限速

帶寬限速與常見的 API 限流不同:限流控制的是請求次數(如每分鐘100次),而限速控制的是網絡帶寬(如每秒200KB)。在實際應用中,帶寬限速有著重要的業(yè)務價值:

場景一:文件下載服務對于網盤或資源分發(fā)平臺,免費用戶限制在 200KB/s,VIP 用戶提升到 2MB/s,既能保障基礎體驗,又能激勵付費轉化。

場景二:視頻流媒體不同清晰度對應不同帶寬限制(480P 用 500KB/s,1080P 用 3MB/s),避免高碼率視頻占用過多服務器帶寬。

場景三:API 接口保護大數據量接口(如導出報表)如果沒有帶寬控制,單個請求可能占滿整個出口帶寬,影響其他用戶訪問。

核心原理:令牌桶算法

令牌桶算法是流量控制的經典方案,其思想非常直觀:想象一個桶,系統(tǒng)以固定速率向桶中放入令牌,請求數據時必須從桶中取走對應數量的令牌。

核心參數解析:

1. 桶容量(Capacity):決定能承受多大突發(fā)流量。容量為 200KB 時,即使桶已滿,最多也只能連續(xù)發(fā)送 200KB 數據,之后必須等待令牌補充。

2. 填充速率(Refill Rate):決定長期平均傳輸速度。每秒補充 200KB 令牌,意味著平均速度就是 200KB/s。

3. 分塊大小(Chunk Size):影響流量平滑度。將 8KB 數據拆分成 2KB×4 次寫入,每次寫入之間進行令牌檢查,比一次性寫入 8KB 更加平滑。

算法流程:

發(fā)送數據前:
1. 計算距離上次補充的時間差
2. 根據 時間差 × 填充速率 計算新增令牌數
3. 更新桶中令牌數(不超過容量上限)
發(fā)送數據時:
1. 檢查令牌是否足夠
2. 足夠:直接扣除令牌,發(fā)送數據
3. 不足:計算 (缺少令牌數 / 填充速率) 得到等待時間,精確等待后發(fā)送

技術設計

整體流程

本方案采用攔截器模式,在請求處理的早期階段完成限速組件的初始化,通過請求屬性傳遞包裝后的響應對象。

請求流程:
┌─────────────────────────────────────────────────────────────────────┐
│ 1. DispatcherServlet 分發(fā)請求                                       │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│ 2. BandwidthLimitInterceptor.preHandle()                            │
│    - 解析 @BandwidthLimit 注解                                      │
│    - 從 BandwidthLimitManager 獲取共享 TokenBucket                   │
│    - 創(chuàng)建 BandwidthLimitResponseWrapper 并存入 request attribute    │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│ 3. Controller 處理請求                                              │
│    - 通過 BandwidthLimitHelper.getLimitedResponse() 獲取包裝后的響應 │
│    - 向響應流寫入數據(自動觸發(fā)限速)                                │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│ 4. BandwidthLimitInterceptor.afterCompletion()                      │
│    - 清理資源,關閉流                                                │
└─────────────────────────────────────────────────────────────────────┘

為什么選擇 HandlerInterceptor

在 Spring Boot 中實現請求處理,有兩種常見方式:Filter 和 HandlerInterceptor。本方案選擇 HandlerInterceptor 的關鍵原因是:注解解析需要 HandlerMethod 對象

Filter 在 DispatcherServlet 之前執(zhí)行,此時還沒有確定具體的處理方法,無法獲取方法上的 @BandwidthLimit 注解。而 HandlerInterceptor 在處理器確定后執(zhí)行,可以通過 HandlerMethod 精確獲取方法級別和類級別的注解信息。

核心組件職責

組件

職責

@BandwidthLimit

聲明式注解,配置限速參數

BandwidthLimitInterceptor

攔截請求,解析注解,創(chuàng)建響應包裝器

BandwidthLimitManager

管理多維度限速桶(全局/API/用戶/IP)

BandwidthLimitResponseWrapper

包裝 HttpServletResponse,替換 OutputStream

RateLimitedOutputStream

實現限速邏輯,包裝 TokenBucket

TokenBucket

令牌桶算法實現

BandwidthLimitHelper

從請求屬性中獲取包裝后的響應對象

多維度限速實現

本方案支持四種限速維度,滿足不同業(yè)務場景需求:

全局限速(GLOBAL)

所有請求共享同一個限速桶,適合保護服務器整體出口帶寬。例如設置 10MB/s 全局限制,即使有100個并發(fā)下載,總帶寬也不會超過 10MB/s。

@BandwidthLimit(value = 200, unit = BandwidthUnit.KB, type = LimitType.GLOBAL)
@GetMapping("/download/global")
public void downloadGlobal(HttpServletResponse response) throws IOException {
    HttpServletResponse limitedResponse = BandwidthLimitHelper.getLimitedResponse(request, response);
    // 寫入數據...
}

API 維度限速(API)

每個接口路徑獨立限速,不同接口的流量互不影響。/api/file/download 限制 500KB/s,/api/video/stream 限制 2MB/s,兩個接口可以同時達到各自的速度上限。

@BandwidthLimit(value = 500, unit = BandwidthUnit.KB, type = LimitType.API)
@GetMapping("/download/file")
public void downloadFile(HttpServletResponse response) throws IOException {
    // 文件下載邏輯
}

@BandwidthLimit(value = 2048, unit = BandwidthUnit.KB, type = LimitType.API)
@GetMapping("/stream/video")
public void streamVideo(HttpServletResponse response) throws IOException {
    // 視頻流邏輯
}

用戶維度限速(USER)

根據用戶標識(如請求頭 X-User-Id)進行限速,每個用戶獨立計算帶寬。配合 free 和 vip 參數,可實現差異化服務:

@BandwidthLimit(value = 200, unit = BandwidthUnit.KB, type = LimitType.USER,
                free = 200, vip = 2048)
@GetMapping("/download/user")
public void downloadByUser(@RequestHeader("X-User-Type") String userType,
                           HttpServletResponse response) throws IOException {
    // 根據請求頭 X-User-Type 自動應用 200KB/s 或 2MB/s 限速
}

IP 維度限速(IP)

根據客戶端 IP 地址限速,防止單個 IP 占用過多帶寬。支持代理環(huán)境下的 IP 獲?。╔-Forwarded-For、X-Real-IP)。

@BandwidthLimit(value = 300, unit = BandwidthUnit.KB, type = LimitType.IP)
@GetMapping("/download/ip")
public void downloadByIp(HttpServletResponse response) throws IOException {
    // 每個獨立 IP 限制 300KB/s
}

關鍵代碼實現

1. 令牌桶核心算法

TokenBucket 的核心在于精確的時間計算和令牌補充。使用 System.nanoTime() 獲取納秒級時間戳,確保高精度速率控制。

public synchronized void acquire(long permits) {
    // 1. 補充令牌
    refill();
    // 2. 計算等待時間
    if (tokens >= permits) {
        tokens -= permits;
        return;
    }
    long deficit = permits - tokens;
    long waitNanos = (deficit * 1_000_000_000L) / refillRate;
    // 3. 精確等待
    sleepNanos(waitNanos);
    // 4. 等待后消費
    tokens = 0;
}
private void refill() {
    long now = System.nanoTime();
    long elapsedNanos = now - lastRefillTime;
    long newTokens = (elapsedNanos * refillRate) / 1_000_000_000L;
    tokens = Math.min(capacity, tokens + newTokens);
    lastRefillTime = now;
}

2. 響應包裝器

HttpServletResponseWrapper 是 Servlet 規(guī)范提供的響應包裝基類,通過覆蓋 getOutputStream() 方法返回自定義的限速輸出流。

public class BandwidthLimitResponseWrapper extends HttpServletResponseWrapper {
    private final TokenBucket sharedTokenBucket;  // 共享的令牌桶
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (limitedOutputStream == null && sharedTokenBucket != null) {
            // 使用共享 TokenBucket,確保多維度統(tǒng)計正確
            limitedOutputStream = new RateLimitedOutputStream(
                super.getOutputStream(),
                sharedTokenBucket,
                bandwidthBytesPerSecond
            );
        }
        return limitedOutputStream;
    }
}

3. 攔截器獲取包裝響應

攔截器在 preHandle 中創(chuàng)建響應包裝器,存儲到 request attribute,Controller 通過 BandwidthLimitHelper 獲取。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    BandwidthLimit annotation = findAnnotation(handler);
    if (annotation != null) {
        // 從 Manager 獲取共享 TokenBucket
        TokenBucket bucket = limitManager.getBucket(type, key, capacity, rate);
        // 創(chuàng)建包裝器并存儲
        BandwidthLimitResponseWrapper wrappedResponse =
            new BandwidthLimitResponseWrapper(response, bucket, bandwidthBytesPerSecond, chunkSize);
        request.setAttribute("BandwidthLimitWrappedResponse", wrappedResponse);
    }
    return true;
}

4. Controller 獲取限速響應

Controller 通過 BandwidthLimitHelper.getLimitedResponse() 獲取包裝后的響應,所有寫入操作都會自動限速。

@GetMapping("/download/global")
public void downloadGlobal(HttpServletRequest request, HttpServletResponse response) throws IOException {
    HttpServletResponse limitedResponse = BandwidthLimitHelper.getLimitedResponse(request, response);
    limitedResponse.setContentType("application/octet-stream");
    limitedResponse.setHeader("Content-Disposition", "attachment; filename=test.bin");
    // 寫入數據時自動限速
    limitedResponse.getOutputStream().write(data);
}

參數調優(yōu)指南

桶容量選擇

容量決定突發(fā)流量承受能力:

容量設置

突發(fā)能力

適用場景

速率 × 0.5

平滑,無突發(fā)

流量控制嚴格的場景

速率 × 1.0

允許 1 秒突發(fā)

默認推薦值

速率 × 2.0

允許 2 秒突發(fā)

需要良好首屏加載

// 注解配置
@BandwidthLimit(value = 200, unit = BandwidthUnit.KB, capacityMultiplier = 1.0)

分塊大小選擇

分塊大小影響流量平滑度,經驗公式:chunkSize = bandwidth / 50

帶寬

推薦分塊

理由

200 KB/s

1-4 KB

小分塊保證平滑

1 MB/s

4-8 KB

平衡平滑與性能

5 MB/s+

8-16 KB

減少系統(tǒng)調用開銷

// 自動計算(推薦)
@BandwidthLimit(value = 200, unit = BandwidthUnit.KB, chunkSize = -1)

// 手動指定
@BandwidthLimit(value = 200, unit = BandwidthUnit.KB, chunkSize = 4096)

總結

本文基于令牌桶算法,通過 HandlerInterceptor + HttpServletResponseWrapper,在 Spring Boot 中實現了多維度帶寬限速。

支持全局/API/用戶/IP 四種限速維度,提供實時統(tǒng)計監(jiān)控,適用于API接口保護、文件下載、視頻流等場景。

以上就是SpringBoot實現網絡限速的詳細步驟的詳細內容,更多關于SpringBoot網絡限速的資料請關注腳本之家其它相關文章!

相關文章

  • JVM創(chuàng)建對象及訪問定位過程詳解

    JVM創(chuàng)建對象及訪問定位過程詳解

    這篇文章主要介紹了JVM創(chuàng)建對象及訪問定位過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-12-12
  • Java多線程下載的實現方法

    Java多線程下載的實現方法

    復習多線程的時候,練習了下,順便記錄一下:
    2013-03-03
  • Mybatis使用collection映射一對多查詢分頁問題詳解

    Mybatis使用collection映射一對多查詢分頁問題詳解

    本文通過修改SQL查詢語句,解決了在分頁條件下關聯(lián)查詢多表時,多的一端數據不正確的問題,從而實現了正常的展示
    2025-12-12
  • Java按照List內存儲的對象的某個字段進行排序的實例

    Java按照List內存儲的對象的某個字段進行排序的實例

    下面小編就為大家?guī)硪黄狫ava按照List內存儲的對象的某個字段進行排序的實例。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Java解析Excel內容的方法

    Java解析Excel內容的方法

    這篇文章主要介紹了Java解析Excel內容的方法,實例分析了java解析excel文件的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • Spring實戰(zhàn)之Bean銷毀之前的行為操作示例

    Spring實戰(zhàn)之Bean銷毀之前的行為操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之Bean銷毀之前的行為操作,結合實例形式分析了spring在bean銷毀之前的行為相關設置與使用技巧,需要的朋友可以參考下
    2019-11-11
  • Java中對象的序列化方式克隆詳解

    Java中對象的序列化方式克隆詳解

    在學習編程的過程中,我覺得不止要獲得課本的知識,更多的是通過學習技術知識提高解決問題的能力,這樣我們才能走在最前方。這篇文章主要給大家介紹了Java中對象的序列化方式克隆,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • Java獲取此次請求URL以及服務器根路徑的方法

    Java獲取此次請求URL以及服務器根路徑的方法

    這篇文章主要介紹了Java獲取此次請求URL以及服務器根路徑的方法,需要的朋友可以參考下
    2015-08-08
  • rabbitmq使用springboot實現direct模式(最新推薦)

    rabbitmq使用springboot實現direct模式(最新推薦)

    這篇文章主要介紹了rabbitmq使用springboot實現direct模式,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • SpringBoot 快速實現 api 加密的方法

    SpringBoot 快速實現 api 加密的方法

    在項目中,為了保證數據的安全,我們常常會對傳遞的數據進行加密,常用的加密算法包括對稱加密(AES)和非對稱加密(RSA),本文給大家介紹SpringBoot 快速實現 api 加密,感興趣的朋友一起看看吧
    2023-10-10

最新評論

博罗县| 新兴县| 池州市| 恩平市| 宜兴市| 和平区| 本溪市| 竹山县| 祥云县| 仪陇县| 阿克陶县| 齐河县| 潞西市| 四会市| 交城县| 鄂尔多斯市| 临高县| 玉林市| 科技| 彩票| 玉田县| 图片| 新蔡县| 惠安县| 五寨县| 女性| 株洲县| 株洲市| 太白县| 固始县| 巴林右旗| 定州市| 上栗县| 阳原县| 天等县| 山阳县| 竹山县| 威信县| 洛阳市| 玛多县| 桐柏县|