Nginx延迟过高求助:双服务器架构周末流量高峰响应卡顿
结合你描述的架构和周末高峰遇到的网站卡顿问题,我从几个核心方向梳理下可能的原因和优化方案:
1. PHP-FPM 进程过载是首要嫌疑
你的PHP-FPM平日连接数维持在30-40,峰值却冲到了650,而你的服务器是8核CPU——通常PHP-FPM的合理进程数上限应该是CPU核心数的3-4倍(也就是24-32左右)。650个进程远超阈值会带来两个致命问题:
- 内存耗尽:每个PHP-FPM进程大概占用20-50MB内存,650个进程的内存需求在13G-32G之间,你的服务器只有16G内存,必然会触发内存交换(swap)甚至OOM杀死进程,直接导致响应卡顿。
- 进程调度开销:CPU要在几百个进程间频繁切换,上下文切换成本剧增,看似负载不高但实际有效工作占比极低。
优化建议:
修改PHP-FPM配置文件(比如www.conf):
pm = dynamic pm.max_children = 32 # 8核*4,可根据实际剩余内存微调,确保留足1G以上空闲内存 pm.start_servers = 8 pm.min_spare_servers = 4 pm.max_spare_servers = 16 pm.status_path = /fpm-status # 开启状态页,方便实时监控进程状态
重启PHP-FPM后,用curl http://你的服务器IP/fpm-status查看实时进程数,确保高峰时不会超过max_children。
2. MySQL 后端阻塞排查
PHP-FPM进程卡顿很多时候不是自身问题,而是卡在等待MySQL返回结果。你需要重点确认:
- MySQL的
max_connections是否足够?执行show variables like 'max_connections';,如果默认设置151,高峰时很可能出现连接排队。 - 是否存在慢查询?开启慢查询日志定位问题SQL:
分析慢日志,给频繁查询的表添加合适的索引,优化SQL语句(比如避免slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 # 记录所有执行超过1秒的查询select *、减少不必要的关联查询)。 - 清理闲置连接:执行
show processlist;,如果有大量Sleep状态的连接,建议设置wait_timeout = 60,让MySQL自动清理闲置超过60秒的连接。
3. Nginx 与 Varnish 缓存优化
虽然直接访问Nginx也有问题,但缓存层的优化能大幅减轻后端压力:
- Nginx层面:确保
worker_connections足够(建议设置为10240),同时给静态资源设置缓存过期头,减少重复请求:location ~* \.(css|js|png|jpg|gif)$ { expires 7d; add_header Cache-Control "public, no-transform"; } - Varnish层面:检查缓存策略,确保静态页面、非实时API响应被有效缓存。比如设置缓存TTL为5分钟甚至更久,减少请求穿透到Nginx和PHP。
4. 系统内核与资源监控
- 关闭swap:执行
swapoff -a,并写入/etc/fstab永久关闭。swap的磁盘IO速度远低于内存,会拖慢所有进程的响应速度。 - 调整内核网络参数(写入
/etc/sysctl.conf后执行sysctl -p生效):net.core.somaxconn = 65535 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30 - 高峰时用
htop、vmstat 1、iostat 1监控:重点看CPU的wa(等待IO)指标、内存使用率、磁盘读写速度。如果wa过高,说明MySQL磁盘IO是瓶颈,考虑更换SSD或者优化MySQL缓存(innodb_buffer_pool_size设置为内存的50-70%)。
5. 压力测试精准定位瓶颈
用wrk或者ab模拟高峰流量,直接测试Nginx端口:
wrk -t8 -c100 -d30s http://你的服务器IP:Nginx端口
测试时同时监控:
- PHP-FPM状态页的
active processes是否达到max_children - MySQL的
Threads_running是否过高 - 系统的CPU、内存、IO指标
这样就能精准定位是PHP-FPM、MySQL还是系统资源的问题。
内容的提问来源于stack exchange,提问作者Tan
相关产品推荐
相关产品推荐

