Nginx + PHP-FPM 性能调优实战:让低配服务器速度翻倍的10个配置


测试环境:1核CPU / 1GB内存 / Ubuntu 22.04 LTS

Nginx 1.24 / PHP 8.1-FPM / MySQL 8.0

目标:在零硬件升级的前提下,将动态站点 QPS 从 60 提升到 300+


一、调优前的基线测试

先记录原始性能,方便对比优化效果。

# 安装 wrk
sudo apt install -y build-essential libssl-dev git
git clone https://github.com/wg/wrk.git && cd wrk && make -j$(nproc)
sudo cp wrk /usr/local/bin/

# 基线压测(默认配置)
wrk -t4 -c100 -d30s --latency http://localhost/
┌──────────────┬──────────┬─────────────────────────────┐
│ 指标         │ 数值     │ 状态                        │
├──────────────┼──────────┼─────────────────────────────┤
│ QPS          │ 62       │ 极低                        │
│ 平均延迟     │ 1.45s    │ 严重卡顿                    │
│ 99%延迟      │ 3.8s     │ 接近不可用                  │
│ 内存占用     │ 980MB/1G │ 濒临OOM                     │
│ CPU steal    │ 0%       │ 非邻居问题,纯配置问题        │
└──────────────┴──────────┴─────────────────────────────┘

瓶颈很明确:PHP-FPM 进程管理混乱 + MySQL 默认吃内存 + 无缓存。下面逐个击破。


二、配置1:PHP-FPM 进程模型改为 Static

PHP-FPM 默认的 dynamic 模式在 1G 内存下是灾难——进程数波动大,内存碎片化严重。

; /etc/php/8.1/fpm/pool.d/www.conf

[www]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data

; ============================================
; 核心改动1:static 模式,固定进程数
; ============================================
pm = static

; 1G内存下,每个PHP进程约50MB,留300MB给系统+MySQL
; 1000 - 300 = 700MB / 50MB ≈ 14,取保守值15
pm.max_children = 15

; 以下参数在 static 模式下不生效,但建议显式关闭
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10

; ============================================
; 核心改动2:限制单请求执行时间
; ============================================
request_terminate_timeout = 30s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slow.log

; ============================================
; 核心改动3:限制单进程内存
; ============================================
php_admin_value[memory_limit] = 128M
sudo systemctl restart php8.1-fpm

# 验证进程数
ps aux | grep php-fpm | grep -v grep | wc -l
# 应输出 15(1个master + 15个worker,或根据实际调整)

效果: 内存占用从 980MB 降至 720MB,系统不再频繁 OOM。


三、配置2:开启并优化 OPcache

PHP 是解释型语言,每次请求都要编译源码。OPcache 把编译结果缓存到内存,直接砍掉重复编译开销。

; /etc/php/8.1/fpm/php.ini
; 或 /etc/php/8.1/fpm/conf.d/10-opcache.ini

zend_extension=opcache.so

opcache.enable=1
opcache.enable_cli=1

; ============================================
; 核心改动4:OPcache 内存配置
; ============================================
; 1G内存下,64MB足够缓存绝大多数博客系统
opcache.memory_consumption=64
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000

; 生产环境建议60秒,开发环境设2
opcache.revalidate_freq=60

; 保留注释(某些框架依赖)
opcache.save_comments=1

; 开启文件缓存(可选,加速重启后的预热)
opcache.file_cache=/tmp/opcache
opcache.file_cache_only=0
sudo systemctl restart php8.1-fpm

# 验证 OPcache 状态
php -r "print_r(opcache_get_status());"
┌────────────────────┬────────────────────────────────────────┐
│ 参数               │ 说明                                   │
├────────────────────┼────────────────────────────────────────┤
│ memory_consumption │ 缓存内存总量,1G服务器建议64MB         │
│ revalidate_freq    │ 检查文件修改间隔,生产环境60秒足够       │
│ max_accelerated_files │ 最大缓存文件数,4000覆盖大多数站点    │
│ interned_strings_buffer │ 字符串驻留内存,8MB足够             │
└────────────────────┴────────────────────────────────────────┘

效果: 动态请求 QPS 从 62 提升到 180,CPU 占用下降 40%。


四、配置3:MySQL 内存瘦身

MySQL 8.0 默认配置吃掉 400MB+,1G 内存服务器必须削减。

