PHP 运行时错误导致服务中断,通常不是“代码报错”这么简单,而是会引发:
- 502 Bad Gateway
- 504 Gateway Timeout
- 白屏
- PHP-FPM 崩溃
- 进程被系统 Kill
下面给你一套 生产环境级别的完整分析与解决方案。
一、最常见的 7 大原因
1️⃣ 致命错误(Fatal Error)
典型报错:
Uncaught Error: Call to undefined function
Uncaught Error: Class not found
Allowed memory size exhausted
原因
- 调用不存在函数
- 自动加载失败
- 内存溢出
- 类型错误(PHP 8 更严格)
解决方案
error_reporting(E_ALL);
ini_set('display_errors', 1);
生产环境:
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_error.log');
2️⃣ 内存溢出(Memory Exhausted)
报错:
Allowed memory size of 134217728 bytes exhausted
原因
- 大数组循环
- 无限递归
- 一次性读取大文件
- 查询百万数据
解决
php.ini:
memory_limit = 512M
代码优化(不要这样):
$data = $db->query("SELECT * FROM big_table")->fetchAll();
改为分页:
SELECT * FROM big_table LIMIT 1000
3️⃣ 无限循环 / 死循环
典型:
while(true){
}
或递归无终止条件。
后果
- CPU 100%
- PHP-FPM 进程卡死
- 服务全部阻塞
解决
- 设置超时:
set_time_limit(30);
- 代码加终止条件
4️⃣ 外部接口阻塞
最常见真实问题。
file_get_contents("http://api.xxx.com");
默认无超时,会一直卡住。
正确写法
$context = stream_context_create([
'http' => [
'timeout' => 5
]
]);
file_get_contents($url, false, $context);
或 cURL:
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
5️⃣ 数据库锁表 / 慢查询
表现:
- 接口偶发超时
- 高峰期全部崩溃
排查:
SHOW PROCESSLIST;
如果看到:
Locked
Waiting for table metadata lock
说明锁住了。
解决
- 加索引
- 避免事务太大
- 拆分大 SQL
6️⃣ PHP-FPM 进程耗尽
如果:
pm.max_children = 5
并发 10 个请求就会排队。
表现:
- 高峰期 502
- Nginx upstream timed out
解决:
pm.max_children = 50
重启:
systemctl restart php8.x-fpm
7️⃣ 致命异常未捕获
PHP 8 严格类型后很常见:
function test(int $a){}
test("abc");
会直接 Fatal。
解决
使用 try/catch:
try {
test("abc");
} catch (Throwable $e) {
error_log($e->getMessage());
}
二、导致“服务中断”的真正原因
很多人误以为是“代码报错”。
实际上服务中断通常来自:
| 问题 | 本质 |
|---|---|
| 502 | PHP-FPM 崩了 |
| 504 | 执行太慢 |
| 白屏 | Fatal Error |
| 高峰期崩溃 | 进程耗尽 |
三、生产环境必须做的 8 个防护
✅ 1. 永远不要开启 display_errors
生产必须:
display_errors = Off
log_errors = On
✅ 2. 全局异常捕获
set_exception_handler(function($e){
error_log($e->getMessage());
});
✅ 3. 全局错误捕获
set_error_handler(function($errno,$errstr){
error_log($errstr);
});
✅ 4. 注册致命错误捕获
register_shutdown_function(function(){
$error = error_get_last();
if($error){
error_log(json_encode($error));
}
});
✅ 5. 开启慢日志
php-fpm.conf:
request_slowlog_timeout = 5s
slowlog = /var/log/php_slow.log
✅ 6. 限制最大执行时间
max_execution_time = 30
✅ 7. 使用队列处理耗时任务
不要让接口做:
- 发邮件
- 导出大数据
- 批量更新
用:
- Redis 队列
- RabbitMQ
✅ 8. 加缓存
Redis 缓存可以减少 90% 超时。
四、真实线上崩溃案例
案例1:日志写满磁盘
error.log 30G
磁盘 100% → MySQL 无法写入 → 服务崩溃
解决:
logrotate
案例2:递归死循环
CPU 100%
FPM 卡死
解决:限制递归层数
案例3:接口无超时设置
第三方API卡 120 秒
Nginx 60 秒超时 → 504
解决:设置 curl timeout
五、快速排查命令
CPU:
top
内存:
free -m
FPM 状态:
ps aux | grep php-fpm
Nginx 日志:
/var/log/nginx/error.log
六、终极总结
PHP 运行时错误导致服务中断,本质只有 4 种:
- 内存爆了
- 执行卡住
- 并发太大
- 配置太小
如果你愿意,我可以给你:
- 🔥 企业级 PHP 稳定性加固完整方案
- 🔥 Nginx + PHP-FPM 最佳生产配置
- 🔥 高并发接口优化架构图
- 🔥 线上故障排查流程图
你现在的环境是:
- PHP 版本?
- Nginx 还是 Apache?
- 报什么具体错误?
给我具体报错,我帮你精准定位。
发表回复