一、先说结论:这两个版本不是「新旧」关系,是「约束」关系

PHP 8.1 和 8.3 的差别,决定你能不能开够 PHP-FPM worker。 这是整篇文章的核心,也是大多数选型文章不会讲的。
先说版本本身。 PHP 8.1 是 2022 年 11 月发布的稳定分支,8.3 是 2023 年 11 月发布的稳定分支,两者的安全支持周期都已经进入尾声或正在收尾。8.3 相对 8.1 的主要变化:**
一是引入只读类(readonly classes)。 8.2 引入的 readonly 属性在 8.3 扩展到了整个类,声明一次整个类的属性都不可变。
二是 json_validate() 函数。 8.3 新增了独立的 JSON 校验函数,不用再靠 json_decode 加 json_last_error() 两步走。
三是动态类常量取用。 8.3 允许 Foo::{$bar} 这种动态获取类常量的写法。
四是更好的类型推断。 8.3 里 json_validate() 和部分内部函数的返回类型标注更准确,静态分析工具的误报变少。
五是性能。 8.3 相对 8.1 在纯计算场景有实测提升,但这个提升在 PHP-FPM 架构下不是瓶颈——真实网站的耗时大头是数据库查询和模板渲染,PHP 解释器本身的版本差异通常被淹没在 5% 以内。所以「8.3 更快所以要升」这个理由,对大多数站点是不成立的。
真正会咬人的是内存。 PHP 8.3 的常驻内存占用比 8.1 更高,同一份代码、同一个脚本,8.3 的 worker 常驻内存大约是 120MB 量级,8.1 大约是 90MB 量级。这 30MB 的差距,乘以 worker 数,在 4GB 机器上就是 9 个 worker 的差距。
为什么 worker 数这么关键? 因为 PHP-FPM 是「一个请求占一个 worker」的多进程模型。worker 数量就是你的并发处理能力上限。worker 不够,队列就堆积,表现为高并发时响应变慢、而 CPU 还没跑满。 这也是新手最容易误判的地方——「CPU 使用率只有 40% 但网站很慢」几乎都是 worker 数不足或者某个 worker 卡住了。
这一节先给你一个可执行的判断依据,后面会用真实价格把它算成钱。 先记住三个数字:PHP 8.1 每 worker 约 90MB,PHP 8.3 每 worker 约 120MB,1GB 内存的机器扣掉系统和数据库后基本只够 1 个 worker。这意味着 1GB 机器跑 PHP 8.3 是能跑的,但没有任何余量。
二、内存账:换版本到底要不要加内存

