在 Swoole 伺服器程式中如何實現壓力反饋

韓天峰發表於2023-02-10

為什麼要反饋壓力

服務端程式在遇到高併發請求時,一旦超過程式所能處理的極限,可能會導致崩潰,引發線上服務的大規模雪崩。壓力反饋(Back Pressure)是一種由服務端主動告知客戶端自身資源不足,無法提供服務的一種手段。在 Web 服務中可以返回 HTTP 503Service Unavailable)告知客戶端當前伺服器處於比較高的負載狀態。這時客戶端可以選擇:

  1. 等待一定時間後進行重試
  2. 切換其他負載較低的節點或者伺服器上
  3. 暫時停止使用此服務,對相關的業務進行降級處理

PHP-FPM 如何反饋壓力

在傳統 Nginx+PHP-FPM 服務端程式中,底層有 3 個關鍵的配置影響壓力反饋:

  1. php-fpm.confpm.max_chindren 配置的最大程式數,如配置為 200 表示最大啟動 200 個程式,一旦超過最大程式數,新的請求將不會被 Accept,而是進入到 Listen Backlog 佇列中進行排隊,直到有空閒程式才會從佇列彈出一個新的請求進行處理
  2. php-fpm.conflisten.backlog 配置 Listen Backlog 佇列長度,如配置為 512 ,則表示若沒有空閒程式時,最大允許有 512 個請求排隊
  3. 核心引數 net.core.somaxconnlisten.backlog 設定的數值不一定是有效的,這取決於核心引數 net.core.somaxconn 的設定,實際佇列長度為 min(listen.backlog, net.core.somaxconn),例如 net.core.somaxconn=128listen.backlog=512,實際的佇列長度為 128 而不是 512

因此在 Nginx+PHP-FPM 程式中,最大併發為 pm.max_chindren + min(listen.backlog, net.core.somaxconn),一旦超過之後,就會拒絕新的請求,返回 502 錯誤,向客戶端反饋壓力。實際專案中,應當設定為一個合適的值,不宜過大或過小。否則就出產生客戶端等時間過長,低負載拒絕請求兩種問題。

Nginx 無法區分 502503 錯誤,這是一個缺點

Swoole 程式如何反饋壓力

由於 Swoole 是完全非同步的架構,併發能力更強,在機器資源未耗盡的前提下,是可以無限接受、處理請求的。相比 Nginx+PHP-FPM 不好實現壓力反饋,一般需要框架層面或者應用層程式碼中自行丟擲 503 錯誤。Swoole 底層提供了多項配置可以解決一部分問題。

max_connection

限制最大連線數, 超過最大連線數之後,會拒絕新的連線。返回 502 錯誤給 Gateway

max_coroutine

限制最大程式數,Swoole 會在接收到客戶端請求時建立一個新的協程進行處理,超過最大協程數之後,就會向客戶端傳送 HTTP 503 錯誤

max_concurrency

限制最大併發 HTTP 請求數,當前正在處理的請求數超過 max_concurrency 後,底層會立即向客戶端傳送 HTTP 503 錯誤,並關閉連線。

use Swoole\Http\Server;

$http = new Server('127.0.0.1', 9501);

$http->set([
    'max_connection' => 10000,
    'max_coroutine' => 50000,
    'max_concurrency' => 500,
]);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) {
    Co::sleep(0.1); // sleep 100ms 模擬請求處理的過程
    $response->header('Content-Type', 'text/plain');
    $response->end('Hello World');
});

$http->start();

啟動伺服器後使用 abwrk 壓測。

wrk -c 1000 -d 5s http://127.0.0.1:9501/
Running 5s test @ http://127.0.0.1:9501/
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    70.89ms  132.48ms   1.10s    95.39%
    Req/Sec     7.99k     3.68k   13.03k    66.32%
  77521 requests in 5.09s, 5.41MB read
  Socket errors: connect 0, read 55182, write 0, timeout 0
  Non-2xx or 3xx responses: 55182
Requests/sec:  15242.49
Transfer/sec:      1.06MB

可以看到 5秒 之內,共傳送了 77521 個請求,但是有 55182 個請求返回了 503 。這部分請求就是超過負載後壓力反饋的結果。

相關文章