在掌握了上述知识的基础上,我们将以 Apache 作为实验对象,探究它的三种运行方式在高并发场景下的差异,从而推导出 Web Server 领域高并发优化的内功心法。
Apache 支持三种进程模型:prefork
、worker
和 event
。在此,我们简要分析这三种模式的优缺点。
select
模型遍历 TCP连接数 x 进程数
次才能找到匹配的进程。在单机数千个 TCP 连接数的场景中,仅寻找进程操作就消耗了一颗 CPU 核心 100% 的时间片,导致单机性能达到极限,无法充分利用更多的 CPU 资源。select
模型来遍历 TCP 请求和线程。其性能上限与 prefork 相同,但内存消耗有所降低,初始 TCP 承载能力略好。然而,在请求数突然增加的场景下,worker 模式开启新线程的速度反而比 prefork 更慢,且基础延迟也比 prefork 模式高,在大部分场景下不如 prefork。epoll
模型承载,理论上性能与 Nginx 相当。但由于 Apache 通常与 mod_php(插件)模式的 PHP 一起部署,再加上 PHP 阻塞运行的特性,其性能与前两种模式并无显著差异。因此,即使在 event 模式下运行的 Apache,其性能仍然远低于 Nginx 和 php-fpm 的组合。接下来,我们将使用 jmeter 对 prefork、worker、event 三种模式进行性能测试,并额外验证几个关于 Nginx 和 php-fpm 的悬而未决的问题。
php artisan optimize
后测试测试代码如代码清单 4-1 所示。
Route::get('/', function () {
usleep(500000);
return view('welcome');
});
Apache prefork 模式的配置文件如代码清单 4-2 所示。
<IfModule mpm_prefork_module>
StartServers 100
MinSpareServers 5
MaxSpareServers 100
MaxRequestWorkers 500
MaxRequestsPerChild 100000
</IfModule>
php-fpm 的配置文件如代码清单 4-3 所示。
pm = static
pm.max_children = 500
我们将测试三种配置下的性能表现差异:
单独对比 Nginx 和 Apache 性能的文章很多,数据结果也大同小异,无非是 Nginx 的 QPS 更高,但是 “为什么 QPS 更高?” 却没人回答,本次的实验设计就是要回答这个问题。
prefork + mod_php 模式下的测试结果如图 4-4 和 图 4-5 所示。
Nginx + php-fpm 模式下的测试结果如图 4-6 和 图 4-7 所示。
Nginx 反向代理 Apache 模式下的测试结果如图 4-8 和 图 4-9 所示。
我们可以很明显地看出,Apache + prefork 的问题在于它对数千个 TCP 连接的处理能力不足。
Nginx 每个 worker 进程可以高效地处理上千个 TCP 连接,同时消耗较少的内存和 CPU 资源。这使得单台服务器能够承载比 Apache 多两个数量级的用户量,相较于 Apache 单机 5K 的 TCP 连接数上限(对应于 2000 个在线用户),这是一个巨大的进步。
Nginx 对 TCP 的复用使其非常擅长应对海量客户端的直接连接。根据实际测试,在 HTTP 高并发环境下,Nginx 的活跃 TCP 连接数仅为 Apache 的五分之一,并且随着用户量的增加,复用效果更加显著。
在架构上,基于 FastCGI 网络协议进行架构扩展,可以更轻松地利用多台物理服务器的并行计算能力,从而提升整个系统的性能上限。
📙 高并发的哲学原理 《Philosophical Principles of High Concurrency》
Copyright © 2023 吕文翰