这一节把版本差异翻译成钱。 计算方法:机器总内存,减去 384MB 系统预留(内核、SSH、Nginx、监控),减去按机器档位配的 MySQL buffer pool,剩下的除以每 worker 的常驻内存,就是 worker 数上限。
先把商品库里的真实价格和配置列出来(快照时间 2026-11-11 09:33):
| 机型 | 内存 | 硬盘 | 带宽 | 月流量 | 折合月价 | 每 GB 内存成本 |
|---|---|---|---|---|---|---|
| RosCloud-01 | 1GB | 20GB | 500Mbps | 1024GB | 19.99 美元 | 19.99 美元 |
| RosCloud-02 | 2GB | 40GB | 500Mbps | 2048GB | 29.99 美元 | 14.99 美元 |
| RosCloud-03 | 4GB | 80GB | 500Mbps | 3072GB | 39.99 美元 | 10.00 美元 |
| RosCloud-04 | 8GB | 160GB | 500Mbps | 4096GB | 49.99 美元 | 6.25 美元 |
| RosCloud-05 | 16GB | 240GB | 500Mbps | 5120GB | 59.99 美元 | 3.75 美元 |
| RosCloud-06 | 24GB | 320GB | 500Mbps | 6144GB | 69.99 美元 | 2.92 美元 |
| LAX-STARTER | 2GB | 40GB | 2000Mbps | 5000GB | 16.67 美元 | 8.33 美元 |
| LAX-MICRO | 4GB | 80GB | 4000Mbps | 10000GB | 33.33 美元 | 8.33 美元 |
| LAX-MEDIUM | 8GB | 160GB | 10000Mbps | 20000GB | 66.67 美元 | 8.33 美元 |
注意最右一列的规律:内存越大,每 GB 内存越便宜。 RosCloud 从 1GB 的 19.99 美元一路降到 24GB 的 2.92 美元;sixtynet 的年付机型因为是年付折算,每 GB 内存稳定在 8.33 美元。这意味着「加内存」这件事在价格上是有阶梯优惠的,一次加够比分两次加划算。
现在算 worker 数。 4GB 机器的可用内存是 4096MB 减 384MB 系统预留减 512MB MySQL buffer pool,等于 3200MB:
跑 PHP 8.1:3200MB 除以 90MB,等于 35 个 worker。
跑 PHP 8.3:3200MB 除以 120MB,等于 26 个 worker。
同样的机器,换个版本少了 9 个 worker,降幅 26%。 按每个 worker 处理一个并发请求算,你的高并发承载能力从 35 降到 26。如果你的站点在高峰时段并发正好在 26 到 35 之间,换版本就意味着开始排队。
2GB 机器:2048 减 384 减 256 等于 1408MB。8.1 是 15 个 worker,8.3 是 11 个,少了 4 个。
8GB 机器:8192 减 384 减 1024 等于 6784MB。8.1 是 75 个 worker,8.3 是 56 个,少了 19 个。
1GB 机器:1024 减 384 减 256 等于 384MB,扣掉刚才表格里算的余量后只剩 128MB,8.1 和 8.3 都只能开 1 个 worker。 这一档跑 PHP 8.3 是能跑的,但 1 个 worker 意味着完全没有并发能力,任何一个慢请求就把整站堵死。
所以第一个决策点就出来了:1GB 机器不要考虑 PHP 8.3。 这不是版本兼容问题,是物理内存问题。
第二个决策点是「换版本要不要加内存」。 把上面两个数字放一起算:
在 4GB 机器上,从 8.1 升到 8.3,worker 从 35 掉到 26。如果你需要保持 35 的并发能力,8.3 需要 35 乘 120MB 等于 4200MB,再加 384MB 系统和 512MB 数据库,等于 5096MB,也就是要升到 8GB 档。
RosCloud-03 是 39.99 美元/月,RosCloud-04 是 49.99 美元/月,差额是 10.00 美元/月,一年 120 美元。
这就是这笔账的答案:换 PHP 8.3 且要保持并发能力,4GB 用户的增量成本是每月 10 美元。 而如果你的实际并发只有 10 到 20,那 4GB 跑 8.3 的 26 个 worker 完全够用,一分钱都不用多花。
结论很清晰:先测你的真实并发峰值,再决定要不要加钱。 测并发的方法在第七节给。
三、兼容性雷区:这四类代码会直接报错