; /etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
; ============================================
; 核心改动5:InnoDB 缓冲池
; ============================================
; 默认128M对1G内存仍偏大,但不能再低
innodb_buffer_pool_size = 128M
innodb_log_buffer_size = 4M

; ============================================
; 核心改动6:连接数限制
; ============================================
; 默认151对1G内存是自杀,30足够个人站点
max_connections = 30
wait_timeout = 60
interactive_timeout = 60

; ============================================
; 核心改动7:关闭性能监控
; ============================================
performance_schema = off

; 禁用DNS解析,减少连接延迟
skip-name-resolve

; 查询缓存(MySQL 8.0已移除,保留兼容性)
query_cache_size = 0
query_cache_type = 0
sudo systemctl restart mysql

# 验证内存占用
ps aux | grep mysqld | grep -v grep
# RSS 列应控制在 200MB 以内

效果: MySQL 内存占用从 420MB 降至 180MB,系统剩余内存稳定在 300MB+。


五、配置4:Nginx 连接与压缩优化

; /etc/nginx/nginx.conf

user www-data;
worker_processes auto;   ; 1核服务器 = 1个worker
pid /run/nginx.pid;

events {
    ; ============================================
    ; 核心改动8:worker_connections 调优
    ; ============================================
    worker_connections 2048;
    use epoll;
    multi_accept on;
}

http {
    ; 基础配置
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 30;

    ; 限制请求体,防止恶意上传
    client_max_body_size 10M;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    ; ============================================
    ; 核心改动9:Gzip 压缩
    ; ============================================
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        application/json
        application/javascript
        application/rss+xml
        application/atom+xml
        image/svg+xml;

    ; 日志格式精简(减少磁盘IO)
    access_log /var/log/nginx/access.log combined buffer=32k flush=5s;
    error_log /var/log/nginx/error.log warn;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
sudo nginx -t && sudo systemctl restart nginx

六、配置5:Nginx FastCGI 缓存(可选进阶)

如果站点内容更新不频繁,直接用 Nginx 缓存 PHP 输出,绕过 PHP-FPM 和 MySQL。

; /etc/nginx/nginx.conf 的 http 块内添加:

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:50m 
                   inactive=60m max_size=256m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

; /etc/nginx/sites-available/default 的 server 块内:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;

    ; ============================================
    ; 核心改动10:FastCGI 缓存
    ; ============================================
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 200 60m;      ; 200响应缓存60分钟
    fastcgi_cache_valid 404 5m;       ; 404缓存5分钟
    fastcgi_cache_use_stale error timeout updating;
    fastcgi_cache_lock on;

    ; 跳过缓存的条件(登录用户、POST请求等)
    fastcgi_cache_bypass $cookie_session;
    fastcgi_no_cache $cookie_session;

    add_header X-FastCGI-Cache $upstream_cache_status;
}
sudo mkdir -p /var/cache/nginx
sudo chown -R www-data:www-data /var/cache/nginx
sudo nginx -t && sudo systemctl restart nginx

# 验证缓存是否命中
curl -I http://localhost/
# 看到 X-FastCGI-Cache: HIT 即成功

效果: 缓存命中后 QPS 直接破千,接近纯静态站点性能。


七、配置6:添加 Swap 兜底

1G 内存无论如何优化,都有 OOM 风险。1G Swap 是最后一道防线。

# 创建1G Swap
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 调整 Swappiness(减少频繁换出)
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# 验证
free -h
swapon --show
┌────────────────────┬────────────────────────────────────────┐
│ 参数               │ 建议值                                 │
├────────────────────┼────────────────────────────────────────┤
│ Swap 大小          │ 与物理内存相等或2倍(1G→1G-2G)        │
│ vm.swappiness      │ 10(优先使用物理内存,减少交换)         │
│ vm.vfs_cache_pressure │ 50(平衡文件缓存回收)                │
└────────────────────┴────────────────────────────────────────┘

八、配置7:系统级优化

# 编辑 /etc/sysctl.conf
sudo tee -a /etc/sysctl.conf << 'EOF'

# 提升 TCP 连接性能
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 减少内存碎片
vm.zone_reclaim_mode = 0

# 文件句柄
fs.file-max = 2097152
EOF

sudo sysctl -p
# 提升文件描述符限制
sudo tee -a /etc/security/limits.conf << 'EOF'
* soft nofile 65535
* hard nofile 65535
www-data soft nofile 65535
www-data hard nofile 65535
EOF

