springboot下載接口限速功能實現(xiàn)
當(dāng)然可以!我們來結(jié)合你提供的代碼和限速邏輯,詳細(xì)說明整個“下載限速”功能是如何實現(xiàn)的。
?? 一、整體目標(biāo)
我們要實現(xiàn)的功能是:
限制每個用戶的下載速度(例如1MB/s),并根據(jù)當(dāng)前并發(fā)下載用戶數(shù)動態(tài)調(diào)整限速值。
?? 二、涉及的主要類/方法
| 類/方法 | 功能 |
|---|---|
FileUtil.limitDownloadSpeed(...) | 核心限速方法,控制每秒發(fā)送的數(shù)據(jù)量 |
download(...) | 下載入口,獲取文件路徑、設(shè)置響應(yīng)頭等 |
limitReadFile(...) | 調(diào)用限速方法執(zhí)行下載 |
| Redis 操作 | 統(tǒng)計并發(fā)下載數(shù),用于動態(tài)限速 |
? 三、核心流程圖解(簡化)
客戶端發(fā)起請求
↓
download(...) 方法被調(diào)用
↓
從 Redis 增加并發(fā)數(shù) DOWNLOAD_CONCURRENT_KEY
↓
根據(jù)并發(fā)數(shù)計算限速值(getDownloadSpeedLimit)
↓
調(diào)用 limitReadFile(...) 開始下載文件
↓
limitReadFile(...) 內(nèi)部調(diào)用 FileUtil.limitDownloadSpeed(...)
↓
讀取文件內(nèi)容 → 分段寫入輸出流 → 控制每秒發(fā)送的數(shù)據(jù)量
↓
下載完成或客戶端斷開連接
↓
finally 中減少 Redis 的并發(fā)數(shù)?? 四、關(guān)鍵代碼詳解
1?? 設(shè)置并發(fā)數(shù) + 獲取限速值(download(...) 方法中)
// 增加并發(fā)計數(shù)器 Long currentConcurrent = redisTemplate.opsForValue().increment(DOWNLOAD_CONCURRENT_KEY); // 更新過期時間 redisTemplate.expire(DOWNLOAD_CONCURRENT_KEY, EXPIRE_TIME_IN_SECONDS, TimeUnit.SECONDS); // 計算限速值 int speedLimit = getDownloadSpeedLimit(currentConcurrent.intValue());
increment(...):將 Redis 中的鍵值增加 1,表示有新的下載開始。expire(...):為這個 key 設(shè)置過期時間,防止僵尸數(shù)據(jù)。getDownloadSpeedLimit(...):根據(jù)當(dāng)前并發(fā)數(shù)計算單個用戶的限速值。
2?? 限速策略函數(shù) getDownloadSpeedLimit(...)
private int getDownloadSpeedLimit(int concurrentCount) {
int totalBandwidth = 1024 * 1024 * 5; // 總帶寬 5MB/s
int perUserSpeed = totalBandwidth / Math.max(1, concurrentCount);
return Math.max(perUserSpeed, 1024 * 50); // 最低限速 50KB/s
}- 如果當(dāng)前只有 1 個用戶下載,那他可以使用全部 5MB/s;
- 如果有 5 個用戶同時下載,每人最多只能用到 1MB/s;
- 即使并發(fā)數(shù)很多,也保證最低 50KB/s,避免卡死。
3?? 實際限速邏輯(FileUtil.limitDownloadSpeed(...))
public static void limitDownloadSpeed(InputStream in, OutputStream out, int bytesPerSecond) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE]; // 默認(rèn)是 1024 字節(jié)
int bytesRead;
long bytesSent = 0;
long startTime = System.currentTimeMillis();
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
bytesSent += bytesRead;
if (bytesSent >= bytesPerSecond) {
long elapsedTime = System.currentTimeMillis() - startTime;
if (elapsedTime < 1000) {
Thread.sleep(1000 - elapsedTime);
}
bytesSent = 0;
startTime = System.currentTimeMillis();
}
}
}這段代碼的核心邏輯是:
- 每次從輸入流讀取一塊數(shù)據(jù)(默認(rèn) 1KB);
- 將這塊數(shù)據(jù)寫入輸出流(即發(fā)給客戶端);
- 累計已發(fā)送的字節(jié)數(shù);
- 如果累計發(fā)送的數(shù)據(jù)超過設(shè)定的
bytesPerSecond(如 1MB),就判斷這一秒還沒過去,那么線程休眠剩余時間; - 重置計數(shù)器和開始時間,進(jìn)入下一輪循環(huán)。
示例:限速 1MB/s
- 第一次循環(huán):
- 讀取了 1024 × 1000 = 1MB 數(shù)據(jù);
- 發(fā)送完后發(fā)現(xiàn)只用了 500ms;
- 休眠 500ms;
- 清空計數(shù)器,重新開始下一秒的限速。
這樣就能保證 每秒最多發(fā)送 1MB 數(shù)據(jù)。
?? 五、如何做到“并發(fā)越多,限速越小”?
舉個例子:
| 并發(fā)數(shù) | 總帶寬(假設(shè)) | 每人可用帶寬 |
|---|---|---|
| 1 | 5MB/s | 5MB/s |
| 2 | 5MB/s | 2.5MB/s |
| 5 | 5MB/s | 1MB/s |
| 10 | 5MB/s | 500KB/s |
| 100 | 5MB/s | 50KB/s(最小限制) |
通過這種方式,系統(tǒng)會自動平衡所有用戶的下載速度,不會因為某一個用戶占用過多帶寬而導(dǎo)致其他用戶下載很慢。
?? 六、完整流程總結(jié)
| 步驟 | 描述 |
|---|---|
| 1. 客戶端請求下載 | 請求 /file/download/[code] |
| 2. 服務(wù)器記錄并發(fā)數(shù) | 使用 Redis INCR 增加并發(fā)計數(shù) |
| 3. 計算限速值 | 根據(jù)并發(fā)數(shù)平均分配總帶寬 |
| 4. 執(zhí)行限速下載 | 使用 limitDownloadSpeed(...) 控制每秒發(fā)送的字節(jié)數(shù) |
| 5. 客戶端中斷或下載完成 | 使用 FINALLY 減少 Redis 中的并發(fā)數(shù) |
| 6. 自動清理 | Redis key 設(shè)置了過期時間,防止數(shù)據(jù)殘留 |
? 七、優(yōu)點總結(jié)
| 特性 | 是否支持 | 說明 |
|---|---|---|
| 靜態(tài)限速 | ? 是 | 可以為每個用戶固定限速 |
| 動態(tài)限速 | ? 是 | 根據(jù)并發(fā)數(shù)自動調(diào)整限速 |
| Redis 支持 | ? 是 | 實現(xiàn)并發(fā)統(tǒng)計 |
| 異常安全 | ? 是 | finally 中釋放資源 |
| 可擴展性強 | ? 是 | 可加入 VIP 用戶、IP 限速等功能 |
?? 八、可選優(yōu)化建議(進(jìn)階)
| 優(yōu)化點 | 說明 |
|---|---|
| 緩沖區(qū)增大 | 把 BUFFER_SIZE 改成 64KB 或 128KB 提升性能 |
| 更精細(xì)限速 | 每 100ms 控制一次限速,而不是每秒 |
| VIP 用戶優(yōu)先 | 不同用戶組使用不同限速策略 |
| 斷點續(xù)傳 | 支持 Range 請求頭,允許暫停繼續(xù)下載 |
| 日志記錄 | 記錄每次下載的 IP、速度、時長等信息 |
| 帶寬監(jiān)控 | 顯示實時帶寬使用情況、并發(fā)數(shù)等 |
?? 九、結(jié)語
你現(xiàn)在擁有的是一套完整的、可落地的 “并發(fā)感知型下載限速系統(tǒng)”,它具備以下特點:
- ? 支持靜態(tài)限速
- ? 支持動態(tài)限速(基于并發(fā))
- ? 使用 Redis 統(tǒng)計并發(fā)
- ? 限速邏輯清晰高效
- ? 安全可靠,異常處理完善
如果你希望我?guī)湍氵M(jìn)一步擴展功能,比如:
- 支持 VIP 用戶限速更高
- 加入日志記錄模塊
- 實現(xiàn)斷點續(xù)傳
- 添加帶寬監(jiān)控頁面
到此這篇關(guān)于springboot下載接口限速功能實現(xiàn)的文章就介紹到這了,更多相關(guān)springboot下載限速內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring boot與spring mvc的區(qū)別及功能介紹
這篇文章主要介紹了spring boot與spring mvc的區(qū)別是什么以及spring boot和spring mvc功能介紹,感興趣的朋友一起看看吧2018-02-02
SpringBoot整合iText7導(dǎo)出PDF及性能優(yōu)化方式
在SpringBoot項目中整合iText7庫以導(dǎo)出PDF文件,不僅能夠滿足報告生成需求,而且可以處理復(fù)雜的文檔布局與樣式,整合步驟包括添加Maven依賴、編寫PDF生成代碼,性能優(yōu)化方面,建議使用流式處理、緩存樣式與字體、優(yōu)化HTML/CSS結(jié)構(gòu)、采用異步處理2024-09-09
Java編程使用Runtime和Process類運行外部程序的方法
這篇文章主要介紹了Java編程使用Runtime和Process類運行外部程序的方法,結(jié)合實例形式分析了java使用Runtime.getRuntime().exec()方法運行外部程序的常見情況與操作技巧,需要的朋友可以參考下2017-08-08
微信開發(fā)準(zhǔn)備第二步 springmvc mybatis項目結(jié)構(gòu)搭建
這篇文章主要為大家詳細(xì)介紹了微信開發(fā)準(zhǔn)備第二步,springmvc和mybatis項目結(jié)構(gòu)的搭建,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
JDK8時間相關(guān)類超詳細(xì)總結(jié)(含多個實例)
jdk1.8的一些新特性簡化了代碼的寫法,減少了部分開發(fā)量,下面這篇文章主要給大家介紹了關(guān)于JDK8時間相關(guān)類超詳細(xì)總結(jié),文中包含了多個實例代碼,需要的朋友可以參考下2023-01-01
解決mybatisplus的分頁插件和條件構(gòu)造器自定義SQL遇到的BUG
這篇文章主要介紹了解決mybatisplus的分頁插件和條件構(gòu)造器自定義SQL遇到的BUG,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
SpringBoot Mybatis多數(shù)據(jù)源配置全過程
本文詳細(xì)介紹了如何在Java項目中配置多數(shù)據(jù)源,包括配置文件設(shè)置、多數(shù)據(jù)源配置類、MyBatis配置等,通過兩種不同的方式配置primary和secondary數(shù)據(jù)源,展示了如何處理Mapper接口文件和.xml文件不在同一目錄下的情況,并使用@Primary注解指定默認(rèn)數(shù)據(jù)源2025-11-11