版本升级最大的风险不是性能,是有代码在旧版本里是「静默错误」的,升级后变成「显式报错」。 下面几类是最常踩的。
第一类:隐式 nullable 参数类型被移除。 PHP 8.4 才彻底移除 ?T 的隐式写法,但 8.1 到 8.3 之间,8.2 开始对某些隐式类型转换报弃用警告,8.3 开始对传入 null 给非 nullable 参数报弃用:
Deprecated: Implicit conversion from float 1.5 to int loses precision
升级前先把这些警告逼出来。 命令是:
php -d error_reporting=E_ALL -d display_errors=1 your-script.php
在 8.1 上跑一遍,把所有 Deprecated 都列出来。 8.1 上只是警告的,8.3 上大概率就变成错误了。
第二类:动态属性的弃用。 PHP 8.2 开始,给未声明的属性赋值会产生 Creation of dynamic property 弃用警告。这个问题在 WordPress 插件和 Laravel 老版本包里非常常见,因为它们的类可能没有严格声明属性。8.2 时代的兼容写法是在类里显式声明 #[AllowDynamicProperties] 属性。
第三类:utf8_encode 和 utf8_decode 被弃用。 这两个函数在 PHP 8.2 起被标记为弃用。它们的替代品是 mb_convert_encoding(),参数要改成 UTF-8:
// 旧写法
$out = utf8_encode($str);
// 新写法
$out = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
第四类:某些扩展在 8.3 里不再捆绑。 PHP 8.3 调整了部分扩展的默认启用状态。最典型的是 mysqlnd 相关的旧 ext/mysql(早就在 7.0 移除)和 tidy。更常见的情况是:你的代码用了某个 PECL 扩展,而这个扩展的 8.3 版本还没发布。
这一条是升级失败最常见的原因,而且和 PHP 本身无关。 检查清单:
php -m | sort > /tmp/modules-8.1.txt
# 切换到 8.3 后
php -m | sort > /tmp/modules-8.3.txt
diff /tmp/modules-8.1.txt /tmp/modules-8.3.txt
这个 diff 出来的缺失项,就是你升级后启动就会报错的东西。 如果缺的是 redis、imagick、memcached 这类你确实在用的,那必须先等扩展出 8.3 版本,或者改用容器化的方式把扩展装在独立层。
第五个雷区其实不是报错,是静默行为变化:数字字符串比较。 PHP 8.0 引入的「数字字符串」比较规则改变,在 8.1 到 8.3 之间一直存在,但很多老代码里的 0 == "abc" 这种写法在 8.0 之后返回 false 了。如果你看到升级后某个判断「永远不成立」,第一反应应该是这里。
怎么一次性排查这五类问题? 用静态分析工具。PHPStan 或 Psalm 在检查时会同时报告弃用调用和类型不匹配:
composer require --dev phpstan/phpstan
./vendor/bin/phpstan analyse --level=5 src/
level 5 已经能覆盖上面大部分问题,且不会因为过度严格产生大量噪音。 level 8 以上对老项目基本跑不过,不建议一步到位。
四、升级步骤:双版本并存,不要直接覆盖

这一步的关键:不要在现有机器上直接 apt upgrade php,也不要删掉 8.1。 双版本并存,出问题秒回滚。
Debian / Ubuntu 系统的正确做法是装两个包名:
sudo apt update
sudo apt install php8.1-fpm php8.3-fpm php8.3-cli php8.3-mysql php8.3-curl php8.3-mbstring php8.3-xml php8.3-zip
注意包名带版本号,php8.3-fpm 和 php8.1-fpm 可以同时安装互不冲突。 这就是双版本并存的基础。
先确认两个版本都在:
ls /etc/php/
# 应该看到 8.1 和 8.3 两个目录
然后检查扩展完整性。 把 8.1 已装的扩展对照着装到 8.3 上:
php8.1 -m | grep -v "^\[" | sort > /tmp/m81
php8.3 -m | grep -v "^\[" | sort > /tmp/m83
comm -23 /tmp/m81 /tmp/m83
输出的每一行都是 8.3 缺的扩展,挨个装上对应包。
配置新版本的 PHP-FPM。 复制 8.1 的配置改路径:
sudo cp /etc/php/8.1/fpm/pool.d/www.conf /etc/php/8.3/fpm/pool.d/www.conf
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
改三处关键项。 第一是 socket 路径,必须和 8.1 不同,否则两个版本抢同一个 socket:
listen = /run/php/php8.3-fpm.sock
第二是 worker 数,按第二节算出来的数字填。 4GB 机器跑 8.3 填 26,但实际配置应该留余量,填 20 到 22 更稳:
pm = dynamic
pm.max_children = 22
pm.max_requests = 500
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
第三是 opcache 配置。 这一节后面单独讲。
改 Nginx 指向新 socket。 在站点的 server 块里:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
改完先验证,不要直接 reload:
sudo nginx -t
测试通过才 reload:
sudo systemctl reload nginx
然后用一个测试文件验证真的走了 8.3:
<?php echo PHP_VERSION;
放在站点根目录用浏览器访问,看到 8.3.x 才算成功。 这个验证步骤不能省——因为 Nginx 配置可能有多个 server 块,你改的未必是实际生效的那个。
回滚方式极其简单,这是双版本并存的最大价值:
# 把 fastcgi_pass 改回 8.1
sudo nginx -t && sudo systemctl reload nginx
改一行配置、reload 一下就回滚了,不需要重装、不需要恢复备份、不会丢数据。
这里还要补一个容易被忽略的细节:8.1 的 pool 配置要提前备份。 因为很多人在做升级时会把 www.conf 覆盖掉,回滚时才发现原来的 pm.max_children 记错了:
sudo cp /etc/php/8.1/fpm/pool.d/www.conf /root/www.conf.8.1.bak
sudo cp /etc/php/8.3/fpm/pool.d/www.conf /root/www.conf.8.3.bak
这两行备份命令花两秒钟,能省掉回滚时重新猜参数的一小时。
还有一个和数据库相关的点:8.1 和 8.3 的应用能否共用同一个 MySQL? 答案是可以,PHP 版本和 MySQL 版本是两条独立的轴。MySQL 的客户端协议在 PHP 里由 pdo_mysql 和 mysqli 实现,8.1 和 8.3 用的都是同一套协议,连同一个数据库不需要任何改动。所以双版本并存期间,两个版本的站点可以指向同一个库,这让灰度切换成为可能:先把 10% 流量切到 8.3 观察一天,再全量。
做灰度的话,Nginx 里按域名或路径分流就行:
server {
server_name new.example.com;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
# 其他配置与旧站一致
}
新域名验证没问题后,再把主域名切过去。 这个做法比一次性切换稳妥得多,而且回滚只需要把 DNS 改回来,连 Nginx 都不用动。
五、常见报错:看到原文就知道怎么处理

