>  기사  >  백엔드 개발  >  PHP-FPM 기반 프로세스 풀 탐색

PHP-FPM 기반 프로세스 풀 탐색

coldplay.xixi
coldplay.xixi앞으로
2020-08-08 16:42:142675검색

PHP-FPM 기반 프로세스 풀 탐색

PHP는 멀티 프로세스를 지원하지만 멀티 스레딩은 지원하지 않습니다. PHP-FPM은 프로세스 풀에서 여러 하위 프로세스를 실행하여 모든 연결 요청을 동시에 처리합니다. 다음과 같이 ps를 통해 PHP-FPM 프로세스 풀(pm.start_servers = 2)의 상태를 확인합니다.

root@d856fd02d2fe:~# ps aux -L
USER  PID LWP %CPU NLWP %MEM VSZ RSS TTY  STAT START TIME COMMAND
root   1  1 0.0 1 0.0 4504 692 ?  Ss 13:10 0:00 /bin/sh /usr/local/php/bin/php-fpm start
root   7  7 0.0 1 0.4 176076 19304 ?  Ss 13:10 0:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
www-data  8  8 0.0 1 0.2 176076 8132 ?  S 13:10 0:00 php-fpm: pool www
www-data  9  9 0.0 1 0.2 176076 8132 ?  S 13:10 0:00 php-fpm: pool www
root  10 10 0.0 1 0.0 18376 3476 ?  Ss 14:11 0:00 bash
root  66 66 0.0 1 0.0 34420 2920 ?  R+ 15:13 0:00 ps aux -L

관련 학습 권장사항: php 프로그래밍(동영상)

목록에서 볼 수 있듯이 거기에 프로세스 풀 www에는 두 개의 프로세스가 있습니다. 아직 유휴 상태인 두 개의 하위 프로세스 PID 8과 PID 9가 있습니다. 참고: NLWP는 경량 프로세스 수, 즉 스레드 수를 나타냅니다.

PHP-FPM(FastCGI 프로세스 관리자)이란 무엇입니까? PHP-FPM은 메모리와 프로세스를 효과적으로 제어하고 PHP 구성을 원활하게 다시 로드할 수 있는 PHP-CGI용 프로세스 관리 방법을 제공합니다. FastCGI는 언어 독립적이고 확장 가능한 아키텍처인 CGI 개방형 확장입니다. 주요 동작은 포크 앤 실행이 아닌 CGI 인터프리터 프로세스를 메모리에 오랫동안 유지하여 더 높은 성능을 얻는 것입니다. FastCGI는 분산 배포를 지원하며 웹 서버 이외의 여러 호스트에 배포할 수 있습니다.

탐색 방법: 다중 스레드 동시 실행 시뮬레이션

1. 스레드란 무엇입니까?스레드는 때때로 경량 프로세스(LWP)라고도 하며 일반적으로 스레드 ID, 현재 명령 포인터(PC), 레지스터 컬렉션(Collection)과 스택(Stack)으로 구성되며, 프로세스 내 개체로서 시스템이 독립적으로 스케줄링하는 기본 단위이다. 스레드 자체는 시스템 리소스를 소유하지 않으며, 운영에 꼭 필요한 일부 리소스만 공유한다. 동일한 프로세스에 속한 다른 스레드와 프로세스를 수행합니다. 스레드 간의 상호 제약으로 인해 스레드는 작업에 불연속성을 나타냅니다. 스레드에는 준비, 차단, 실행이라는 세 가지 기본 상태도 있습니다. 프로세스가 리소스 소유자이기 때문에 생성, 취소, 전환 오버헤드가 너무 높으므로 대칭형 다중 프로세서(SMP)에서 여러 스레드(스레드)를 동시에 실행하는 것이 더 적절한 선택입니다. 스레드 엔터티에는 프로그램, 데이터 및 스레드 제어 블록(TCB)이 포함됩니다.

(1) 스레드 상태

(2) 스레드가 실행되지 않을 때 저장되는 현장 리소스.
(3) 실행 스택 세트


(4) 각 스레드의 로컬 변수를 저장하는 메인 메모리


(5) 동일한 프로세스에서 메인 메모리 및 기타 리소스에 액세스합니다.


그러나 여러 프로세스를 사용하면 프로세스 풀의 프로세스가 충돌하거나 공격을 받는 경우 애플리케이션이 더욱 강력해집니다.

2. 멀티스레딩 시뮬레이션:

