11

随着我对 Web 服务器软件进行了更多研究,我开始质疑 Apache 的基于线程/进程的方法与 Nginx 和 Lighttpd 等服务器提供的异步请求处理是否适合,后者往往会扩展更重的负载更好。

我知道后两者和 Apache 之间还有许多其他区别。我的问题是在什么情况下我会选择基于线程/进程的方法而不是异步处理。

  1. 是否有任何我不能与异步方法一起使用的功能/技术(或功能不佳/效果不佳)?

  2. 哪些情况会导致异步方法的性能比基于线程/进程的方法更差?这些是常见的还是罕见的情况,差异有多大?

  3. 在比较两者时,我还应该考虑其他因素吗?请记住,我主要关注基于线程/进程的方法与异步,而不是碰巧使用其中一种方法的任何特定服务器软件。这些问题可能是管理/调试困难、安全问题等。

4

2 回答 2

4

这是旧的,但值得回答。让我们首先说每个模型是如何工作的。

在线程中,您有一个请求进入处理程序,处理程序产生一个新的操作系统线程来处理该请求,并且该请求的所有工作都发生在该线程中,直到发送响应并结束线程。此模型支持与服务器可以生成的线程一样多的并发请求(但线程可能有些重量级)。

当执行异步请求时,请求进入处理程序,但不是创建线程来处理它,而是将连接添加到所谓的事件循环中。事件循环监听连接上的数据/状态变化,并在每次“某事”发生时触发回调。将连接添加到事件循环后,处理程序立即侦听要添加的新连接。这允许您同时拥有许多(有时是 100K)并发连接

是否有任何我不能与异步方法一起使用的功能/技术(或功能不佳/效果不佳)?

是的,当您进行数字运算时。异步(或“事件”)系统的架构使得它擅长传递数据但不处理数据。它可以处理数以千计的并发操作,但是因为它只在一个 OS 线程上运行,所以它触发的回调需要做的尽可能少,以获得最大的吞吐量。这是因为如果您的某个回调执行一些需要 5 秒的数字运算,那么您的整个服务器将冻结 5 秒,直到该操作完成。这个想法是获取数据,将其发送到它要去的地方(数据库、API 等)并以最少的处理发送响应。

异步有利于网络 I/O:在多个源/目标之间传递数据(以及用户界面,但这超出了本文的范围)。

哪些情况会导致异步方法的性能比基于线程/进程的方法更差?这些是常见的还是罕见的情况,差异有多大?

见上文,但任何时候你做的 CPU 工作比网络 I/O 多,你应该切换到线程模型。但是,有一些架构变通方法......例如,您可以拥有一个异步应用程序,并且只要它需要进行实际工作,它就会将工作发送到工作队列。但是,如果每个请求都需要 CPU 处理,那么这种架构就太过分了,您不妨只使用线程服务器。

在比较两者时,我还应该考虑其他因素吗?请记住,我主要关注基于线程/进程的方法与异步,而不是碰巧使用这些方法之一的任何特定服务器软件。这些问题可能是管理/调试困难、安全问题等。

异步编程通常比线程更复杂。也就是说,如果您不是自己进行编程(即您在 nginx 和 apache 之间进行选择),那么我通常建议您使用异步(nginx),因为您通常可以通过这种方式从服务器中榨取更多汁液. 我总是赞成在堆栈中使用尽可能多的异步。

也就是说,如果您正在编写应用程序并尝试决定是使用线程模型还是异步模型,则必须考虑开发人员的时间。除非您使用的语言在事件循环(如方案)上具有绿色线程,否则预计会因流氓异常导致整个应用程序崩溃并且通常将您的头绕在CPS周围/使用回调处理所有事情。Futures/promises 是你的朋友,但只是使异步更好的创可贴。

TL;博士

异步,当在服务器中使用时,如果你正在做网络 IO 而不做其他事情,它可以比线程压缩(很多)更多的并发操作。

如果您正在处理任何类型的数字运算,请使用线程应用程序服务器使用带有后台排队系统的异步应用程序。

异步编程要困难得多,除非您的语言支持“假”线程(即绿色线程)。一旦你克服了最初的驼峰,你就没事了,一般来说。如果您没有绿色线程,请使用承诺。

如果您可以选择线程和异步作为堆栈中的组件(apache 与 nginx),并且它们提供完全相同的功能,则稍微支持异步。不要仅仅因为你认为它会让一切都快 20 倍而选择它。

于 2014-09-19T14:44:10.237 回答
0

与线程和与安全性和可靠性相关的异步模型相比,进程具有几个优点。大多数网站不需要这些特殊优势,但有时它们是不可或缺的。

  1. 安全性:您可以作为低权限用户在沙箱中运行您的工作进程,并且每个工作进程只处理一个请求。这可以缓解某些类型的安全漏洞:即使攻击者接管了您的整个工作进程,只要您根据请求元数据将其严格沙箱化(即它没有对您所有数据的写入权限),它就可以' t 损害系统稳定性或影响对请求的响应。
  2. 安全性#2:有时您需要对不受信任的代码进行沙箱处理,或者在不同代码或不同请求之间强制隔离,而做到这一点的唯一方法是使用单独的一次性流程。(想想运行用户提供的代码。)
  3. 可靠性:如果您定期(或针对每个请求)拆除和更换工作进程,内存泄漏和内存损坏的严重程度要低得多。
  4. 在单独的进程中处理用户请求时,很容易对 CPU 时间、磁盘和网络配额等实施硬限制。即使请求处理代码进入无限循环,主进程(或操作系统)也可以强制超时。
于 2013-09-05T23:25:37.713 回答