PHP高并发部署实录:香港CN2链路下每请求省0.4ms的Nginx/PHP-FPM内核级手术
先说结论:香港CN2是不错的链路,但多数人把高并发优化的目光全放在PHP-FPM进程数和MySQL慢查询上。本文基于轻云互联香港CN2服务器实操验证,直击网络栈、TLS握手、Unix Socket隔离层三个订单系统压测中发现的隐藏瓶颈,不扯概念,全部命令化。
## 1. 第一刀:砍向延迟的“双向RTT放大器”
CN2链路的特点是延迟低至4-8ms,但丢包率往往不为零。TCP拥塞控制算法默认的 `cubic` 在丢包恢复时会线性增加拥塞窗口,在跨国链路上会放大抖动。
查看当前算法:
```bash
sysctl net.ipv4.tcp_congestion_control
```
实测在CN2链路下,改为 `bbr` 并调整 `tcp_notsent_lowat`(降低发送缓冲区低水位标记,让Nginx更快感知可写事件):
```bash
cat >> /etc/sysctl.conf <<'EOF'
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_notsent_lowat = 16384
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_slow_start_after_idle = 0
EOF
sysctl -p
```
`tcp_mtu_probing` 在CN2链路MTU黑洞场景下能自动降级。`tcp_slow_start_after_idle` 关闭空闲后慢启动,对长连接时段的突发请求是个明显的隐形收益,压测中P99延迟降低了0.4ms。
## 2. 第二刀:PHP-FPM的socket隔离
多数人用的是默认的 `/var/run/php-fpm/www.sock`,所有站点共用。在https下,PHP进程池会因不同应用的空闲状态互相“吵闹”(比如一个站点慢查询导致worker被占满,另一个站点的健康请求排队)。
结合Nginx的 `fastcgi_pass unix:/run/php-fpm-xxx.sock`,按核心业务和边缘业务拆分PHP-FPM池,并用 `cgroup` 限制IO:
```bash
mkdir -p /sys/fs/cgroup/blkio/php-io
echo "253:0 1048576" > /sys/fs/cgroup/blkio/php-io/blkio.throttle.read_bps_device
echo "253:0 1048576" > /sys/fs/cgroup/blkio/php-io/blkio.throttle.write_bps_device
```
在 `/etc/php-fpm.d/order.conf` 池配置中绑定worker数和request_terminate_timeout,而核心池 `/etc/php-fpm.d/core.conf` 使用短超时+高worker数:
```ini
[core-pool]
listen = /run/php-fpm-core.sock
listen.backlog = 4096
pm = dynamic
pm.max_children = 80
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 40
pm.max_requests = 10000
request_terminate_timeout = 10s
```
关键是 `listen.backlog`。CN2链路到来访请求极快,TCP accept队列如果太短会直接SYN丢弃。
## 3. Nginx keepalive + fastcgi_finish_request的取舍
很多人不敢用 `fastcgi_finish_request`,怕连接被提前关闭。实际上在Nginx + PHP-FPM下,这个函数可以让PHP提前返回结果给Nginx,后续的耗时操作(如写日志)不占用worker。
但注意坑点:Nginx收到响应后如果未配置 `fastcgi_keep_conn on`,它会关闭到PHP-FPM的socket连接,那么PHP进程内还没执行完的 `fastcgi_finish_request` 后面代码,如果尝试向客户端输出或操作header会报错。
部署时建议在 `nginx.conf` 的 `http` 段中明确:
```nginx
fastcgi_keep_conn on;
upstream php_backend {
server unix:/run/php-fpm-core.sock;
keepalive 32;
}
```
这里 `keepalive 32` 指向Unix Socket,要配合PHP-FPM 7.4+。实测在轻云互联香港CN2线路 + 4核8G机型上,这种配置让接口的TCP连接复用率提升了近3倍,CPU占用率下降了12%。
## 4. session落盘与Redis并存的高并发陷阱
PHP高并发下,默认的filesession会卡在磁盘IO上,尤其是在NFS或云硬盘上。但直接全都切Redis又会导致Redis故障时全站不可用。
较稳妥的折中方案是`session.save_handler`先用Redis,同时在Redis连接失败时自动降级为memcached再降级到文件:
```php