龙卷风vs wsgi(与gunicorn)

sch*_*acs 26 python wsgi tornado uwsgi gunicorn

我读到关于龙卷风的信息:

另一方面,如果您已经拥有一个WSGI应用程序并希望在快速的tornado.httpserver.HTTPServer上运行它,请使用tornado.wsgi.WSGIContainer进行包装.但你需要小心.由于您的原始应用程序没有为异步服务器做好准备,并且会进行大量的IO /计算,因此它会在生成响应时阻止其他请求(进一步的请求将被接受并缓冲,但排队等待以后处理).

而Guincorn说:

'用于UNIX的Python WSGI HTTP服务器.这是一个从Ruby的Unicorn项目移植的前叉工作者模型.

  1. 那么Gunicorn会产生工作进程来处理请求吗?
  2. 每个工人有一个可靠的请求?
  3. 虽然龙卷风将在一个过程中使用epollkqueue完成工作(没有主人/工人流程)?
  4. 因此,如果我使用阻塞调用(如requests.get在处理程序的get/post函数中),这将阻止所有请求处理或仅阻止当前正在处理的请求?

Gra*_*ton 42

如果您在Tornado之上运行WSGI应用程序,那么Tornado和gunicorn之间没有太大区别,只要在特定进程中由应用程序处理WSGI请求,就不会发生其他任何事情. .在gunicorn的情况下,因为它只有一个线程处理请求,而在Tornado的情况下,因为主事件循环将永远不会在那段时间内运行来处理任何并发请求.

在龙卷风的情况下,实际上也存在隐患.

对于gunicorn,因为只有一个请求线程,所以工作进程一次只接受一个Web请求.如果有并发请求命中服务器,则它们将由任何其他可用的工作进程处理,因为它们都共享同一个侦听器套接字.

但是,对于Tornado,WSGI应用程序下的层的异步性质意味着一个进程可以同时接受多个请求.它们最初会在请求标头和内容被读取时进行交错,在调用WSGI应用程序之前,Tornado会将其读入内存.当已经读取了整个请求内容时,控制权将被移交给WSGI应用程序以处理该一个请求.与此同时,只要WSGI应用程序处理第一个请求,将阻止由尚未读取请求标头和内容的同一进程处理的并发请求.

现在,如果您只有一个Tornado进程,这不是什么大问题,因为请求将被序列化,但是如果您使用gunicorn的tornado worker模式以便使多个Tornado工作进程共享相同的侦听器套接字,则可以很糟糕 这是因为异步层导致的各个进程的贪婪性质意味着当可能有另一个可以处理它的工作进程时,请求可能在进程中被阻塞.

总之,对于单个Tornado Web服务器进程,您只能一次处理一个请求.在gunicorn中,您可以使用多个工作进程来同时处理请求.但是,使用Tornado的多进程设置可能会阻止请求.

因此,Tornado对于非常小的自定义WSGI应用程序非常有用,因为它们做得不多,因此响应非常快,但是在阻塞的WSGI应用程序下运行长时间运行的请求时,它可能会受到影响.因此,Gunicorn会更好,因为它具有处理并发请求的适当能力.虽然gunicorn是单线程的,但需要多个工作进程,但它将使用更多的内存.

所以他们都有权衡,在某些情况下,你可以更好地使用WSGI服务器,它通过多线程和多个工作进程提供并发.这允许您处理并发请求,但不会因需要许多工作进程而耗尽内存使用量.同时,您需要使用多个进程来平衡每个进程的线程数,以免在CPU繁重的应用程序中过度受到GIL的影响.

具有多线程能力的WSGI服务器的选择是mod_wsgi,uWSGI和waitress.对于女服务员,虽然您仅限于一个工作进程.

总而言之,哪个是最好的WSGI服务器实际上很大程度上取决于您的Web应用程序的细节.没有一个WSGI服务器在所有方面都是最好的.

  • 至于神话般的 C10K,将 nginx 贴在带有 WSGI 应用程序的 gunicorn 前面不会有太大帮助。gunicorn 可以处理的并发请求数量仍然受到内存中可以容纳多少进程的限制,与以下事实相平衡:在某些情况下,由于 Python 的 GIL 的工作方式,拥有比处理器内核多的工作进程可能对性能有害多处理器系统。 (3认同)
  • 对于大多数网站而言,C10k实际上并不是一个实际的基准或尝试实现的目标,因为你永远不会真实地拥有它,或者如果你这样做,通过典型的Python Web应用程序尝试在一台机器上实现它通常是荒谬的.如果您对应用程序的一部分有特定要求以维护长时间运行的连接,则将其分段并为其编写特殊用途的异步应用程序.不要仅仅因为一个部分需要异步来感染整个应用程序.然后将nginx路由分别分配给WSGI和异步应用程序. (3认同)
  • 因为第一个工作进程已经接受了套接字连接并开始从中读取数据。此时另一个进程无法接管连接。与曾经为嵌入 nginx 编写的 WSGI 模块所描述的问题类似,如 http://blog.dscpl.com.au/2009/05/blocking-requests-and-nginx-version-of.html 中所述 (2认同)
  • 这个答案最好的地方是关于 C10K 问题的评论。至少现在我知道不应该使用龙卷风和枪炮来处理这么大的流量。 (2认同)
  • @Realistic - 仅当您在龙卷风中使用 WSGI 时才如此。正如 Graham Dumpleton 解释的那样:“只要 WSGI 请求由特定进程中的应用程序处理,就不会发生任何其他事情”。对于 WSGI 接口来说也是如此。但是,如果您使用本机 Tornado 请求处理程序(例如,没有 Gunicorn),那么您就不仅限于单个请求。然后,您实际上可以使用 await 语句或通过从请求处理程序产生 Future 实例在请求之间切换。您还可以使用 Nginx 在多个 Tornado 进程之间分发请求(而不是 Gunicorn 的 master) (2认同)