到目前为止,我已经使用PHP,Python和Java开发了一些基于Web的应用程序。但是一些基本但非常重要的问题仍然是我所不知道的,所以我发这篇文章是为了得到你们的帮助和澄清。
假设我使用一些编程语言作为我的后端语言(PHP / Python / .Net / Java等),并使用Web服务器(apache / lighttpd / nginx / IIS等)部署我的应用程序。并且假设在时间T,我的一个页面得到来自不同用户的100个同时请求。所以我的问题是:
编辑: 最近我读了一些关于CGI和fastcgi的文章,这让我知道fastcgi的方法应该是hanlde请求的典型方法。
协议在多个独立的FastCGI请求之间复用单个传输连接。这支持能够使用事件驱动或多线程编程技术处理并发请求的应用程序。
引自fastcgi spec,其中提到了可以处理多个请求的 connection ,并且可以在多线程技术中实现。我想知道这个连接可以被视为进程,它可以为每个请求生成几个线程。如果这是真的,我对如何处理每个线程中的共享资源感到困惑更多?
P.S感谢托马斯关于将帖子分成几个帖子的建议,但我认为问题是相关的,最好将它们组合在一起。感谢S.Lott的回答,但每个问题的答案都过于简短或根本没有涉及。
感谢大家的回答,这让我更接近事实。
答案 0 :(得分:53)
答案 1 :(得分:21)
我的网络服务器如何处理这100个同步请求? Web服务器是否为每个请求生成一个进程/线程? (如果是,流程或线程?)
它有所不同。 Apache具有处理请求的线程和进程。 Apache启动了几个并发进程,每个进程可以运行任意数量的并发线程。您必须配置Apache以控制它实际为每个请求播放的方式。
后端语言的解释器如何做?它将如何处理请求并生成正确的html?解释器是否会为每个请求生成一个进程/线程?(如果是,进程或线程?)
这取决于您的Apache配置和语言。对于Python,一种典型的方法是让守护进程在后台运行。每个Apache进程都拥有一个守护进程。这是通过mod_wsgi模块完成的。它可以配置为以多种不同的方式工作。
如果解释器将为每个请求生成一个进程/线程,那么这些进程(线程)如何?他们会分享一些代码空间吗?他们会互相沟通吗?如何处理后端代码中的全局变量?或者它们是独立的进程(线程)?进程/线程的持续时间有多长?它们会在处理请求并返回响应时被销毁吗?
线程共享相同的代码。根据定义。
进程将共享相同的代码,因为这就是Apache的工作方式。
他们没有 - 故意 - 相互沟通。您的代码无法轻松确定其他内容。这是设计的。您无法分辨正在运行的进程,也无法分辨此进程空间中正在运行的其他线程。
流程长期运行。它们不会(也不应该)动态创建。您可以将Apache配置为在开始时分叉自身的多个并发副本,以避免创建进程的开销。
线程创建的开销要小得多。 Apaches如何在内部处理线程并不重要。但是,您可以将Apache视为每个请求启动一个线程。
假设Web服务器只能支持100个并发请求,但现在它同时获得了1000个请求。它如何处理这种情况?它会像队列一样处理它们并在服务器可用时处理请求吗?或其他方法?
这是“可扩展性”问题。简而言之 - 随着负载的增加,性能将如何降低。一般的答案是服务器变慢。对于某些负载级别(假设100个并发请求),有足够的进程可用,它们都可以快速运行。在某个负载级别(比如101个并发请求),它开始变慢。在其他一些负载级别(谁知道有多少请求)它变得如此之慢,你对速度感到不满意。
有一个内部队列(通常是TCP / IP工作方式的一部分),但是没有调控器将工作负载限制为100个并发请求。如果您获得更多请求,则会创建更多线程(而不是更多进程),并且运行速度会更慢。
答案 2 :(得分:4)
首先,要求对所有要点的详细解答有点多,恕我直言。
无论如何,关于你的问题的一些简短答案:
#1
这取决于服务器的体系结构。 Apache是一个多进程,也可以是多线程服务器。有一个主进程侦听网络端口,并管理一个工作进程池(在“worker”mpm的情况下,每个工作进程有多个线程)。当请求进入时,它将被转发给其中一个空闲工作者。主服务器通过根据负载和配置设置启动和终止工作程序来管理工作池的大小。
现在,lighthttpd和nginx是不同的;它们是所谓的基于事件的体系结构,其中多个网络连接通过使用OS支持进行事件多路复用(例如POSIX中的经典select()/ poll(),或者更具可伸缩性,但多路复用到一个或多个工作进程/线程上)不幸的是,特定于操作系统的机制,例如Linux中的epoll。这样做的好处是,每个额外的网络连接只需要几百字节的内存,允许这些服务器保持打开成千上万的连接,这通常对于每个进程/线程架构的请求(例如apache)来说是过高的。但是,这些基于事件的服务器仍然可以使用多个进程或线程来利用多个CPU内核,并且还可以并行执行阻塞系统调用,例如正常的POSIX文件I / O.
有关详细信息,请参阅稍微过时的C10k page by Dan Kegel。
#2
再次,这取决于。对于经典CGI,每个请求都会启动一个新流程。对于带有apache的mod_php或mod_python,解释器嵌入到apache进程中,因此无需启动新进程或线程。但是,这也意味着每个apache进程需要相当多的内存,并且结合我上面针对#1解释的问题,限制了可伸缩性。
为了避免这种情况,可以在运行解释器时使用单独的重量级进程池,并且在需要生成动态内容时,前端Web服务器代理后端。这基本上是FastCGI和mod_wsgi采用的方法(虽然它们使用自定义协议而不是HTTP,所以从技术上来说它可能不代理)。这通常也是在使用基于事件的服务器时选择的方法,因为用于生成动态内容的代码很少是可重入的,为了在基于事件的环境中正常工作,它需要是可重入的。如果动态内容代码不是线程安全的,那么多线程方法也是如此;例如,可以使用线程工作者mpm前端apache服务器代理使用单线程prefork mpm运行PHP代码的后端apache服务器。
#3
根据您要求的级别,他们将通过操作系统缓存机制共享一些内存,是的。但一般来说,从程序员的角度来看,它们是独立的。请注意,这种独立性本身并不是一件坏事,因为它可以直接向多台机器进行水平扩展。但是,唉,通常需要进行一些沟通。一种简单的方法是通过数据库进行通信,假设由于其他原因需要一个,就像通常那样。另一种方法是使用一些专用的分布式内存缓存系统,例如memcached。
#4
取决于。它们可能排队,或者服务器可能会回复一些合适的错误代码,例如HTTP 503,或者服务器可能只是首先拒绝连接。通常,上述所有情况都可能发生,具体取决于服务器的加载方式。
#5
这种方法的可行性取决于服务器架构(参见我对#1的回答)。对于基于事件的服务器,保持连接打开不是什么大问题,但对于apache,肯定是由于每个连接都需要大量内存。是的,这肯定需要一个长期运行的解释器进程,但如上所述,除了经典的CGI之外,这几乎是被授予的。
答案 3 :(得分:0)
Web服务器是多线程环境;除了使用应用程序作用域变量之外,用户请求不会与其他线程交互。
所以: