成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

HTTP客戶端實現請求QPS的控制,你學會了嗎?

開發 項目管理
結語QPS控制是保障系統穩定性的重要環節。選擇方案時需結合業務場景、技術成本和擴展性。通過客戶端與服務端的雙重限流,配合監控與報警,可有效避免因QPS超限導致的服務不可用。

背景:高德API調用QPS限制引發的問題

最近在項目中使用高德API進行地址轉坐標時,頻繁遇到CUQPS_HAS_EXCEEDED_THE_LIMIT錯誤。這是因為API對每秒請求量(QPS)有嚴格限制(如高德地圖API默認QPS為3)。當客戶端請求速度超過限制時,服務端會直接拒絕請求。為解決這一問題,我們需要在客戶端實現QPS控制,確保請求速率符合服務端要求。

一、當前實現方案

ScheduledExecutorService + Semaphore

我們采用信號量(Semaphore)與定時任務(ScheduledExecutorService)結合的方式控制QPS:

  1. 信號量:初始化為允許的最大并發數(如100)。
  2. 定時任務:每秒重置信號量許可數量,確保QPS不超過限制。

簡單實現:

public class QpsTaskCtrl {
  
    private final Semaphore semaphore;
    private final ScheduledExecutorService scheduler;

    public QpsTaskScheduler(int qps) {
        this.semaphore = new Semaphore(qps);

        this.scheduler = Executors.newScheduledThreadPool(1);

        this.scheduler.scheduleAtFixedRate(() -> {
            if( semaphore.availablePermits() >= qps ){
                semaphore.drainPermits();
            }
            semaphore.release();
        }, 0, 1000/qps, TimeUnit.MILLISECONDS);
    }

    public <T> T execute(Callable<T> callable){
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            LOGGER.error("Failed to acquire semaphore", e);
        }

        T result = null;
        try {
            result = callable.call();
        } catch (Exception e) {
            LOGGER.error("Failed to execute task", e);
            semaphore.release();
        } finally {

        }
        return result;
    }
}

測試

public static void main(String[] args) throws Exception {
        QpsTaskScheduler scheduler = new QpsTaskScheduler(3);
        for (int i = 0; i < 20; i++) {
            String testUrl = "https://jsonplaceholder.typicode.com/todos/"+ DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
            Request req = new Request.Builder().url(testUrl).build();
            Response res = scheduler.execute(()->{
                return new OkHttpClient().newCall(req).execute();
            });
            System.out.println( res );
        }
}

優點:

  • 實現簡單,無需引入外部依賴。
  • 適用于單機場景。

缺點:

  • 定時任務可能因延遲導致信號量重置不及時。
  • 無法應對突發流量(如瞬時高并發)。
  • 分布式場景下需額外同步機制。

二、其他QPS控制方案及對比

除上述方案外,常見的QPS控制方法還包括:

1. 漏桶算法(Leaky Bucket)

  • 原理:請求進入“漏桶”,以固定速率流出。若桶滿則拒絕請求。
  • 實現:使用隊列存儲請求,定時任務按QPS處理隊列。
  • 優點:嚴格控制請求速率,平滑流量。
  • 缺點:無法利用突發流量(如短時間內允許更多請求)。

2. 令牌桶算法(Token Bucket)

  • 原理:每秒生成固定數量令牌,請求需消耗令牌。若令牌不足則等待或拒絕。
  • 實現:使用Guava RateLimiter(基于令牌桶)。
  • 優點:允許一定突發流量,靈活性高。
  • 缺點:實現復雜度較高。

代碼示例:

import com.google.common.util.concurrent.RateLimiter;

RateLimiter rateLimiter = RateLimiter.create(100); // QPS=100
rateLimiter.acquire(); // 阻塞直到有令牌可用

3. 滑動窗口計數器(Sliding Window Counter)

  • 原理:將時間窗口劃分為多個子窗口,統計每個子窗口內的請求數。
  • 實現:使用環形數組記錄每個子窗口的請求量。
  • 優點:精確控制QPS,避免固定窗口計數器的“突刺問題”。
  • 缺點:內存占用較高。

三、服務端接口限流

針對服務端的限流,我們需要通過控制客戶端請求頻率來控制,避免過于頻繁的接口調用出錯或封號等。

服務端限流一般有哪些方案呢?

