PHP 部署服务
自 php7 之后的 php 服务是我见过最便捷的部署方式, 基本上用自带的源安装就能处理完所有步骤:
# 直接首先安装应用和 fpm 解析程序, 同时建议安装的组件
sudo apt install php php-fpm
sudo apt install php-intl php-mysql php-redis php-curl php-mbstring php-dom php-gd php-zip
# 现在很多发行版默认安装 php 会自动帮你安装 apache2 这个 Web 服务
# 这个服务会和 Nginx 之类产生占用冲突, 所以建议关闭掉
# 如果没有这些服务单元就不用管
sudo systemctl stop apache2.service # 关闭服务
sudo systemctl diable apache2.service # 禁止开机自启动
# 启动解析服务, 这里后续发行版都带 php{版本号}-fpm.service 启动
# 具体需要看默认源安装的版本号, 我这边默认安装的 php8.2 版本
sudo systemctl start php8.2-fpm.service # 启动解析服务
sudo systemctl enable php8.2-fpm.service # 启动开机服务
# 这里需要创建我一般采用 Nginx 托管, 所以这里建议创建个统一配置
sudo vim /etc/nginx/php-fpm.conf
/etc/nginx/php-fpm.conf 配置内容如下:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# 这里默认发行版都是采用 unixdomain 方式监听
# 默认发行版的 fpm 配置目录在 /etc/php/8.2/fpm, 具体可以输出命令:
# cat /etc/php/8.2/fpm/pool.d/www.conf |grep "^listen ="
# -------------------------------------------------------------
# 还有需要注意的是系统用户归属, 有的发行版 php-fpm 没有运行在 www-data(nginx 网络用户组)
# 这样会导致 php 生成的一些缓存没有访问权限, 具体输入命令确认是否设定在同个用户分组:
# cat /etc/php/8.2/fpm/pool.d/www.conf |grep -e "^user =" -e "^group =" -e "^listen.owner =" -e "^listen.group ="
# 这几个确认分配和 nginx 同个组
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
而 ngnix 引用也是很简单直接加载即可:
server {
# 其他略
# 默认页面需要追加 index.php
index index.php index.html index.htm;
# 首页默认跳转 index.php
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# 启用PHP配置, 没有路径默认是 /etc/nginx
include php-fpm.conf;
# 异常页面也同时映射交给 php 处理
error_page 404 /index.php;
# 禁止访问隐藏文件,如 .htaccess
location ~ /\. {
deny all;
}
}
这样就很轻松搭建出 php 环境配置, 后续主要问题的就是优化处理配置
优化说明
默认首先主要容易出问题的就是 fpm 配置, PHP-FPM 提供 3 种进程管理模式, 根据服务器负载选择:
| 模式 | 适用场景 | 特点 |
|---|---|---|
static |
高并发、资源充足的服务器 | 进程数固定,无动态调度开销 |
dynamic |
负载波动较大的服务器 | 进程数动态调整(按需创建) |
ondemand |
低负载、轻量应用 | 有请求时才创建进程,节省内存 |
具体通过命令可以看到目前适用的管理模式:
# 查看默认的管理模式, 一般默认是 dynamic
cat /etc/php/8.2/fpm/pool.d/www.conf |grep "^pm ="
默认 dynamic 保持不变即可, 主要问题就是怎么去分配数值:
# 这里求出目前的单个进程占用, 比如我这里输出 '单个PHP-FPM进程平均内存:40333.5 KB', 40333.5 KB 换算过来就是 40M 大小
# 如果服务器是台 4G(4096M) 内存的服务器, 需要预留扣除 10%~20% 内存作为让渡给系统占用(这里预留20%), 那么计算得出:
# 可用内存 = 总内存 × (1 - 预留比例) = 4096M × 80% = 3276.8M ≈ 3276M, 这就是 FPM 可用的内存大小
ps aux | grep php-fpm | grep -v grep | awk '{sum+=$6} END {print "单个PHP-FPM进程平均内存:" sum/NR " KB"}'
# 除了内存也需要去定内存核心数量和线程数量有多少
# 有些主机 CPU 采用 2核4线程的 CPU, 所以需要确认线程数量, 不过默认服务器都是单核心对应单线程, 所以不用管其他默认等于核心数即可
grep -c ^processor /proc/cpuinfo | awk '{print $1}'
那么目前这里可以调整的 /etc/php/8.2/fpm/pool.d/www.conf 配置:
pm.max_children: 最大子进程数pm.start_servers: 启动时的进程数pm.min_spare_servers: 最小空闲进程数pm.max_spare_servers: 最大空闲进程数
按照之前上面提出的 FPM=40, Memory=3276M, CPU=2 来计算(服务器配置为 2U4G):
pm.max_children=3276(内存) ÷ 40(单应用内存) = 81.9 → 向下取整81.9(预留少量冗余)=80pm.start_servers=2 (CPU核心)=2pm.min_spare_servers=2(CPU核心) ÷ 2(CPU核心) → 需小于 start_servers=1(这个值可以微调, 主要牵涉启动 fpm 默认初始化多少进程)pm.max_spare_servers=2(CPU核心) * 2(CPU核心) → 需小于 max_children=4(这个值可以微调, 如果服务器还有其他计算密集任务需降低)
之后就是 Linux 系统内核调优, 需要调整 /etc/security/limits.conf 文件配置, 不配置的话可能高并发会出现 504 异常:
# 默认文件描述符(fd)限制为 1024, 需要给指定用户提升
www-data soft nofile 65535
www-data hard nofile 65535
其他基本上就是 /etc/php/8.2/fpm/php.ini 里面设置, 这里摘取几个比较有用的:
; 隐藏PHP版本信息(响应头不返回X-Powered-By)
expose_php = Off
; 禁用危险函数(根据业务需求调整,如exec/system等, 有的第三方库会需要用到部分底层方法)
disable_functions = exec,system,passthru,shell_exec,escapeshellcmd,escapeshellarg,proc_open,proc_get_status,pcntl_alarm,pcntl_fork
; 关闭远程文件包含(高危)
allow_url_include = Off
; 若业务不需要,关闭远程文件打开
allow_url_fopen = Off
剩下基本上不需要去处理直接就可以跑起服务, 不过需要注意的是 php 的组件和配置修改都需要手动去重启 fpm 服务.
系统定时
实际上在 linux 各大发行版普遍集成 systemd 的情况, 已经不太需要利用 crontab 这种守护定时程序.
实际上是因为
crontab调度最小单位只能到分钟, 有些时延任务要到秒级别的情况可能没办法使用
大部分情况都会利用 php 来调度任务来执行定时程序, 这里假设设定个定时通知功能:
sudo touch /etc/systemd/system/php-notify.service # 定时调用服务
sudo touch /etc/systemd/system/php-notify.timer # 定时器服务
这里首先编写启动脚本服务(php-notify.service):
[Unit]
Description=PHP Notify Service
After=network.target
[Service]
Type=oneshot
# 这里采用 php 调度脚本, 这里就是我们需要修改的地方, 按照你的需求定义即可
ExecStart=/usr/bin/php -f {项目根目录路径}/notify.php
# 限制脚本超时时间(如 5 秒, 避免任务卡死)
TimeoutSec=5
# 脚本失败后重试(最多 3 次,间隔 3 秒)
Restart=on-failure
RestartSec=3
# 运行用户(非 root 更安全)
# 一般都以依赖 nginx 网络服务的, 可以挂靠在 www-data 这个用户运行
User=www-data
Group=www-data
之后编写具体定时器单元(php-notify.timer):
[Unit]
Description=Timer For PHP Notify
# 依赖服务单元, 也就是我们自己编写调度 service
Requires=php-notify.service
[Timer]
# 定时器激活后立即执行第一次任务
OnActiveSec=0s
# 上次任务完成后, 间隔 3 秒再次执行(核心配置)
OnUnitActiveSec=3s
# 绑定到服务单元
# 也就是我们自己编写服务单元
Unit=php-notify.service
[Install]
WantedBy=timers.target
最后更新下系统服务并启动即可:
sudo systemctl daemon-reload
sudo systemctl start php-notify.timer # 启动
sudo systemctl enable php-notify.timer # 有需要可以开机自启
其他什么定时调度扩展功能可以参考相关 systemd 教程