部署PHP 部署
MeteorCat自 php7 之后的 php 服务是我见过最便捷的部署方式, 基本上用自带的源安装就能处理完所有步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 直接首先安装应用和 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 配置内容如下:
1 2 3 4 5 6 7 8 9 10 11 12
| 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 引用也是很简单直接加载即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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 |
低负载、轻量应用 |
有请求时才创建进程,节省内存 |
具体通过命令可以看到目前适用的管理模式:
1 2
| # 查看默认的管理模式, 一般默认是 dynamic cat /etc/php/8.2/fpm/pool.d/www.conf |grep "^pm ="
|
默认 dynamic 保持不变即可, 主要问题就是怎么去分配数值:
1 2 3 4 5 6 7 8
| # 这里求出目前的单个进程占用, 比如我这里输出 '单个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(预留少量冗余) = 80
pm.start_servers = 2 (CPU核心) = 2
pm.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 异常:
1 2 3
| # 默认文件描述符(fd)限制为 1024, 需要给指定用户提升 www-data soft nofile 65535 www-data hard nofile 65535
|
其他基本上就是 /etc/php/8.2/fpm/php.ini 里面设置, 这里摘取几个比较有用的:
1 2 3 4 5 6 7 8 9 10 11
| expose_php = Off
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 来调度任务来执行定时程序, 这里假设设定个定时通知功能:
1 2
| sudo touch /etc/systemd/system/php-notify.service # 定时调用服务 sudo touch /etc/systemd/system/php-notify.timer # 定时器服务
|
这里首先编写启动脚本服务(php-notify.service):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [Unit] Description=PHP Notify Service After=network.target
[Service] Type=oneshot
ExecStart=/usr/bin/php -f {项目根目录路径}/notify.php
TimeoutSec=5
Restart=on-failure RestartSec=3
User=www-data Group=www-data
|
之后编写具体定时器单元(php-notify.timer):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| [Unit] Description=Timer For PHP Notify
Requires=php-notify.service
[Timer]
OnActiveSec=0s
OnUnitActiveSec=3s
Unit=php-notify.service
[Install] WantedBy=timers.target
|
最后更新下系统服务并启动即可:
1 2 3
| sudo systemctl daemon-reload sudo systemctl start php-notify.timer # 启动 sudo systemctl enable php-notify.timer # 有需要可以开机自启
|
其他什么定时调度扩展功能可以参考相关 systemd 教程