1. Guava RateLimiter(單機)

  • 原理:基于令牌桶算法,線程安全。
  • 優點:簡單易用,適用于單機服務。
  • 缺點:無法跨節點同步,分布式場景需配合Redis。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimiter {
    double qps(); // 每秒允許的請求數
    long warmupPeriod() default 0; // 預熱期(毫秒)
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
@Aspect
@Component
public class RateLimiterAspect {
    // 使用ConcurrentHashMap存儲不同接口的RateLimiter實例
    private final Map<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<>();

    @Around("@annotation(rateLimiter)")
    public Object around(ProceedingJoinPoint joinPoint, RateLimiter rateLimiter) throws Throwable {
        String methodKey = joinPoint.getSignature().getName(); // 以方法名作為限流標識
        RateLimiter limiter = rateLimiterMap.computeIfAbsent(
            methodKey, 
            k -> RateLimiter.create(
                rateLimiter.qps(),
                rateLimiter.warmupPeriod(),
                rateLimiter.timeUnit()
            )
        );

        if (!limiter.tryAcquire()) { // 嘗試獲取令牌,立即返回
            throw new TooManyRequestsException("接口請求過于頻繁,請稍后再試");
        }
        return joinPoint.proceed();
    }
}

2. Redis計數器(分布式)

  • 原理:利用Redis的INCR命令統計請求數,結合EXPIRE實現時間窗口。
  • 實現:
-- lua腳本實現原子計數
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key) or "0")
if current + 1 > limit then
    return 0
else
    redis.call("INCR", key)
    redis.call("EXPIRE", key, 1)
    return 1
end
  • 優點:支持分布式場景,精度高。
  • 缺點:依賴Redis性能,需考慮網絡延遲。

3. Nginx限流(網關層)

  • 配置:
limit_req_zone $binary_remote_addr zone=one:10m rate=100r/s;
server {
    location /api {
        limit_req zone=one burst=200;
        proxy_pass http://backend;
    }
}
  • 優點:高效(內核級處理),不影響業務邏輯。
  • 缺點:配置較復雜,無法感知業務狀態。

4. Sentinel(阿里開源框架)

  • 功能:基于滑動窗口限流,支持熔斷、降級、負載保護。
  • 優點:功能全面,適用于微服務架構。
  • 缺點:引入額外依賴,學習成本較高。

結語

QPS控制是保障系統穩定性的重要環節。選擇方案時需結合業務場景、技術成本和擴展性。通過客戶端與服務端的雙重限流,配合監控與報警,可有效避免因QPS超限導致的服務不可用。

責任編輯:武曉燕 來源: Java技術指北
相關推薦

2022-06-16 07:50:35

數據結構鏈表

2023-12-04 07:07:36

HTTP請求

2023-12-07 12:29:49

Nginx負載均衡策略

2024-03-12 08:37:32

asyncawaitJavaScript

2024-07-29 10:35:44

KubernetesCSI存儲

2024-02-02 11:03:11

React數據Ref

2023-08-01 12:51:18

WebGPT機器學習模型

2024-01-02 12:05:26

Java并發編程

2022-10-11 08:48:08

HTTP狀態碼瀏覽器

2022-07-08 09:27:48

CSSIFC模型

2024-01-19 08:25:38

死鎖Java通信

2023-07-26 13:11:21

ChatGPT平臺工具

2023-01-10 08:43:15

定義DDD架構

2024-02-04 00:00:00

Effect數據組件

2024-10-29 08:08:44

2022-03-05 23:29:18

LibuvwatchdogNode.js

2025-06-20 09:57:42

2024-08-12 08:12:38

2024-11-28 10:32:32

2024-05-29 07:47:30

SpringJava@Resource
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲国产中文字幕 | 日韩欧美视频免费在线观看 | 美女视频网站久久 | 精品亚洲一区二区三区 | 一色桃子av一区二区 | 国产一区久久 | 日韩精品免费 | 91久久精品一区二区二区 | 99精品国产一区二区青青牛奶 | 在线中文字幕av | 精品欧美一区免费观看α√ | 国产一级免费视频 | 福利色导航 | 久久99精品久久久久久国产越南 | 99这里只有精品 | 天天射视频 | 色资源在线观看 | 亚洲精久久久 | 亚洲社区在线 | 中文字幕91| 午夜精品久久久 | 日韩a级片 | 国产精品亚洲一区 | 天堂视频免费 | 97精品国产一区二区三区 | 国产精品精品久久久 | 亚洲二区在线观看 | 黄色大片观看 | 日本成人午夜影院 | 精品国产一区二区三区日日嗨 | 亚洲国产精品第一区二区 | 成人性生交大片免费看r链接 | 成人免费一区二区三区视频网站 | 国产一区二区三区久久 | 国产成人av在线播放 | 精品国产一区二区三区性色 | 亚洲欧美高清 | 美女黄网站视频免费 | 青青久久av北条麻妃海外网 | 奇米四色影视 | 91在线一区二区三区 |