Quarkus 中的負載削減
1. 概述
quarkus-load-shedding
擴充功能提供了一種在高流量條件下故意拒絕請求的機制,以防止應用程式或服務內的系統過載。該庫還公開了有助於自訂如何處理負載削減的關鍵配置屬性。
在本教程中,我們將研究如何將此擴充功能合併到我們的 Quarkus 應用程式中並自訂其配置以滿足我們的特定需求。
2. 設定
為了示範quarkus-load-shedding
擴充功能的主要功能,我們將使用兩個作為 REST 端點公開的 Web 資源: 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 呼叫兩個端點來測試我們的配置。在 JMeter 中,我們設定了7
使用者線程,運行兩次,啟動時間為5
秒:
執行此測試計劃將得到以下結果,顯示 HTTP 503 錯誤率在兩個端點之間均勻分佈。
標籤 | # 範例 | 平均的 | 分分鐘 | 最大限度 | 標準。開發。 | 錯誤 % |
---|---|---|---|---|---|---|
斐波那契 HTTP 請求 | 14 | 5735 | 2 | 12613 | 4517.63 | 28.571% |
階乘 HTTP 請求 | 14 | 5195 | 1 | 11470 | 4133.69 | 28.571% |
全部的 | 二十八 | 5465 | 1 | 12613 | 4338.33 | 28.571% |
根據application.properties
中的配置, quarkus-load-shedding
擴充功能會無差別地拒絕請求。
4. 自訂減載
quarkus-load-shedding
擴充功能公開了一些配置,使我們能夠自訂負載削減行為。其中一個功能是,當系統負載過重時,可以確定應優先處理哪些請求。讓我們在下一小節中討論這個問題。
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 測試計劃,產生以下結果:
標籤 | # 範例 | 平均的 | 分分鐘 | 最大限度 | 標準。開發。 | 錯誤 % |
---|---|---|---|---|---|---|
斐波那契 HTTP 請求 | 14 | 5848 | 9 | 13355 | 4280.47 | 14.286% |
階乘 HTTP 請求 | 14 | 6915 | 10 | 14819 | 5905.41 | 28.571% |
全部的 | 二十八 | 6381 | 9 | 14819 | 5184.86 | 21.429% |
如表所示,由於優先權較高,/ fibonacci
端點的拒絕率較低。
4.3.系統探測率
probeFactor
配置影響擴展探測或檢查系統請求處理能力波動的頻率。
預設情況下, probeFactor
設定為 30。為了比較此設定的效果,我們首先僅對FibonacciResource
執行 JMeter 測試,使用11
使用者執行緒:
我們來看看執行JMeter測試計畫之後的結果:
標籤 | # 範例 | 平均的 | 分分鐘 | 最大限度 | 標準。開發。 | 錯誤 % |
---|---|---|---|---|---|---|
斐波那契 HTTP 請求 | 33 | 8236 | 3 | 14484 | 4048.21 | 9.091% |
全部的 | 33 | 8236 | 3 | 14484 | 4048.21 | 9.091% |
如預期的那樣,只有三個請求(即33
樣本 x 9.091
% 的錯誤率)被拒絕,因為我們在application.properties
檔案中將允許的最大並發請求數配置為10
。
現在讓我們在application.properties
檔案中將probeFactor
從預設值30
增加:
quarkus.load-shedding.probe-factor=70
然後,讓我們使用與之前相同的設定重新執行 JMeter 測試並檢查結果:
標籤 | # 範例 | 平均的 | 分分鐘 | 最大限度 | 標準。開發。 | 錯誤 % |
---|---|---|---|---|---|---|
斐波那契 HTTP 請求 | 33 | 6515 | 11 | 13110 | 3850.50 | 6.061% |
全部的 | 33 | 6515 | 11 | 13110 | 3850.50 | 6.061% |
此次,只有兩項請求被拒絕。設定較高的probeFactor
會使系統對負載波動較不敏感。
4.4.隊列管理
alphaFactor
和betaFactor
配置根據觀察到的請求佇列大小控制限制如何增加和減少(從初始到最大限制)。為了查看它們的效果,讓我們將它們新增到我們的application.properties
檔案中:
quarkus.load-shedding.alpha-factor=1
quarkus.load-shedding.beta-factor=5
使用上一節中的 11 個使用者執行緒重新執行我們先前的 JMeter 測試,我們得到以下結果:
從結果中我們注意到,限制分配是漸進的,這導致第六個請求被拒絕,儘管尚未達到最大限制。
5. 結論
在本文中,我們了解如何將quarkus-load-shedding
擴充功能合併到我們的 Quarkus 應用程式中,以便我們的系統能夠在負載下有效回應。我們還學習如何透過調整擴充的配置屬性來客製化擴充以滿足我們的需求,並更深入地了解每個擴充的含義。
與往常一樣,程式碼可在 GitHub 上取得。