Nginx与PHP-FPM配置最佳实践

好的,各位亲爱的程序员朋友们,欢迎来到今天的“Nginx与PHP-FPM的爱恨情仇”特别讲座!我是你们的老朋友,江湖人称“代码诗人”的程序猿老王。今天,咱们不谈枯燥的代码,只聊聊如何让Nginx和PHP-FPM这对黄金搭档,在你服务器上跳起优雅的华尔兹,而不是互相掐架,搞得你的网站一团糟。

开场白:一对欢喜冤家的前世今生

想象一下,你的网站就像一家餐馆,用户(顾客)点了菜(请求),Nginx就是那个帅气的服务员,负责接待客人、点单,以及把订单送到厨房。而PHP-FPM,就是那个手艺精湛的大厨,负责烹饪美食(处理PHP脚本),然后把做好的菜交给服务员(Nginx),最终送到顾客手中。

Nginx擅长静态资源的处理,它就像一个勤劳的小蜜蜂,嗖嗖嗖地就把图片、CSS、JS文件送到了用户面前。但遇到PHP这种需要“烹饪”的动态请求,它就得找PHP-FPM帮忙了。

所以,Nginx和PHP-FPM,一个负责前端接待,一个负责后端处理,分工明确,配合默契。但如果配置不当,这对搭档就会变成一对冤家,互相推诿,导致你的网站卡顿、崩溃,用户体验直线下降。😱

第一幕:Nginx的自我修养(配置篇)

首先,我们得让Nginx明白,哪些请求需要交给PHP-FPM处理。这就要用到location指令了,它就像一个导游,告诉Nginx该怎么走。

