加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

基于PHP-FPM进程池的研究

发布时间:2022-07-21 14:05:04 所属栏目:PHP教程 来源:互联网
导读: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 ro
  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)
 
  相关学习推荐:PHP编程从入门到精通
 
  1. 什么是线程:线程有时又称轻量级进程(Lightweight Process,LWP),通常由线程ID、当前指令指针(PC)、寄存器集合和堆栈组成,是进程中的一个实体,是被系统独立调度的基本单位;线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,与同属一个进程的其它线程共享进程所拥有的全部资源。 由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。由于进程是资源拥有者,创建、撤消与切换开销过大,在对称多处理机(SMP)上同时运行多个线程(Threads)才是更合适的选择。线程的实体包括程序、数据和线程控制块(Thread Control Block,TCB),TCB包括以下信息:
 
  (1)线程状态;
 
  (2)当线程不运行时,被保存的现场资源;
 
  (3)一组执行堆栈;
 
  (4)存放每个线程的局部变量主存;
 
  (5)访问同一个进程中的主存和其它资源。
 
  但使用多个进程会使得应用程序在出现进程池内的进程崩溃或被攻击的情况下变得更加健壮。
 
  2. 模拟多线程:
 
  /**
 
   * PHP 只支持多进程不支持多线程。
 
   *
 
   * PHP-FPM 在进程池中运行多个子进程并发处理所有连接,
 
   * 同一个子进程可先后处理多个连接请求,但同一时间
 
   * 只能处理一个连接请求,未处理连接请求将进入队列等待处理
 
   //主机名
 
   private $host = 'tcp://172.17.0.5';
 
 
    //采用当前时间给线程编号
 
    $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,
 
    if ($run++ < 9) {//最多模拟10个线程
 
     $fp = fsockopen($this->host, $this->port);
 
     fputs($fp, "GET {$_SERVER['PHP_SELF']}?run={$run}rnrn");
 
     sleep(1);//usleep(500)
 
     fclose($fp);
 
    }
 
   
 
    $this->log();
 
   }
 
   
 
   /**
 
    * 日志记录当前模拟线程运行时间
 
    *
 
    * @return void
 
    */
 
  $thread = new SimulatedThread();
 
  $thread->simulate();
 
  echo "Started to simulate threads...";
 
  探秘汇总:本人通过运行上述脚本后,发现一些可预料但却不是我曾想到的结果
 
  1. PHP-FPM配置项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,因此它只可能出现在第六条以后的位置。
 
 
  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)延迟,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 s = 1000000 us)。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读