升级过程中会遇到的报错,按原文对照处理。
| 报错原文 | 含义 | 处理 |
|---|---|---|
PHP Warning: PHP Startup: Unable to load dynamic library 'redis.so' |
扩展没装或版本不匹配 | 用 php8.3 -m 确认,装对应 8.3 版本的扩展包 |
Deprecated: Creation of dynamic property X::$y |
动态属性弃用(8.2 起) | 显式声明属性或加 #[AllowDynamicProperties] |
Deprecated: Implicit conversion from float to int loses precision |
隐式类型转换弃用 | 显式写 (int) 转换,配合 PHPStan 逐个修 |
Call to undefined function json_validate() |
8.3 独有函数在 8.1 上不存在 | 升级到 8.3,或做函数存在性判断 function_exists() |
PHP Fatal error: Allowed memory size exhausted |
内存不够,通常是脚本本身泄漏 | memory_limit 只是拖延,要找泄漏点 |
502 Bad Gateway + connect() failed (111: Connection refused) |
FPM 没起来或 socket 路径不对 | ls -l /run/php/ 看实际 socket 名,对齐 Nginx 配置 |
nginx: [emerg] socket "/run/php/php8.3-fpm.sock" failed |
socket 尚未创建 | 先启动 sudo systemctl start php8.3-fpm 再 reload nginx |
Your requirements could not be resolved(Composer) |
某个包还不支持 8.3 | composer why-not php 8.3 看是哪个包卡住 |
class not found: Redis |
扩展加载了但类没注册 | 检查 php8.3 -m 里有没有 redis,且 php.ini 没把它禁用 |
「Composer 的 why-not」这一条值得单独强调,它是排查依赖地狱最快的工具:
composer why-not php 8.3
输出会直接告诉你哪个包挡路,以及它的最低 PHP 版本要求。 很多老包卡在 PHP 8.0 或 8.1 支持上,而这种包在 8.3 上同样能跑(只是没有官方声明支持),所以你有两个选择:等它更新,或者用 --ignore-platform-req=php 强制安装。后者要谨慎,装完必须完整跑一遍回归测试。
关于 Allowed memory size exhausted 这条要展开说,因为它经常被误解。 很多人第一反应是去改 php.ini 里的 memory_limit:
memory_limit = 256M
在小内存 VPS 上,把 memory_limit 调大是危险的。 因为 PHP-FPM 有多个 worker,每个 worker 都能用到 memory_limit 上限,一个 worker 吃 256MB、20 个 worker 就是 5GB,直接把机器送进 OOM。
正确的做法是:memory_limit 设成 worker 内存的一半左右(4GB 机器跑 8.3 时设 128M 到 192M),让单个脚本在可控范围内失败,而不是把整台机器拖垮。 排查真正的泄漏点用:
# 看哪个脚本最耗内存
grep -r "memory_get_peak_usage" src/ | head
这一条和第一节的算账是同一件事的两面。 第一节算出 4GB 机器跑 8.3 时 worker 上限是 26 个,第六节算出 OPcache 要占 192MB,这两笔加起来是 3120MB,加上系统的 384MB 和数据库的 512MB 是 4016MB,已经贴到 4096MB 的天花板了。 这就是为什么 memory_limit 不能随便调大——它实际上是每个 worker 的内存上限,是 26 份而不是 1 份。
要确认脚本有没有内存泄漏,最直接的办法是观察 worker 的常驻内存是否随时间上涨:
ps -eo pid,etimes,rss,comm | grep php-fpm
rss 列是常驻内存 KB,etimes 是进程已运行的秒数。 如果一个运行了几小时的 worker 的 rss 是 800MB,而刚起的新 worker 只有 150MB,那这个 worker 里跑过的某个脚本有泄漏。 这时候 pm.max_requests = 500 就是解药:让 worker 每处理 500 个请求就重启一次,泄漏被自动清空。这个参数的价值在有泄漏的站点上远大于在正常站点上。
六、OPcache 配置:这是升级后最该调的一步

