自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

HTTP客戶端實(shí)現(xiàn)請(qǐng)求QPS的控制,你學(xué)會(huì)了嗎?

開(kāi)發(fā) 項(xiàng)目管理
結(jié)語(yǔ)QPS控制是保障系統(tǒng)穩(wěn)定性的重要環(huán)節(jié)。選擇方案時(shí)需結(jié)合業(yè)務(wù)場(chǎng)景、技術(shù)成本和擴(kuò)展性。通過(guò)客戶端與服務(wù)端的雙重限流,配合監(jiān)控與報(bào)警,可有效避免因QPS超限導(dǎo)致的服務(wù)不可用。

背景:高德API調(diào)用QPS限制引發(fā)的問(wèn)題

最近在項(xiàng)目中使用高德API進(jìn)行地址轉(zhuǎn)坐標(biāo)時(shí),頻繁遇到CUQPS_HAS_EXCEEDED_THE_LIMIT錯(cuò)誤。這是因?yàn)锳PI對(duì)每秒請(qǐng)求量(QPS)有嚴(yán)格限制(如高德地圖API默認(rèn)QPS為3)。當(dāng)客戶端請(qǐng)求速度超過(guò)限制時(shí),服務(wù)端會(huì)直接拒絕請(qǐng)求。為解決這一問(wèn)題,我們需要在客戶端實(shí)現(xiàn)QPS控制,確保請(qǐng)求速率符合服務(wù)端要求。

一、當(dāng)前實(shí)現(xiàn)方案

ScheduledExecutorService + Semaphore

我們采用信號(hào)量(Semaphore)與定時(shí)任務(wù)(ScheduledExecutorService)結(jié)合的方式控制QPS:

  1. 信號(hào)量:初始化為允許的最大并發(fā)數(shù)(如100)。
  2. 定時(shí)任務(wù):每秒重置信號(hào)量許可數(shù)量,確保QPS不超過(guò)限制。

簡(jiǎn)單實(shí)現(xiàn):

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;
    }
}

測(cè)試

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 );
        }
}

優(yōu)點(diǎn):

  • 實(shí)現(xiàn)簡(jiǎn)單,無(wú)需引入外部依賴。
  • 適用于單機(jī)場(chǎng)景。

缺點(diǎn):

  • 定時(shí)任務(wù)可能因延遲導(dǎo)致信號(hào)量重置不及時(shí)。
  • 無(wú)法應(yīng)對(duì)突發(fā)流量(如瞬時(shí)高并發(fā))。
  • 分布式場(chǎng)景下需額外同步機(jī)制。

二、其他QPS控制方案及對(duì)比

除上述方案外,常見(jiàn)的QPS控制方法還包括:

1. 漏桶算法(Leaky Bucket)

  • 原理:請(qǐng)求進(jìn)入“漏桶”,以固定速率流出。若桶滿則拒絕請(qǐng)求。
  • 實(shí)現(xiàn):使用隊(duì)列存儲(chǔ)請(qǐng)求,定時(shí)任務(wù)按QPS處理隊(duì)列。
  • 優(yōu)點(diǎn):嚴(yán)格控制請(qǐng)求速率,平滑流量。
  • 缺點(diǎn):無(wú)法利用突發(fā)流量(如短時(shí)間內(nèi)允許更多請(qǐng)求)。

2. 令牌桶算法(Token Bucket)

  • 原理:每秒生成固定數(shù)量令牌,請(qǐng)求需消耗令牌。若令牌不足則等待或拒絕。
  • 實(shí)現(xiàn):使用Guava RateLimiter(基于令牌桶)。
  • 優(yōu)點(diǎn):允許一定突發(fā)流量,靈活性高。
  • 缺點(diǎn):實(shí)現(xiàn)復(fù)雜度較高。

代碼示例:

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

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

3. 滑動(dòng)窗口計(jì)數(shù)器(Sliding Window Counter)

  • 原理:將時(shí)間窗口劃分為多個(gè)子窗口,統(tǒng)計(jì)每個(gè)子窗口內(nèi)的請(qǐng)求數(shù)。
  • 實(shí)現(xiàn):使用環(huán)形數(shù)組記錄每個(gè)子窗口的請(qǐng)求量。
  • 優(yōu)點(diǎn):精確控制QPS,避免固定窗口計(jì)數(shù)器的“突刺問(wèn)題”。
  • 缺點(diǎn):內(nèi)存占用較高。

