为什么我会选择基于线程/进程的方法与异步Web服务器

hel*_*922 11 webserver multithreading asynchronous multiprocessing

随着我对Web服务器软件的更多研究,我开始质疑Apache的基于线程/进程的方法是否可以采用Nginx和Lighttpd等服务器提供的异步请求处理方式.更重的负载更好.

据我所知,后两者和Apache之间存在许多其他差异.我的问题是在什么情况下我会选择基于线程/进程的方法来进行异步处理.

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

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

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

and*_*rew 5

这是旧的,但值得回答。让我们首先介绍一下每个模型的工作原理。

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

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

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

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

异步对于网络 I/O 很有好处:在多个源/目的地之间传递数据(还有用户界面,但这超出了本文的范围)。

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

参见上文,但只要您执行的 CPU 工作多于网络 I/O,您就应该切换到线程模型。但是,有一些架构解决方法......例如,您可以有一个异步应用程序,只要它需要执行实际工作,它就会将作业发送到工作队列。但是,如果每个请求都需要 CPU 处理,那么该架构就太过分了,您还不如使用线程服务器。

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

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

也就是说,如果您正在编写应用程序并尝试决定是使用线程模型还是异步模型,则必须考虑开发人员的时间。除非你使用的语言在事件循环上有绿色线程(比如方案),否则你会因为流氓异常导致整个应用程序崩溃并且通常会陷入CPS 的困境而感到烦恼。 /对所有内容使用回调。期货/承诺是你的朋友,但只是让异步变得更好的创可贴。

长话短说

当在服务器中使用异步时,如果您只进行网络 IO 而没有执行其他操作,则可以比线程压缩更多的并发操作

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

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

如果您可以在线程和异步之间选择作为堆栈中的组件(apache 与 nginx),并且它们提供完全相同的功能,则稍微偏向异步。不要仅仅因为您认为它会使一切速度加快 20 倍而选择它。


dan*_*mak 0

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

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