OPcache 是 PHP 的字节码缓存,关掉它和开着它,页面响应时间能差 3 到 5 倍。 很多人升级完发现「好像也没快多少」,问题不在版本,在 OPcache 没配好。
先看当前状态:
php8.3 -i | grep -A 12 "^opcache.enable"
关键项的推荐值(4GB 机器、8.3 版本):
; /etc/php/8.3/fpm/php.ini 或 conf.d/99-opcache.ini
opcache.enable = 1
opcache.memory_consumption = 192
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60
逐条解释这些值的含义和为什么这么配。
opcache.memory_consumption = 192 是内存账的另一半。 这个值是 OPcache 预分配的内存,它和 PHP-FPM 是共享同一个内存池的。4GB 机器上设 192MB 是合理起点:不能超过总内存的 8% 左右。如果设成默认的 128MB 加上 22 个 worker 各 120MB,等于 128 + 2640 等于 2768MB,加上系统的 384MB 和数据库的 512MB 已经 3664MB,逼近 4096MB。 这就是为什么很多 4GB 机器跑着跑着就 OOM 了——OPcache 那 192MB 很多人根本没算进去。
opcache.max_accelerated_files = 20000 决定能缓存多少个 PHP 文件。 默认值 10000 在 WordPress 加插件的环境下经常不够用——一个装了几个插件的 WordPress 站点轻松就有一两千个 PHP 文件,加上框架和 vendor 目录,10000 可能会被撑满。 撑满后的表现是:日志里出现 Zend OPcache seems to be disabled - too many cached files 警告,缓存写入失败,性能等于没开。 所以这个值要往上设。
opcache.validate_timestamps = 1 和 revalidate_freq = 60 的组合是开发环境的安全选择。 前者让 OPcache 每个请求都检查文件修改时间,后者把检查间隔压到 60 秒。代价是每次请求多一次 stat 调用。 生产环境可以关掉(validate_timestamps = 0),但这样改了代码不会生效,必须 sudo systemctl reload php8.3-fpm 手动重载。如果你在生产环境并且用 CI 部署,关掉它能让响应再快一点。
opcache.interned_strings_buffer = 16 这个值和字符串驻留有关。 8.3 相对 8.1 在这里有个值得注意的点:8.3 的 interned strings 内存效率更好,同样的设置能承载更多字符串。 但 16MB 对小站是够的,别无脑调大。
改完必须重启 FPM 才生效:
sudo systemctl restart php8.3-fpm
验证 OPcache 真的在工作:
php8.3 -r 'var_dump(opcache_get_status(false));'
输出里的 opcache_enabled 应该是 true,memory_usage 显示已用字节数,cached_scripts 显示缓存的文件数。 如果 cached_scripts 是 0 或者很小,说明没生效。
还有一个容易忽略的收益:OPcache 会降低 PHP worker 的 CPU 占用,间接让同样的机器扛更多并发。 这也是本文把 OPcache 单独列一节的原因——它不是「优化项」,是「配置正确与错误差一倍以上」的那类开关。
七、怎么测你到底需要多少并发