三、服務(wù)端接口限流

針對(duì)服務(wù)端的限流,我們需要通過(guò)控制客戶端請(qǐng)求頻率來(lái)控制,避免過(guò)于頻繁的接口調(diào)用出錯(cuò)或封號(hào)等。

服務(wù)端限流一般有哪些方案呢?

1. Guava RateLimiter(單機(jī))

  • 原理:基于令牌桶算法,線程安全。
  • 優(yōu)點(diǎn):簡(jiǎn)單易用,適用于單機(jī)服務(wù)。
  • 缺點(diǎn):無(wú)法跨節(jié)點(diǎn)同步,分布式場(chǎng)景需配合Redis。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimiter {
    double qps(); // 每秒允許的請(qǐng)求數(shù)
    long warmupPeriod() default 0; // 預(yù)熱期(毫秒)
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
@Aspect
@Component
public class RateLimiterAspect {
    // 使用ConcurrentHashMap存儲(chǔ)不同接口的RateLimiter實(shí)例
    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(); // 以方法名作為限流標(biāo)識(shí)
        RateLimiter limiter = rateLimiterMap.computeIfAbsent(
            methodKey, 
            k -> RateLimiter.create(
                rateLimiter.qps(),
                rateLimiter.warmupPeriod(),
                rateLimiter.timeUnit()
            )
        );

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

2. Redis計(jì)數(shù)器(分布式)

  • 原理:利用Redis的INCR命令統(tǒng)計(jì)請(qǐng)求數(shù),結(jié)合EXPIRE實(shí)現(xiàn)時(shí)間窗口。
  • 實(shí)現(xiàn):
-- lua腳本實(shí)現(xiàn)原子計(jì)數(shù)
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
  • 優(yōu)點(diǎn):支持分布式場(chǎng)景,精度高。
  • 缺點(diǎn):依賴Redis性能,需考慮網(wǎng)絡(luò)延遲。

3. Nginx限流(網(wǎng)關(guān)層)

  • 配置:
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;
    }
}
  • 優(yōu)點(diǎn):高效(內(nèi)核級(jí)處理),不影響業(yè)務(wù)邏輯。
  • 缺點(diǎn):配置較復(fù)雜,無(wú)法感知業(yè)務(wù)狀態(tài)。

4. Sentinel(阿里開(kāi)源框架)

  • 功能:基于滑動(dòng)窗口限流,支持熔斷、降級(jí)、負(fù)載保護(hù)。
  • 優(yōu)點(diǎn):功能全面,適用于微服務(wù)架構(gòu)。
  • 缺點(diǎn):引入額外依賴,學(xué)習(xí)成本較高。

結(jié)語(yǔ)

QPS控制是保障系統(tǒng)穩(wěn)定性的重要環(huán)節(jié)。選擇方案時(shí)需結(jié)合業(yè)務(wù)場(chǎng)景、技術(shù)成本和擴(kuò)展性。通過(guò)客戶端與服務(wù)端的雙重限流,配合監(jiān)控與報(bào)警,可有效避免因QPS超限導(dǎo)致的服務(wù)不可用。

責(zé)任編輯:武曉燕 來(lái)源: Java技術(shù)指北
相關(guān)推薦

2022-06-16 07:50:35

數(shù)據(jù)結(jié)構(gòu)鏈表

2023-12-04 07:07:36

HTTP請(qǐng)求

2023-12-07 12:29:49

Nginx負(fù)載均衡策略

2024-03-12 08:37:32

asyncawaitJavaScript

2024-07-29 10:35:44

KubernetesCSI存儲(chǔ)

2022-10-11 08:48:08

HTTP狀態(tài)碼瀏覽器

2022-07-08 09:27:48

CSSIFC模型

2024-02-02 11:03:11

React數(shù)據(jù)Ref

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2023-01-10 08:43:15

定義DDD架構(gòu)

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺(tái)工具

2024-01-19 08:25:38

死鎖Java通信

2024-10-29 08:08:44

2024-11-28 10:32:32

2022-03-05 23:29:18

LibuvwatchdogNode.js

2024-08-12 08:12:38

2022-12-06 08:37:43

2024-05-29 07:47:30

SpringJava@Resource
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)