1. 概述

Quarkus的quarkus-load-shedding扩展提供了一种在高流量场景下主动拒绝请求的机制,防止应用或服务过载。该扩展还暴露了关键配置属性,帮助自定义负载削减行为。

本文将展示如何将此扩展集成到Quarkus应用中,并通过调整配置满足特定需求。

2. 环境搭建

为演示quarkus-load-shedding扩展的核心功能,我们创建两个REST接口:FibonacciResourceFactorialResource。调用这些接口时,会随机产生1-15秒的响应延迟。

首先添加扩展依赖到Quarkus项目:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-load-shedding</artifactId>
</dependency>

以开发模式启动应用后,可在Dev UI中看到该扩展:

./mvnw quarkus:dev

⚠️ 截至本文撰写时,该扩展仍处于实验阶段:
Quarkus Dev UI扩展选项截图

3. 默认负载削减

添加扩展后,默认启用负载削减功能,使用默认配置拒绝请求。我们通过修改application.properties文件调整配置使其更严格:

quarkus.load-shedding.enabled=true
quarkus.load-shedding.max-limit=10
quarkus.load-shedding.initial-limit=5

关键配置说明

  • max-limit:设置并发请求上限
  • initial-limit:主要用于计算可接受队列大小

使用JMeter测试配置:设置7个用户线程运行2次,5秒内逐步启动:
JMeter测试计划设置截图

测试结果如下,HTTP 503错误率在两个接口间均匀分布:

标签 样本数 平均值 最小值 最大值 标准差 错误率
Fibonacci HTTP Request 14 5735 2 12613 4517.63 28.571%
Factorial HTTP Request 14 5195 1 11470 4133.69 28.571%
总计 28 5465 1 12613 4338.33 28.571%

quarkus-load-shedding扩展根据配置无差别拒绝请求。

4. 自定义负载削减

该扩展提供多个配置项实现自定义负载削减行为,其中关键功能是高负载下按优先级拒绝请求。

4.1. 请求优先级

application.properties中启用优先级设置:

# ...
quarkus.load-shedding.priority.enabled=true

实现RequestPrioritizer指定请求优先级:

@Provider
public class LoadRequestPrioritizer implements RequestPrioritizer<HttpServerRequestWrapper> {
    @Override
    public boolean appliesTo(Object request) {
        return request instanceof HttpServerRequestWrapper;
    }

    //...
}

LoadRequestPrioritizer类使用@Provider注解作为CDI Bean,运行时可自动发现。我们指定其仅处理HttpServerRequestWrapper类型请求。

为特定接口分配优先级:

@Provider
public class LoadRequestPrioritizer implements RequestPrioritizer<HttpServerRequestWrapper> {
    //...
    @Override
    public RequestPriority priority(HttpServerRequestWrapper request) {
        String requestPath = request.path();
        if (requestPath.contains("fibonacci")) {
            return RequestPriority.CRITICAL;
        } else {
            return RequestPriority.NORMAL;
        }
    } 
}

/fibonacci接口获得更高优先级,其请求被拒绝的概率低于其他接口

4.2. 负载触发检测

quarkus-load-shedding扩展仅在检测到系统压力时才应用优先级负载削减。模拟CPU负载:

@Path("/fibonacci")
public class FibonacciResource {
    //...
    @PostConstruct
    public void startLoad() {
        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
            new Thread(() -> {
                while (true) {
                    Math.pow(Math.random(), Math.random());
                }
            }).start();
        }
    }
}

首次调用时,FibonacciResource@PostConstruct触发CPU密集型任务,确保测试期间CPU持续高负载。重启应用后,先触发/fibonacci接口请求:

curl -X GET http://localhost:8080/api/fibonacci?iterations=9

再次执行相同参数的JMeter测试,结果如下:

标签 样本数 平均值 最小值 最大值 标准差 错误率
Fibonacci HTTP Request 14 5848 9 13355 4280.47 14.286%
Factorial HTTP Request 14 6915 10 14819 5905.41 28.571%
总计 28 6381 9 14819 5184.86 21.429%

由于优先级更高,/fibonacci接口的拒绝率显著降低。

4.3. 系统探测频率

probeFactor配置影响扩展探测系统请求处理能力波动的频率。默认值为30,为对比效果,先用11个用户线程测试FibonacciResource
JMeter测试设置:11用户线程,1秒启动,3次循环

测试结果:

标签 样本数 平均值 最小值 最大值 标准差 错误率
Fibonacci HTTP Request 33 8236 3 14484 4048.21 9.091%
总计 33 8236 3 14484 4048.21 9.091%

如预期,3个请求被拒绝(33样本×9.091%错误率),因为我们在application.properties中设置了最大并发请求为10。

application.properties中提高probeFactor

quarkus.load-shedding.probe-factor=70

使用相同设置重新测试:

标签 样本数 平均值 最小值 最大值 标准差 错误率
Fibonacci HTTP Request 33 6515 11 13110 3850.50 6.061%
总计 33 6515 11 13110 3850.50 6.061%

提高probeFactor使系统对负载波动敏感度降低,仅2个请求被拒绝。

4.4. 队列管理

alphaFactorbetaFactor配置基于观察到的请求队列大小控制限制增减(从初始值到最大值)。在application.properties中添加:

quarkus.load-shedding.alpha-factor=1
quarkus.load-shedding.beta-factor=5

使用前述11用户线程测试,结果如下:
JMeter结果表格截图

踩坑提示:限制分配是渐进式的,导致第6个请求被拒绝,即使尚未达到最大限制。

5. 总结

本文展示了如何将quarkus-load-shedding扩展集成到Quarkus应用,使系统在负载下有效响应。通过调整配置属性实现自定义需求,并深入理解了各配置项的具体作用。简单粗暴地说,掌握这些配置能帮你轻松应对高并发场景下的服务保护问题。


原始标题:Load Shedding in Quarkus | Baeldung