第二节的账要成立,前提是你知道自己的真实并发。 这一节给出可执行的方法。
方法一:用 PHP-FPM 的状态页,最直接。 启用状态页:
; /etc/php/8.3/fpm/pool.d/www.conf
pm.status_path = /fpm-status
ping.path = /fpm-ping
Nginx 里加一段:
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
allow YOUR_SERVER_IP;
deny all;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
然后访问 /fpm-status,输出的关键三行:
active processes: 12
idle processes: 10
total processes: 22
active processes 的历史最大值乘以 1.5,就是你需要预留的 worker 数。 为什么乘 1.5:峰值是瞬时的,而机器从空闲恢复到满载需要预热(pm.start_servers 要逐批拉起),留 50% 余量才能在峰值到来时不排队。
在正常业务高峰(比如你订单最多的那个小时)采样一次,记下 active processes 的最大值。 这个数字乘 1.5,然后对照第二节的表:
乘完的数小于等于 11(2GB 机器 8.3 的上限),选 2GB 就够。
在 12 到 26 之间,选 4GB。
在 27 到 56 之间,选 8GB。
大于 56,考虑 16GB 起步。
方法二:从 Nginx 访问日志算并发。 没有 FPM 状态页权限时可以用这个。Nginx 日志格式里加上 $request_time 和 $upstream_response_time,然后统计「同一秒内的请求数」的峰值:
log_format main '$remote_addr $time_local $request_time $upstream_response_time';
一条 awk 命令就能算出每秒最大请求数:
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f3 | sort | uniq -c | sort -rn | head -5
输出第一列是那一秒的请求数。 这个数字是「到达量」,比 FPM 的 active processes 更保守(因为它包含了请求排队的时间),用它乘 2 就是保守的 worker 数需求。
方法三:用 ab 做压测,但只测你自己能承受的量。 不要在生产机上压测,会挤掉真实用户:
ab -n 500 -c 20 https://your-domain.com/
-c 20 是并发数。 从 5 开始往上加,每加一次观察响应时间和错误率。关注的指标是 Failed requests 必须为 0,Time per request 在 0.3 秒以内。
这三个数字构成你的验收阈值:首字节时间不超过 300 毫秒、1MB 静态资源下载不超过 2 秒、FPM 的 active processes 峰值不超过 pm.max_children 的 80%。
为什么要卡 80% 这个线? 因为 FPM 的 worker 是复用的,一个 worker 处理完请求后要清理请求上下文再处理下一个,100% 占满意味着每个请求都要等前一个完全清理完,等于每个请求都多了一段串行时间。 留 20% 空转,吞吐反而更高。
八、什么情况下不该升到 PHP 8.3

这一节讲「什么时候升 8.3 是错的」,依据只用公开事实:PHP 官方支持周期、扩展的发布状态、内存的物理上限。
场景一:你的核心依赖还没声明支持 8.3。 判断依据是 composer why-not php 8.3 的输出。如果卡住的是你业务的核心包(比如一个关键的老版支付 SDK),那么升级不是「版本选择问题」而是「依赖问题」,正确做法是等该包更新,或者把支付环节隔离成独立服务。 替代方案是继续用 8.1,这不是妥协,8.1 本身是更成熟的分支,插件生态的兼容性问题更少。
场景二:你的机器是 1GB 档。 依据是第二节算出的 worker 数:1GB 机器扣掉系统和数据库只剩 128MB 可用,8.1 和 8.3 都只能开 1 个 worker。在 1GB 机器上讨论 8.1 还是 8.3 是个伪命题,两个版本都跑不动。 替代方案是直接选 2GB 起步(LAX-STARTER 折合 16.67 美元/月、RosCloud-02 是 29.99 美元/月),或者如果站点是纯静态,就不要装 PHP。
场景三:你的站点是静态站或者只有后台偶尔改内容。 依据是 ps 输出里没有 php-fpm 进程,或者 php-fpm 的 active processes 长期为 0。静态站跑 PHP 是纯粹的浪费——既占内存又占 CPU。 替代方案是用静态托管方案,把机器只用来跑数据库或者后台任务。这类场景下 PHP 版本完全不重要,把预算花在带宽和硬盘上更划算。
场景四:你的服务器没有第二个 PHP 版本可并存。 依据是 ls /etc/php/ 只有一个版本目录。单版本机器上做升级是风险最高的方式——升级过程中一旦出问题,回滚需要重装整个 PHP 环境加上重配所有站点的 pool 配置。 替代方案是先用新开一台机器做验证(按月付最低档,比如 LAX-STARTER 16.67 美元/月),验证通过后再迁移。这一条在新手的技术栈里几乎总是对的。
场景五:你的站点 PHP 版本已经因为插件强制锁死。 依据是某些 CMS 或建站面板(宝塔、WordPress 的部分托管方案)会锁定版本。这时候强行升级等于和面板的自动升级机制打架,几天后又被改回去。 替代方案是接受现状,把精力放在 OPcache 和 worker 数调优上——在 8.1 上把 OPcache 配好,收益通常比从 8.1 升到 8.3 大得多。
九、给四类人的具体版本与配置建议

