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());
}


二、导致“服务中断”的真正原因

很多人误以为是“代码报错”。

实际上服务中断通常来自:

问题本质
502PHP-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 种:

  1. 内存爆了
  2. 执行卡住
  3. 并发太大
  4. 配置太小

如果你愿意,我可以给你:

  • 🔥 企业级 PHP 稳定性加固完整方案
  • 🔥 Nginx + PHP-FPM 最佳生产配置
  • 🔥 高并发接口优化架构图
  • 🔥 线上故障排查流程图

你现在的环境是:

  • PHP 版本?
  • Nginx 还是 Apache?
  • 报什么具体错误?

给我具体报错,我帮你精准定位。