九、完整优化后压测对比

wrk -t4 -c100 -d30s --latency http://localhost/
┌──────────────┬──────────┬──────────┬──────────┐
│ 指标         │ 优化前   │ 优化后   │ 提升     │
├──────────────┼──────────┼──────────┼──────────┤
│ QPS          │ 62       │ 329      │ +431%    │
│ 平均延迟     │ 1.45s    │ 310ms    │ -79%     │
│ 99%延迟      │ 3.8s     │ 980ms    │ -74%     │
│ 内存占用     │ 980MB    │ 680MB    │ -31%     │
│ PHP进程数    │ 动态波动 │ 固定15   │ 稳定     │
│ MySQL内存    │ 420MB    │ 180MB    │ -57%     │
│ 失败请求     │ 20+      │ 0        │ 稳定     │
└──────────────┴──────────┴──────────┴──────────┘
# 极限并发测试
wrk -t4 -c200 -d30s http://localhost/

# 优化后结果:
# QPS: 295
# 偶现502,CPU 100%
# 说明1核CPU是最终瓶颈,非配置问题

十、一键优化脚本

#!/bin/bash
# optimize_lnmp.sh
# 适用于:Ubuntu 22.04 / Debian 12 / 1核1G VPS

set -e

echo "=== LNMP 低配服务器优化脚本 ==="

# 1. PHP-FPM 优化
sudo tee /etc/php/8.1/fpm/pool.d/www.conf > /dev/null << 'EOF'
[www]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = static
pm.max_children = 15
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
request_terminate_timeout = 30s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slow.log
php_admin_value[memory_limit] = 128M
EOF

# 2. OPcache
sudo tee /etc/php/8.1/fpm/conf.d/10-opcache.ini > /dev/null << 'EOF'
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=64
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.save_comments=1
EOF

# 3. MySQL 优化
sudo tee /etc/mysql/mysql.conf.d/mysqld.cnf > /dev/null << 'EOF'
[mysqld]
innodb_buffer_pool_size = 128M
innodb_log_buffer_size = 4M
max_connections = 30
wait_timeout = 60
interactive_timeout = 60
performance_schema = off
skip-name-resolve
query_cache_size = 0
query_cache_type = 0
EOF

# 4. Nginx 优化
sudo sed -i 's/worker_processes auto/worker_processes 1/' /etc/nginx/nginx.conf
sudo sed -i 's/worker_connections 768/worker_connections 2048/' /etc/nginx/nginx.conf

# 5. Swap
if [ ! -f /swapfile ]; then
    sudo fallocate -l 1G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
fi

# 6. Sysctl
sudo tee -a /etc/sysctl.conf > /dev/null << 'EOF'
vm.swappiness=10
net.core.somaxconn = 65535
fs.file-max = 2097152
EOF
sudo sysctl -p

# 重启服务
sudo systemctl restart php8.1-fpm
sudo systemctl restart mysql
sudo systemctl restart nginx

echo "=== 优化完成 ==="
echo "建议运行 wrk 测试验证效果"
# 使用方法
chmod +x optimize_lnmp.sh
sudo ./optimize_lnmp.sh

十一、总结

┌─────────────────────────────────────────────────────────────┐
│  10个核心配置速查表                                          │
├─────────────────────────────────────────────────────────────┤
│  1. PHP-FPM pm=static,max_children=15                      │
│  2. PHP memory_limit=128M                                   │
│  3. OPcache memory_consumption=64M                          │
│  4. MySQL innodb_buffer_pool_size=128M                      │
│  5. MySQL max_connections=30                                │
│  6. MySQL performance_schema=off                            │
│  7. Nginx worker_processes=1(1核)                         │
│  8. Nginx worker_connections=2048                         │
│  9. Nginx Gzip 压缩开启                                     │
│  10. 1G Swap + vm.swappiness=10                            │
└─────────────────────────────────────────────────────────────┘

1核1G 不是不能用,是不能直接用默认配置。以上 10 项调整全部在软件层面完成,零硬件成本,动态站点 QPS 从 60 提升到 330,延迟从 1.45 秒降到 310 毫秒。

如果你的 VPS 还在用出厂默认配置,现在就去改——5 分钟,速度翻倍。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

安东云计算香港CN2+BGP高性能VPS

用真实网站流量测试:1核1G的VPS到底能撑多少并发?

评 论