直接照做,不用再比。
第一类:个人博客、WordPress 小站,日均 1 万 PV 以内。 用 PHP 8.1,不要升 8.3。 理由很实在:你的并发峰值大概率不超过 10,8.1 在 2GB 机器上能开 15 个 worker,8.3 在同机器上只有 11 个,而 8.1 的插件兼容性明显更好。机器选 LAX-STARTER(16.67 美元/月,2GB 内存,每 GB 内存 8.33 美元,是全库同内存档里最便宜的一档)或者 RosCloud-02(29.99 美元/月)。但如果你想省钱,记住 PHP 8.1 每 worker 90MB 内存这个数:2GB 机器开 15 个 worker,实际业务用不到 5 个,那降到 1GB 配 8.1 也够(1 个 worker... 不行,1GB 只剩 128MB)——所以 2GB 是这一档的下限。 更好的省钱方式是用静态化方案替代 PHP。
第二类:日均 10 万 PV 起步的电商或业务系统,有真实并发峰值。 用 PHP 8.3,选 4GB 起步。 具体是 LAX-MICRO(33.33 美元/月,4GB 内存,每 GB 内存 8.33 美元,4000Mbps 带宽,10000GB 流量)或者 RosCloud-03(39.99 美元/月,4GB,每 GB 内存 10.00 美元)。4GB 跑 8.3 的 worker 上限是 26 个,按第七节的方法测出你的峰值乘 1.5,如果结果在 20 以内就直接上 26 留余量。 这一档的必做项有三个:OPcache 必开(memory_consumption 设 192MB)、pm.max_requests 设 500、MySQL 的 innodb_buffer_pool_size 改到 512M。三件事不做,换版本也白搭。
第三类:多站点、或者有 Worker 队列的团队业务。 用 PHP 8.3,选 8GB 起步,流量按 10000GB 起。 具体是 LAX-MEDIUM(66.67 美元/月,8GB 内存,每 GB 内存 8.33 美元,10000Mbps,20000GB 流量)或者 RosCloud-04(49.99 美元/月,8GB,每 GB 内存 6.25 美元,500Mbps,4096GB 流量)。8GB 跑 8.3 的 worker 上限是 56 个,8.1 是 75 个——如果你的队列任务很吃内存,8.3 的 56 个 worker 会让单任务的内存占用高 33%,这时候要重新测峰值。 这一档还有一个必须确认的事:队列进程和 web 进程是不是在同一台机器上。 如果是,队列的内存占用没有上限,会把 web worker 全挤掉。正确做法是给队列单独限制内存,或者干脆分机器部署。
第四类:纯静态站、企业官网展示、或者只用 WordPress 后台改内容。 不要装 PHP。 直接用静态托管,或者只用一个极低配的机器跑后台。这一类应该把钱花在带宽和硬盘上,不是内存。 如果确实要保留 PHP 后台,选 LAX-Storage-500G(33.33 美元/月,4GB 内存、500GB 硬盘、10000Mbps 带宽、10000GB 流量,每 GB 硬盘只要 0.067 美元)这种存储带宽型机型,内存够跑后台就行。
按你的情况,下一步该看哪家
上面讲的是判断标准,但多数人最后还是想问一句「那我该买谁」。按你的实际情况对照下面几条,直接去看对应的机型页比继续比价更快:
- 只想搭个站、预算优先:先看价格最低那档够不够用,别为用不上的配置付钱。看 iwebfusion 当前机型与价格
- 做跨境或店群、需要多 IP:优先看 IP 类型与换 IP 政策,别只看配置。看 racknerd 当前机型与价格
- 只是开发测试、临时用:按小时或月付,用完就删,别买年付。看 cloudcone 当前机型与价格
价格与库存以商家页面当日显示为准,下单前建议先确认退款窗口与是否支持按月付费。
十、完整落地清单:照着做不会出错

