1. 概述
Quarkus的quarkus-load-shedding
扩展提供了一种在高流量场景下主动拒绝请求的机制,防止应用或服务过载。该扩展还暴露了关键配置属性,帮助自定义负载削减行为。
本文将展示如何将此扩展集成到Quarkus应用中,并通过调整配置满足特定需求。
2. 环境搭建
为演示quarkus-load-shedding
扩展的核心功能,我们创建两个REST接口:FibonacciResource
和FactorialResource
。调用这些接口时,会随机产生1-15秒的响应延迟。
首先添加扩展依赖到Quarkus项目:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-load-shedding</artifactId>
</dependency>
以开发模式启动应用后,可在Dev UI中看到该扩展:
./mvnw quarkus:dev
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秒内逐步启动:
测试结果如下,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
:
测试结果:
标签 | 样本数 | 平均值 | 最小值 | 最大值 | 标准差 | 错误率 |
---|---|---|---|---|---|---|
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. 队列管理
alphaFactor
和betaFactor
配置基于观察到的请求队列大小控制限制增减(从初始值到最大值)。在application.properties
中添加:
quarkus.load-shedding.alpha-factor=1
quarkus.load-shedding.beta-factor=5
❌ 踩坑提示:限制分配是渐进式的,导致第6个请求被拒绝,即使尚未达到最大限制。
5. 总结
本文展示了如何将quarkus-load-shedding
扩展集成到Quarkus应用,使系统在负载下有效响应。通过调整配置属性实现自定义需求,并深入理解了各配置项的具体作用。简单粗暴地说,掌握这些配置能帮你轻松应对高并发场景下的服务保护问题。