>백엔드 개발 >PHP 튜토리얼 >PHP 메모리 오버플로, 명령줄 및 웹 서비스 실행 방법에 대한 이해

PHP 메모리 오버플로, 명령줄 및 웹 서비스 실행 방법에 대한 이해

不言
不言원래의
2018-05-31 16:53:252087검색

이 글은 주로 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节点等配置):

  1. 请求静态资源不需要 FastCGI 处理,直接转到相应文件位置

  2. 动态请求需要 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

그리고 개발 중 한가지 현상을 발견했습니다. 웹으로 접속하면 OOM이 발생하는데, 콘솔로 실행하면 오류가 보고되지 않습니다.

두 가지 방법에는 차이가 있음을 알 수 있습니다. 웹에 액세스할 때 PHP 스크립트 프로세스는 PHP-FPM에 의해 시작되고 또한 /etc/php-의 구성 파일에 의해 제한됩니다. fpm.d에는 php_admin_value[memory_limit] = 128M 제한이 있습니다. 따라서 단순히 php.ini에서 memory_limit를 늘리는 것은 웹을 통해 액세스할 때 아무런 효과가 없습니다.

콘솔 모드 실행은 PHP-FPM을 거치지 않기 때문에 php.ini에 구성된 메모리 매개 변수와 개발 머신에서 구성된 memory_limit => 512M => 512M에 의해서만 제한되므로 이때 OOM이 발생하지 않습니다. 시간.

여기서 질문이 있습니다. 구현 원칙의 관점에서 PHP-FPM은 PHP 프로세스를 어떻게 관리합니까? PHP-FPM은 실제로 PHP 스크립트 프로세스를 종료하기 위해 kill -9를 사용합니까? 🎜
🎜WebServer, PHP-FPM 및 PHP 스크립트 간의 호출 관계는 첨부되어 있습니다.🎜🎜 요청은 먼저 웹 서버(예: Nginx)에 들어가고 Nginx는 요청( 서버 노드, 위치 노드 등에 따라 구성): 🎜
  1. 🎜정적 리소스 요청에는 FastCGI 처리가 필요하지 않으며 해당 파일 위치로 직접 이동합니다🎜
  2. 🎜동적 요청에는 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 인터프리터를 시작하는 PHP-FPM과 동일하며, 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.