http://www.sohu.com/a/146723313_466839

PHP使用的模型相当简单。虽然有一些变化,但基本上PHP服务器看起来像:

HTTP请求来自用户的浏览器,并且访问了你的Apache网站服务器。Apache为每个请求创建一个单独的进程,通过一些优化来重用它们,以便最大程度地减少其需要执行的次数(创建进程相对来说较慢)。Apache调用PHP并告诉它在磁盘上运行相应的.php文件。PHP代码执行并做一些阻塞的I/O调用。若在PHP中调用了file_get_contents(),那在背后它会触发read()系统调用并等待结果返回。

当然,实际的代码只是简单地嵌在你的页面中,并且操作是阻塞的:

<?php

// 阻塞的文件I/O

$file_data = file_get_contents('/path/to/file.dat');

// 阻塞的网络I/O

$curl = curl_init('http://example.com/example-microservice');

$result = curl_exec($curl);

// 更多阻塞的网络I/O

$result = $db->query('SELECT id, data FROM examples ORDER BY id DESC limit 100');

?>

相当简单:一个请求,一个进程。I/O是阻塞的。优点是什么呢?简单,可行。那缺点是什么呢?同时与20,000个客户端连接,你的服务器就挂了。由于内核提供的用于处理大容量I/O(epoll等)的工具没有被使用,所以这种方法不能很好地扩展。更糟糕的是,为每个请求运行一个单独的过程往往会使用大量的系统资源,尤其是内存,这通常是在这样的场景中遇到的第一件事情。

Nginx 是非阻塞IO & IO复用模型,通过操作系统提供的类似 epoll 的功能,可以在一个线程里处理多个客户端的请求。 Nginx 的进程就是线程,即每个进程里只有一个线程,但这一个线程可以服务多个客户端。

PHP-FPM 是阻塞的单线程模型,pm.max_children 指定的是最大的进程数量,pm.max_requests 指定的是每个进程处理多少个请求后重启(因为 PHP 偶尔会有内存泄漏,所以需要重启). PHP-FPM 的每个进程也只有一个线程,但是一个进程同时只能服务一个客户端。