为啥 Apache Event MPM 表现不佳?
Posted
技术标签:
【中文标题】为啥 Apache Event MPM 表现不佳?【英文标题】:Why is the Apache Event MPM Performing Poorly?为什么 Apache Event MPM 表现不佳? 【发布时间】:2015-03-07 12:26:26 【问题描述】:Event MPM 与 nginx 的设计并不完全相同,但显然是为了让 keepalives 更稳定并更快地发送静态文件而设计的。我的理解是 Event MPM 有点用词不当,因为:
-
虽然连接传递给kqueue/epoll,
某些非常重要的模块,例如 mod_gzip 和 mod_ssl 会阻塞/消耗一个线程,直到响应完成,
这对于大文件来说是个问题,但对于 php 生成的 html 文档等可能不是问题。
不幸的是,Apache 不断失去市场份额,大多数基准测试都对 MPM 事件不利。基准测试是否存在缺陷,或者事件 MPM 对 Nginx 的表现真的很差?即使有这些限制,在正常流量(非恶意)和较小文件下,它应该与 Nginx 有一定的竞争力。例如,通过 php-fpm 在慢速连接上提供 PHP 生成的文档应该具有竞争力,因为文档将被缓冲(即使是 ssl'd 和 gzip'd)并异步发送。使用压缩或不使用压缩的 SSL 和非 SSL 连接的工作方式与 Nginx 在此类工作负载上的工作方式没有明显不同。
那么为什么它没有在各种基准测试中大放异彩呢?它出什么问题了?或者基准有什么问题?大型网站是否将其用作对权威的诉求?
【问题讨论】:
如果您引用了您所引用的基准,这将是一个更好的问题。如果您只是想要快速安装,那么 pre-fork Apache + mod_php 在中低负载下将始终优于 Nginx - 在重负载下会有很大差异。但是,如果您想要容量和性能,那么您应该考虑不同的架构 - 在您的网络服务器前使用 ATS/nginx/varnish。 @symcbean 可能是真的。我还没有找到一个看起来不错的(Apache 发布的除外)。我也认为你过于笼统了。 ATS 或 Varnish 对无法缓存的动态内容几乎没有作用(或有害)。 相反。在 pre-fork 网络服务器前运行基于事件的服务器将提供针对 sloloris 攻击的保护,并卸载静态内容服务,节省内存并增加容量。动态内容的额外延迟应该是几毫秒的数量级——几乎不会惊天动地。事实上,如果您可以将反向代理移动到更靠近客户端的位置,您应该会看到性能的显着提升。 @symcbean 我只是指动态内容。请参阅“...关于无法缓存的动态内容”。它可能会对 mod_reqtimeout 或 mod_security 上的慢读和慢读做一些事情,但会以管道上的另一个副本为代价。我想你可以说 Nginx + Apache+mod_php 在技术上与 Nginx + php-fpm 没有太大区别。但是为什么会有人使用 php-fpm 呢? php-fpm 和 FastCGI 到 localhost 是否比 HTTP over localhost 快得多?无论如何,正如另一个答案所说,Event MPM 大致相当于您描述 Nginx 的方式——前面的基于事件的服务器。 【参考方案1】:它比 nginx 慢,因为带有事件 MPM 的 Apache(非常)大致相当于带有工作 MPM 的 Apache 前面的事件驱动 HTTP 代理(nginx、varnish、haproxy)。事件是工作者,但不是在其生命周期内将每个新连接交给一个线程,事件 MPM 的线程将连接交给一个辅助线程,该线程将其推入队列或在 keep-alive 为时关闭它关闭或已过期。
事件相对于工作者的真正好处是资源使用。如果您需要维持 1,000 个并发连接,则工作 MPM 需要 1,000 个线程,而事件 MPM 可能会在事件队列中管理 100 个活动线程和 900 个空闲连接。在该假设中,事件 MPM 将使用工作者 MPM 的一小部分资源,但缺点仍然存在:这些请求中的每一个都由必须由内核调度的单独线程处理,因此将产生成本切换上下文。
另一方面,我们有 nginx,它使用事件模型本身作为其调度程序。 Nginx 只是在处理下一个连接之前尽可能多地处理每个连接上的工作。无需额外的上下文切换。
事件 MPM 真正大放异彩的一个用例是处理在 Apache 中运行的繁重应用程序的设置,为了节省保持活动期间空闲线程的资源,您将部署代理(例如作为nginx)在apache前面。如果您的前端没有其他用途(例如静态内容、代理到其他服务器等),事件 MPM 会漂亮地处理该用例并消除对代理的需求。
【讨论】:
如果你使用 Apache 事件 MPM + PHP-fpm,这正是我希望它能做得很好的原因。它不应该比 Nginx + PHP-fpm 做得更多或更糟。但是每个基准测试都说没有。是时候做我自己的基准测试了。顺便说一句,他们真的可以将这种“保持活动优化”应用于每个 MPM——包括 prefork。没有什么能阻止他们使用主进程来跟踪空闲的保持活动连接,并且只在活动时将它们交给池中的进程。他们只是对工人这样做。 我做的比较是 Nginx + Apache-worker + PHP-fpm ~~ Apache-event + PHP-fpm。 Nginx + PHP-fpm 的性能将总是明显优于 Apache-event + PHP-fpm,因为 Apache 下的每个 FastCGI 连接都必须由单独的线程处理。如果 php 是线程安全的,你可以通过使用 Apache-event+mod_php 获得更接近 Nginx 的性能,但唉,它不是...... 也许我理解错了,但线程的生命周期将非常短暂,因为大多数与 php-fpm 的连接都是短暂的。响应将很小(HTML 文档通常为 10-100k)、被缓冲并以基于事件的方式发送。我猜 Nginx 可以完全做到这一点,每个连接都不需要一个线程,状态机与 php-fpm 对话。它可能还会缓冲它,因为否则它将重新创建 prefork 连接速度慢的问题,并将其推送回 php-fpm 进程而不是 httpd 进程。我认为差异不会那么大。 据我了解,如果响应被缓冲并通过事件队列传递,像 mod_gzip 这样的模块将不会在响应期间占用线程。运行事件队列的线程存在以保持 HTTP 请求之间的连接。所以在你的场景中,当下一个请求进来时,事件循环交给一个线程来处理它,该线程向 php-fcgi 发送一个请求,php-fcgi 处理它并返回,apache 线程发送响应并将连接交给事件循环。 Nginx 可以跳过切换并在其事件循环中与 fcgi 对话。 在 Nginx 中仍有一些 CPU 绑定的事情要做,比如 SSL 和压缩。这就是为什么它通常配置为有 NUM_CPUs+1 个左右的进程,而不是一个轻量级的 Lighttpd?我猜 Event 可能是一个改进,但如果有人向 Nginx 添加 .htaccess 支持并让它与 CPanel 配合得很好,那么 Apache 看起来真的会枯萎。【参考方案2】:对我来说,主要的操作差异在于事件:
处理程序(负责生成响应的插件)是同步的 - 如果它们执行计算或 I/O,它们将占用一个线程 核心必须使用跨线程锁来保护关键数据结构,因为它是多线程的,可以支持如此多的同步请求这就是为什么像 nginx(或 Apache Traffic Server 或任何现代商业/高性能代理)这样的高容量服务器通常会领先。
IMO 您问题中的项目符号有点离题,SSL 和 deflate 并没有真正造成这里的差异,因为它们都是过滤器,不会真正导致可伸缩性问题,甚至不会将 httpd 与其传统 API 联系起来保证请求或连接的生命周期。像这样的过滤器(相对于处理程序,或负责低级 I/O 的核心过滤器)可能是与处理模型关联最少的东西。
但我也不认为它表现得如此糟糕,除了最极端的工作负载或极其受限的系统之外。由于某种原因,我看到的大多数基准测试质量都非常差。
我认为大部分人希望他们今天所谓的网络服务器成为更复杂的应用程序服务器(Java EE、PHP 等)的代理,并且旨在最有效地移动 I/O 而没有 API 包袱的服务器将会有优势。
【讨论】:
我应该补充一点,作为 Apache httpd 贡献者,我有偏见。 谢谢!我承认通过对代码和文档的快速审核进行猜测。我对处理程序的看法是对的,但对细节的看法是错误的,我错过了锁定。我提出这些模块的原因是我可以看到它在大型静态文件上是一个大问题。谷歌希望我们在 2015 年转向一切——SSL。我什至可以看到 SSL 转向内核,因为我们不能再仅仅映射文件并发送。但至少在 Nginx 中它不会全时抢走我们的线程。它可以在几个线程上逐块使用 ssh/gzip+epoll,也许有一些亲和力。我错了吗? Gzip 提出了类似的问题。以上是关于为啥 Apache Event MPM 表现不佳?的主要内容,如果未能解决你的问题,请参考以下文章
Apache三种MPM分析: PreforkWorker和Event
Apache PreforkWorker和Event三種MPM分析
Apache PreforkWorker和Event三种MPM分析
Apache的三种MPM模式比较:prefork,worker,event