<?php
/**
 * PHP 只支持多进程不支持多线程。
 *
 * PHP-FPM 在进程池中运行多个子进程并发处理所有连接,
 * 同一个子进程可先后处理多个连接请求,但同一时间
 * 只能处理一个连接请求,未处理连接请求将进入队列等待处理
 *
 */

class SimulatedThread
{
 //模拟线程
 private $thread;

 //主机名
 private $host = &#39;tcp://172.17.0.5&#39;;

 //端口号
 private $port = 80;

 public function __construct()
 {
  //采用当前时间给线程编号
  $this->thread = microtime(true);
 }

 /**
  * 通过socket发送一个新的HTTP连接请求到本机,
  * 此时当前模拟线程既是服务端又是模拟客户端
  *
  * 当前(程序)子进程sleep(1)后会延迟1s才继续执行,但其持有的连接是继续有效的,
  * 不能处理新的连接请求,故这种做法会降低进程池处理并发连接请求的能力,
  * 类似延迟处理还有time_nanosleep()、time_sleep_until()、usleep()。
  * 而且sleep(1)这种做法并不安全,nginx依然可能出现如下错误:
  * “epoll_wait() reported that client prematurely closed connection,
  * so upstream connection is closed too while connecting to upstream”
  *
  * @return void
  */
 public function simulate()
 {
  $run = $_GET[&#39;run&#39;] ?? 0;
  if ($run++ < 9) {//最多模拟10个线程
   $fp = fsockopen($this->host, $this->port);
   fputs($fp, "GET {$_SERVER[&#39;PHP_SELF&#39;]}?run={$run}\r\n\r\n");
   sleep(1);//usleep(500)
   fclose($fp);
  }

  $this->log();
 }

 /**
  * 日志记录当前模拟线程运行时间
  *
  * @return void
  */
 private function log()
 {
  $fp = fopen(&#39;simulated.thread&#39;, &#39;a&#39;);
  fputs($fp, "Log thread {$this->thread} at " . microtime(true) . "(s)\r\n");

  fclose($fp);
 }
}

$thread = new SimulatedThread();
$thread->simulate();
echo "Started to simulate threads...";
탐색 요약: 위 스크립트를 실행한 후 예측 가능했지만 내가 생각했던 것과는 다른 결과를 발견했습니다.

1. item pm.max_children = 5,simulated.thread 기록은 다음과 같습니다.

Log thread 1508054181.4236 at 1508054182.4244(s)
Log thread 1508054181.4248 at 1508054182.4254(s)
Log thread 1508054181.426 at 1508054182.428(s)
Log thread 1508054181.6095 at 1508054182.6104(s)
Log thread 1508054182.4254 at 1508054183.4262(s)
Log thread 1508054183.4272 at 1508054183.4272(s)
Log thread 1508054182.4269 at 1508054183.4275(s)
Log thread 1508054182.4289 at 1508054183.43(s)
Log thread 1508054182.6085 at 1508054183.6091(s)
Log thread 1508054182.611 at 1508054183.6118(s)
프로세스 풀의 최대 동시 연결 처리 용량이 5이므로 가장 최근에 생성된(시뮬레이션된) 스레드 등록이 빨간색으로 표시된 항목 위치에 나타납니다. 6번째 막대 다음 위치에만 나타날 수 있습니다.

Log thread 1508058075.042 at 1508058076.0428(s)
Log thread 1508058075.0432 at 1508058076.0439(s)
Log thread 1508058075.0443 at 1508058076.045(s)
Log thread 1508058075.6623 at 1508058076.6634(s)
Log thread 1508058076.0447 at 1508058077.0455(s)
Log thread 1508058076.046 at 1508058077.0466(s)
Log thread 1508058077.0465 at 1508058077.0466(s)
Log thread 1508058076.0469 at 1508058077.0474(s)
Log thread 1508058076.6647 at 1508058077.6659(s)
Log thread 1508058076.6664 at 1508058077.6671(s)

흥미로운 점은 녹색 항목으로 표시되는 (시뮬레이션된) 스레드와 빨간색 항목으로 표시되는 (시뮬레이션된) 스레드의 등록 시간이 동일하다는 점으로, 두 개의 (시뮬레이션된) 스레드가 동시에 실행됨을 나타냅니다.

2. PHP-FPM 구성 항목 pm.max_children = 10,simulated.thread 기록은 다음과 같습니다.

Log thread 1508061169.7956 at 1508061170.7963(s)
Log thread 1508061169.7966 at 1508061170.7976(s)
Log thread 1508061169.7978 at 1508061170.7988(s)
Log thread 1508061170.2896 at 1508061171.2901(s)
Log thread 1508061170.7972 at 1508061171.7978(s)
Log thread 1508061171.7984 at 1508061171.7985(s)
Log thread 1508061170.7982 at 1508061171.7986(s)
Log thread 1508061170.7994 at 1508061171.8(s)
Log thread 1508061171.2907 at 1508061172.2912(s)
Log thread 1508061171.2912 at 1508061172.2915(s)
서버의 동시 접속 처리 용량 상한이 10에 도달하므로 가장 최근에 생성된(시뮬레이션된) ) 스레드 등록은 어느 위치에나 나타날 수 있습니다.

3. usleep(500) Delay,simulated.thread 레코드를 다음과 같이 실행합니다.

Log thread 1508059270.3195 at 1508059270.3206(s)
Log thread 1508059270.3208 at 1508059270.3219(s)
Log thread 1508059270.322 at 1508059270.323(s)
Log thread 1508059270.323 at 1508059270.324(s)
Log thread 1508059270.3244 at 1508059270.3261(s)
Log thread 1508059270.3256 at 1508059270.3271(s)
Log thread 1508059270.3275 at 1508059270.3286(s)
Log thread 1508059270.3288 at 1508059270.3299(s)
Log thread 1508059270.3299 at 1508059270.331(s)
Log thread 1508059270.3313 at 1508059270.3314(s)
로그 레코드의 순서가 (시뮬레이트된) 스레드 생성 순서와 일치함을 알 수 있습니다. usleep 지연의 기본 단위는 마이크로초(us, 1초 = 1000000us)입니다.

위 기록에서 볼 수 있습니다. 1) 이 (시뮬레이션) 스레드는 스크립트를 실행하라는 첫 번째 요청 후에 자동으로 생성됩니다. 하나의 (시뮬레이션) 스레드가 즉시 다른 (시뮬레이션) 스레드를 생성합니다.