把全文压缩成一个可以照着走的顺序。
第 1 步:先测并发,不急着升级。 按第七节的方法拿到 active processes 的历史峰值。这一步步序最重要——在不知道并发需求的情况下选版本,必然浪费。
第 2 步:算 worker 数。 用第二节的公式:可用内存除以每 worker 内存(8.1 是 90MB,8.3 是 120MB)。再用实测峰值乘 1.5 验证,两个数字取小的那个作为 pm.max_children。
第 3 步:决定升不升。 跑 composer why-not php 8.3。如果输出为空或者只有一两个边缘包,升;输出里有核心业务包,不升,先优化 8.1。
第 4 步:双版本并存安装。 按第四节的命令装 php8.3-fpm,保留 8.1 不删。 用 comm -23 对比扩展清单,把缺的补齐。
第 5 步:配 8.3 的 pool 和 OPcache。 socket 路径改掉、worker 数填第二步的结果、OPcache 四个参数按第六节配。
第 6 步:切 Nginx 前先验证。 sudo nginx -t 通过再 reload,然后用 <?php echo PHP_VERSION; 确认真的走了 8.3。
第 7 步:验收三个数字。 首字节时间不超过 300 毫秒、1MB 静态资源下载不超过 2 秒、active processes 峰值不超过 pm.max_children 的 80%。 任一不达标就回滚。
第 8 步:观察一周再固化。 看 pm.max_requests = 500 有没有让内存曲线变平、opcache_get_status 的 cached_scripts 有没有涨到正常水平、CPU 使用率有没有降下来。三项都达标,再考虑把 validate_timestamps 关掉做最后一点优化。
关于回滚的最后提醒:回滚只需要把 Nginx 的 fastcgi_pass 改回 8.1 的 socket,然后 sudo nginx -t && sudo systemctl reload nginx。 这一行命令是你敢做升级的全部底气。所以第 4 步的「双版本并存」不是可选项,是升级的前提条件。
最后补一个运维细节:把版本选择写进部署文档。 如果你的团队有多个人在部署,「用哪个 PHP 版本」这种信息必须落在文件里,不能落在某个人的记忆里。 最简单的做法是在项目根目录放一个 .php-version 文件:
8.3.13
这个文件配合 phpbrew 或者 asdf 之类的版本管理工具,可以在本地和 CI 里自动切到对应版本。 它的内容应该和你在服务器上跑的实际版本一致,并且在每次生产发布时更新。
还有一个很多人会忽略的检查点:确认 PHP 版本不是只升了一半。 也就是 CLI 版本和 FPM 版本必须一致:
php -v | head -1
php-fpm8.3 -v | head -1
如果这两个输出显示的是不同版本,你会有一个诡异的现象:命令行里跑迁移脚本是 8.3 的行为,但网站上的代码跑的是 8.1 的行为。 有些命令(比如 composer install 触发的脚本、cron 任务里的 PHP 脚本)走的是 CLI 版本,这就会导致「测试环境过了、线上 cron 任务报错」这种难查的问题。 在 Debian 系上让它们对齐的方法是:
sudo update-alternatives --set php /usr/bin/php8.3
sudo update-alternatives --set php-config /usr/bin/php-config8.3
改完 php -v 确认版本正确,再跑一次 cron 里的脚本验证。

喜欢
高兴
鬼脸
呵呵
无聊
伤心