如何在python worker中处理长时间运行的请求?

时间:2009-11-04 15:51:17

标签: python nginx load-balancing wsgi reverse-proxy

我有一个python(嗯,现在是php,但我们正在重写)函数,它接受一些参数(A和B)并计算一些结果(在图中找到从A到B的最佳路径,图形是只读的),在典型情况下,一次调用需要0.1秒到0.9秒才能完成。用户可以将此函数作为简单的REST Web服务访问(GET bestpath.php?from = A& to = B)。目前的实现非常愚蠢 - 它是一个简单的PHP脚本+ apache + mod_php + APC,每个请求都需要加载所有数据(在php数组中超过12MB),创建所有结构,计算路径并退出。我想改变它。

我想要一个具有N个独立工作者的设置(每个服务器X个Y服务器),每个工作者是一个循环运行的python应用程序(获取请求 - >处理 - >发送回复 - >获取req ... ),每个工人可以一次处理一个请求。我需要一些可以作为前端的东西:从用户那里获取请求,管理请求队列(具有可配置的超时),并一次向我的工作人员提供一个请求。

如何处理这个问题?你能提出一些设置吗? nginx + fcgi或wsgi还是其他什么? HAProxy的?你可以看到我是python,反向代理等新手。我只需要一个关于架构(和数据流)的起点

顺便说一句。工作人员正在使用只读数据,因此无需维护它们之间的锁定和通信

7 个答案:

答案 0 :(得分:2)

看起来你需要“工作者”成为独立的进程(至少其中一些进程,因此也可能使它们成为所有单独的进程,而不是将一组线程分成几个进程)。 Python 2.6及更高版本的标准库中的multiprocessing模块提供了良好的工具来生成进程池并通过FIFO“队列”与它们进行通信;如果由于某种原因你仍然坚持使用Python 2.5甚至更早,那么PyPi存储库上就有多种处理版本,您可以下载这些版本并与旧版本的Python一起使用。

“前端”可以而且应该很容易与WSGI(使用Apache或Nginx)一起运行,它可以通过multiprocessing处理与工作进程之间的所有通信,而无需使用用于该系统部分的HTTP,代理等;只有前端本身就是一个网络应用程序,工作人员只是按照前端的要求接收,处理和响应工作单元。这对我来说似乎是最健全,最简单的架构。

在Python的第三方软件包中还有其他分布式处理方法,但多处理非常不错,并且具有成为标准库一部分的优势,因此,如果没有其他特殊的限制或约束,多处理就是我建议的你去。

答案 1 :(得分:1)

在Python中使用线程处理这种排列的典型方法是使用标准库模块Queue。可以在此处找到使用队列模块管理员工的示例:Queue Example

答案 2 :(得分:1)

有许多FastCGI模块具有preforked模式和用于python的WSGI接口,最着名的是flup。我个人对此类任务的偏好是superfcgi和nginx。两者都将启动多个流程并将向他们发送请求。 12Mb并不是在每个进程中单独加载它们,但如果你想在工作者之间共享数据,则需要线程,而不是进程。注意,由于GIL,使用单个进程和许多线程的python中的繁重数学将不会有效地使用多个CPU /核心。可能最好的方法是使用多个进程(尽可能多的核心),每个进程运行多个线程(superfcgi中的默认模式)。

答案 3 :(得分:1)

在这种情况下,最简单的解决方案是使用网络服务器来完成所有繁重的工作。当网络服务器为您完成所有这些操作时,为什么要处理线程和/或进程?

Python部署中的标准安排是:

  1. 网络服务器启动许多进程,每个进程运行一个完整的python解释器并将所有数据加载到内存中。
  2. HTTP请求进入并被分派到某个进程
  3. 进程执行计算并将结果直接返回给Web服务器和用户
  4. 当您需要更改代码或图表数据时,请重新启动网络服务器并返回步骤1.
  5. 这是使用Django和其他流行的Web框架的架构。

答案 4 :(得分:0)

我认为你可以配置modwsgi / Apache,因此它将有几个“热门”Python解释器 在单独的进程中随时可以运行,并将它们重新用于新访问 (如果他们都很忙,就会产生一个新的)。 在这种情况下,您可以将所有预处理数据作为模块全局加载,他们会 每个进程只加载一次,并为每次新访问重用。实际上我不确定这不是默认配置 对于modwsgi / Apache。

这里的主要问题是你最终会消费 很多“核心”记忆(但也可能不是问题)。 我认为你也可以为单个进程/多个配置modwsgi 线程 - 但在这种情况下,您可能只使用一个CPU,因为 我认为Python全局解释器锁(臭名昭着的GIL)。

不要害怕在modwsgi邮件列表上询问 - 他们非常 敏感而友好。

答案 5 :(得分:0)

您可以使用nginx负载均衡器代理PythonPaste paster(提供WSGI,例如Pylons),无论如何都会将每个请求作为单独的线程启动。

答案 6 :(得分:0)

另一个选项是数据库中的队列表 工作进程在循环或关闭cron中运行,并轮询队列表以查找新作业。