server {
    listen 80;
    server_name yourdomain.com;
    root /var/www/yourdomain;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ .php$ {
        fastcgi_pass unix:/run/php/php7.4-fpm.sock; # 或者 tcp:127.0.0.1:9000
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /.ht {
        deny all;
    }
}

这段配置的意思是:

  • location /:处理所有请求,如果请求的文件或目录存在,就直接返回;否则,把请求交给index.php处理(这就是伪静态的关键)。
  • location ~ .php$:处理所有以.php结尾的请求,交给PHP-FPM处理。
  • fastcgi_pass:指定PHP-FPM的连接方式,可以是Unix socket(推荐)或者TCP。
  • fastcgi_param SCRIPT_FILENAME:告诉PHP-FPM要执行哪个PHP文件。
  • location ~ /.ht:禁止访问.htaccess文件,防止敏感信息泄露。

重点解读:

  • try_files指令: 这个指令非常重要,它决定了Nginx如何处理请求。它的工作原理是:依次尝试请求的文件、目录,如果都找不到,就执行最后的fallback(通常是index.php)。
  • fastcgi_params文件: 这个文件包含了FastCGI协议需要的各种参数,比如SCRIPT_NAMEREQUEST_URI等等。Nginx会把这些参数传递给PHP-FPM,让它知道该怎么处理请求。

优化小技巧:

  • 缓存静态资源: 使用expires指令可以缓存静态资源,减少对服务器的请求,提高访问速度。
location ~* .(jpg|jpeg|png|gif|css|js|ico)$ {
    expires 30d;
    log_not_found off; # 关闭404日志,减少磁盘IO
    access_log off; # 关闭访问日志,减少磁盘IO
}
  • Gzip压缩: 开启Gzip压缩可以减小传输的文件大小,提高访问速度。
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

第二幕:PHP-FPM的内心独白(配置篇)

PHP-FPM的配置文件通常位于/etc/php/[版本号]/fpm/pool.d/www.conf(不同系统可能有所不同)。这里面有很多参数需要配置,但最重要的几个是:

[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock # 或者 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

pm.status_path = /status # 监控状态页面

request_terminate_timeout = 120s
request_slowlog_timeout = 10s
slowlog = /var/log/php7.4-fpm.log.slow

重点解读:

  • usergroup 指定PHP-FPM进程的运行用户和用户组,要和Nginx的运行用户一致(通常是www-data)。
  • listen 指定PHP-FPM监听的地址,要和Nginx的fastcgi_pass指令对应。
  • pm 指定进程管理方式,有三种:
    • static:启动固定数量的子进程,适用于内存充足的服务器。
    • dynamic:动态调整子进程数量,根据请求量自动增加或减少,适用于资源有限的服务器。
    • ondemand:只有在有请求时才启动子进程,适用于流量不稳定的服务器。
  • pm.max_children 指定最大子进程数量,要根据服务器的CPU和内存来调整,过大容易导致内存溢出,过小容易导致请求排队。
  • pm.start_serverspm.min_spare_serverspm.max_spare_servers 这些参数控制了动态进程管理的行为,可以根据实际情况进行调整。
  • pm.status_path 指定PHP-FPM状态页面的URL,可以通过这个页面监控PHP-FPM的运行状态。
  • request_terminate_timeout 指定PHP脚本的最大执行时间,超过这个时间会被强制终止,防止恶意脚本占用资源。
  • request_slowlog_timeoutslowlog 指定记录慢日志的阈值和文件路径,可以用来排查性能问题。

优化小技巧:

  • 调整pm.max_children 这个参数是影响性能的关键因素,要根据服务器的CPU和内存来调整。一个简单的估算方法是:

    pm.max_children = (服务器总内存 - 其他服务占用内存) / 每个PHP进程占用内存

    可以使用top命令或者ps命令来查看PHP进程的内存占用情况。

  • 开启OPcache: OPcache可以缓存PHP脚本的编译结果,避免重复编译,显著提高性能。

    zend_extension=opcache.so
    opcache.enable=1
    opcache.memory_consumption=128 # 建议设置为128MB以上
    opcache.interned_strings_buffer=8
    opcache.max_accelerated_files=10000
    opcache.validate_timestamps=0 # 生产环境建议关闭

第三幕:性能调优的葵花宝典

配置好Nginx和PHP-FPM之后,并不意味着万事大吉。我们还需要不断地进行性能调优,才能让它们发挥出最大的潜力。

1. 监控是王道:

  • Nginx: 使用ngx_http_stub_status_module模块可以监控Nginx的运行状态,比如连接数、请求数等等。

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1; # 允许本地访问
        deny all;
    }
  • PHP-FPM: 通过pm.status_path配置的状态页面可以监控PHP-FPM的运行状态,比如活跃进程数、空闲进程数等等。

  • 系统资源: 使用tophtopvmstat等命令可以监控服务器的CPU、内存、磁盘IO等资源的使用情况。

2. 慢查询日志:

开启MySQL的慢查询日志,可以找到执行时间过长的SQL语句,然后进行优化。

3. 代码优化:

  • 避免循环嵌套: 循环嵌套会大大降低代码的执行效率。
  • 使用缓存: 缓存可以减少对数据库的访问,提高响应速度。
  • 优化数据库查询: 使用索引、避免全表扫描、减少JOIN操作等等。
  • 减少HTTP请求: 合并CSS、JS文件,使用CSS Sprites等等。

4. 使用CDN:

CDN(内容分发网络)可以将静态资源缓存到离用户更近的节点,提高访问速度。

5. 使用HTTP/2:

HTTP/2可以多路复用连接,减少延迟,提高传输效率。

表格总结:常见问题与解决方案

问题 可能原因 解决方案
网站访问速度慢 1. 服务器配置不足; 2. Nginx配置不当; 3. PHP-FPM配置不当; 4. 数据库查询慢; 5. 代码效率低; 6. 静态资源未缓存 1. 升级服务器配置; 2. 优化Nginx和PHP-FPM配置; 3. 优化数据库查询; 4. 优化代码; 5. 开启静态资源缓存; 6. 使用CDN; 7. 开启Gzip压缩
网站出现502 Bad Gateway错误 1. PHP-FPM进程挂掉; 2. PHP脚本执行超时; 3. Nginx和PHP-FPM连接失败 1. 检查PHP-FPM进程是否正常运行; 2. 增加request_terminate_timeout的值; 3. 检查Nginx和PHP-FPM的连接配置是否正确; 4. 检查服务器资源是否充足
网站出现504 Gateway Timeout错误 1. PHP脚本执行超时; 2. Nginx等待PHP-FPM响应超时 1. 增加request_terminate_timeout的值; 2. 增加proxy_read_timeoutproxy_connect_timeout的值; 3. 优化代码,减少PHP脚本的执行时间; 4. 检查服务器资源是否充足
CPU占用率过高 1. PHP脚本执行效率低; 2. Nginx配置不当; 3. 恶意攻击 1. 优化PHP脚本; 2. 优化Nginx配置; 3. 部署防火墙,防止恶意攻击; 4. 增加pm.max_children的值(但要注意内存占用); 5. 开启OPcache
内存占用率过高 1. PHP-FPM进程过多; 2. 内存泄漏 1. 减少pm.max_children的值; 2. 检查代码是否存在内存泄漏; 3. 重启PHP-FPM进程; 4. 升级服务器内存
磁盘IO过高 1. 频繁读写数据库; 2. 写入大量日志 1. 优化数据库查询; 2. 减少日志写入; 3. 使用SSD硬盘; 4. 使用缓存

第四幕:安全加固,防患于未然

安全是网站的生命线,我们不仅要让网站跑得快,还要让它跑得稳。

  • 更新软件: 及时更新Nginx、PHP、MySQL等软件,修复已知的安全漏洞。
  • 配置防火墙: 使用防火墙可以阻止恶意流量,保护服务器安全。
  • 禁用不必要的模块: 禁用Nginx和PHP中不必要的模块,减少攻击面。
  • 限制文件上传: 限制用户上传的文件类型和大小,防止恶意文件上传。
  • 使用HTTPS: 使用HTTPS可以加密数据传输,防止数据泄露。
  • 定期备份: 定期备份数据,以防万一。

尾声:代码诗人的寄语

各位朋友,今天的“Nginx与PHP-FPM的爱恨情仇”就到这里了。希望通过今天的分享,大家能够对Nginx和PHP-FPM的配置和优化有更深入的了解。记住,代码的世界,没有一劳永逸的解决方案,只有不断学习、不断探索,才能写出更优雅、更高效的代码。

最后,送给大家一句代码诗人的箴言:

“代码如诗,优雅至上,性能为王,安全护航。”

祝大家编程愉快,Bug远离!😊

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注