2) 이러한 (시뮬레이션된) 스레드 중 일부는 동일한 하위 프로세스 공간에서 생성되고 실행됩니다.

3) 인접한 (시뮬레이션된) 스레드 간의 생성 시간 간격은 매우 작거나 거의 동시에 또는 다음( 시뮬레이션) 스레드는 이전(시뮬레이션) 스레드가 실행을 마치고 종료되기 전에 생성됩니다.

4) 여러(시뮬레이션) 스레드를 동시에 실행할 수 있습니다.

그래서 위의 다중 스레드 동시성 시뮬레이션 구현은 성공적입니다. PHP-FPM 프로세스 풀의 동일한 하위 프로세스는 여러 연결 요청을 연속적으로 처리할 수 있지만 동시에 하나의 연결 요청만 처리할 수 있습니다. 처리되지 않은 연결 요청은 대기열에 들어가 처리를 기다립니다. 즉, 동일한 하위 프로세스에는 연결 요청을 동시에 처리할 수 있는 기능이 없습니다.

PHP-FPM 풀 구성: 여러 풀을 정의할 수 있으며 각 풀은 서로 다른 구성 항목을 정의할 수 있습니다. 다음은 탐색 과정에서 주의했던 기타 구성 항목 목록입니다

1. Listen: FastCGI 요청을 수락하는 주소는 TCP 소켓과 Unix 소켓의 두 가지 통신 프로토콜을 지원합니다. 청취 = [::]:9000을 설정할 수 있습니다.

2. Listen.allowed_clients: 연결이 허용된 FastCGI 클라이언트의 주소(IPv4/IPv6) 목록입니다. 이 구성 항목은 쉼표로 구분된 목록입니다(예: listening.allowed_clients = 127.0.0.1,172.17.0.5).

3. pm: 프로세스 관리자가 하위 프로세스 수를 제어하는 ​​방법을 선택합니다. 이 구성 항목은 FPM이 정적, 동적 및 온디맨드를 포함하여 프로세스 풀을 관리하는 방식을 설정합니다.

4. pm.max_requests: 각 하위 프로세스가 다시 생성되기 전에 실행해야 하는 요청 수입니다. 이는 타사 라이브러리에서 메모리 누수를 해결하는 데 유용할 수 있습니다. 타사 라이브러리에서 처리 메모리 누수에 유용합니다.

5.pm.status_path: FPM 상태 페이지를 보기 위한 URI입니다.

관련 학습 권장 사항: 프로그래밍 비디오

위 내용은 PHP-FPM 기반 프로세스 풀 탐색의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제