3

为什么要反馈压力

服务端程序在遇到高并发请求时,一旦超过程序所能处理的极限,可能会导致崩溃,引发线上服务的大规模雪崩。压力反馈(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 。这部分请求就是超过负载后压力反馈的结果。


韩天峰
7.9k 声望11.1k 粉丝

Swoole 开源项目创始人