이 글은 주로 PHP 메모리 오버플로, 명령줄 및 웹 서비스의 두 가지 실행 방법에 대한 이해를 소개합니다. 이제는 필요한 친구들이 개발 과정에서 참고할 수 있도록 공유합니다. , 특정 데이터베이스에서 읽은 데이터의 양이 너무 크기 때문에 인터페이스는 200 상태를 반환하지만 응답 데이터가 없습니다. PHP 오류 로그에는 다음 정보가 포함됩니다. PHP 치명적인 오류: 허용되는 메모리 크기는 134217728바이트입니다. 탈진한.
분명히 Out of Memory로 인한 오류인데 의아한 점은 Yii 프레임워크의 비즈니스 로그(application.log)에 출력이 없고 페이지에 Stack Trace 오류 메시지도 없다는 점입니다. 원인을 조사하십시오.
이유는 다음과 같습니다. 먼저 Yii 프레임워크 CApplication.php 파일의 핵심 코드를 살펴보세요.
public function run() { if($this->hasEventHandler('onBeginRequest')) $this->onBeginRequest(new CEvent($this)); register_shutdown_function(array($this,'end'),0,false); $this->processRequest(); if($this->hasEventHandler('onEndRequest')) $this->onEndRequest(new CEvent($this)); }
비정상 종료가 발생할 경우 요청을 처리하기 전에 register_shutdown_function
을 사용하여 일반적으로 콜백을 등록합니다. , PHP가 비정상적인 스크립트 종료를 발견하면 end()
메소드가 다시 호출됩니다. onEndRequest
의 리스너에서 error_get_last()
를 사용할 수 있습니다. > 이 오류를 얻기 위한 이벤트입니다.
그러나 OOM이 발생하면 Linux Out Of Memory 킬러는 kill -9를 실행하여 SIGKILL 신호를 보냅니다. PHP 설명서의 지침에 따르면 SIGKILL 신호를 캡처하고 가로챌 수 없으며 PHP 스크립트가 직접 종료됩니다. 정리 코드는 실행되지 않으므로 register_shutdown_function
메서드가 작동하지 않으며 당연히 후속 로깅, 오류 페이지 표시 및 기타 프로세스가 발생하지 않습니다. register_shutdown_function
注册异常终止时的回调,正常来说,PHP 出现异常脚本终止时会回调 end()
方法,在 onEndRequest
事件的监听器中可以使用 error_get_last()
获取到本次错误。
但是,当 OOM 发生时,Linux Out Of Memory killer 会执行 kill -9 发送 SIGKILL 信号,根据 PHP 手册中的说明, SIGKILL 信号无法捕获和拦截,PHP 脚本会直接退出,任何清理代码都不会执行,所以 register_shutdown_function
方法不会发挥作用,自然也不会有后续的日志记录、错误页面显示等流程。
另外在开发中注意到一个现象:通过 Web 访问会出现 OOM,但通过 Console 执行就不会报错。
由此可见两种方式是有区别的,Web 访问时,PHP 脚本进程由 PHP-FPM启动,还要受 FPM 配置文件限制,/etc/php-fpm.d里配置文件有 php_admin_value[memory_limit] = 128M 限制。所以通过 Web 访问时,仅增加 php.ini 中的 memory_limit 无效。
而 Console 方式执行不经过 PHP-FPM,所以仅受 php.ini 中配置的内存参数限制,而开发机中配置的 memory_limit => 512M => 512M,所以此时不会产生 OOM。
这里有个疑问,从实现原理的角度,PHP-FPM 是如何对 PHP 进程管理的?PHP-FPM 真的会用 kill -9 杀死 PHP 脚本进程么?
附上 WebServer、PHP-FPM、PHP 脚本的调用关系:
请求首先进入 Web 服务器(如 Nginx),Nginx 分发请求(依据server节点、location节点等配置):
请求静态资源不需要 FastCGI 处理,直接转到相应文件位置
动态请求需要 PHP 代码处理,则需要把请求交给实现了 FastCGI 协议的程序(PHP-FPM)
可以在Nginx看到这样的配置信息:“fastcgi_pass 127.0.0.1:9000;”,执行命令“lsof -i:9000”可以看到9000端口刚好是PHP-FPM进程。
Nginx 将请求信息传给了 PHP-FPM,PHP-FPM 分配一个 Worker 进程处理,Worker 进程注册变量 $_GET/$_POST
等,根据请求信息访问指定的 PHP 脚本文件,然后使用 PHP 解释器执行。
(我的理解是:相当于 PHP-FPM 启动了 PHP 解释器,有点像执行了 php -f script.php
$_GET/$_POST
등을 등록하고 지정된 PHP 스크립트에 액세스합니다. 요청 정보에 따라 파일을 생성한 다음 PHP 인터프리터를 사용하여 실행합니다. php -f script.php
명령을 실행하는 것과 비슷합니다) 🎜🎜네트워크 요청 정보가 레이어에 전달됩니다. 계층별로 마침내 PHP에 도달하므로 이 HTTP 요청의 다양한 매개변수를 PHP 코드에서 얻을 수 있습니다. 🎜🎜Nginx는 실행할 PHP 스크립트를 PHP-FPM에 알려줍니다. 🎜fastcgi_param SCRIPT_FILENAME /home/dev_user/www/xxx/webroot/index.php;🎜PHP 파일을 지정하지 않으면 index.php 파일을 사용해 보세요. 루트 디렉터리에 있습니다. 프레임워크 프로그램은 index.php에서 시작되며, 프레임워크는 실제 비즈니스 로직을 완성하기 위해 해당 컨트롤러와 액션을 찾습니다. 🎜
위 내용은 PHP 메모리 오버플로, 명령줄 및 웹 서비스 실행 방법에 대한 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!