django - 在 nginx/gunicorn/django Web 架构中有效处理长时间运行的 HTTP 连接

标签 django performance web-services nginx gunicorn

我正在开发基于 nginx 实现的 Web 服务+ gunicorn + django .客户端是智能手机应用程序。应用程序需要对外部 API(Facebook、Amazon S3...)进行一些长时间运行的调用,因此服务器只需将作业排队到作业服务器(使用 Celery 而不是 Redis )。

只要有可能,一旦服务器将作业排队,它就会立即返回,并关闭 HTTP 连接。这工作正常,并允许服务器维持非常高的负载。

client                   server                 job server
  .                        |                        |
  .                        |                        |
  |------HTTP request----->|                        |
  |                        |--------queue job------>|
  |<--------close----------|                        |
  .                        |                        |
  .                        |                        |

但在某些情况下,客户需要在作业完成后立即获得结果。不幸的是,一旦 HTTP 连接关闭,服务器就无法联系客户端。一种解决方案是依靠客户端应用程序每隔几秒钟轮询一次服务器,直到作业完成。如果可能的话,我想避免这种解决方案,主要是因为它会阻碍服务的 react 性,并且还因为它会给服务器加载许多不必要的轮询请求。

简而言之,我想保持 HTTP 连接正常运行,什么都不做(除了可能每隔一段时间发送一个空格以保持 TCP 连接处于事件状态,只是 like Amazon S3 does ),直到工作完成,服务器返回结果。
client                   server                 job server
  .                        |                        |
  .                        |                        |
  |------HTTP request----->|                        |
  |                        |--------queue job------>|
  |<------keep-alive-------|                        |
  |         [...]          |                        |
  |<------keep-alive-------|                        |
  |                        |<--------result---------|
  |<----result + close-----|                        |
  .                        |                        |
  .                        |                        |

假设服务器处于非常高的负载下,我如何以有效的方式实现长时间运行的 HTTP 连接(目前还不是这样,但目标是能够维持尽可能高的负载,每秒有数百或数千个请求)?

将实际作业卸载到其他服务器应该确保服务器上的 CPU 使用率较低,但是如何避免进程堆积并使用服务器的所有 RAM,或者由于打开的连接过多而丢弃传入请求?

这可能主要是正确配置 nginx 和 gunicorn 的问题。我读过一些关于 async workers based on greenlets in gunicorn :文档说“应用程序进行长时间阻塞调用(即外部 Web 服务)”使用异步 worker ,这听起来很完美。它还说“一般来说,应用程序应该能够使用这些工作类而无需更改”。这听起来很棒。对此有何反馈?

感谢您的建议。

最佳答案

我是 answering my own question ,也许有人有更好的解决方案。

阅读 gunicorn's documentation更进一步,阅读更多关于 eventlet 的内容和 gevent ,我认为gunicorn完美地回答了我的问题。 Gunicorn 有一个管理 worker 池的主进程。每个工作人员可以是同步的(单线程,一次处理一个请求)或异步的(每个工作人员实际上几乎同时处理多个请求)。

同步 worker 很容易理解和调试,如果 worker 失败,只会丢失一个请求。但是如果一个工作人员被困在一个长时间运行的外部 API 调用中,它基本上是在 sleep 。因此,在高负载的情况下,所有工作人员可能最终会在等待结果时进入休眠状态,并且请求最终会被丢弃。

所以解决办法就是把默认的worker类型从同步改为异步(选择eventlet或者gevent,here's a comparison)。现在每个 worker 运行多个 green threads ,每一个都非常轻巧。每当一个线程必须等待某个 I/O 时,另一个绿色线程就会恢复执行。这称为 cooperative multitasking .它非常快,非常轻量级(如果他们正在等待 I/O,单个工作人员可以处理数千个并发请求)。正是我需要的。

我想知道如何更改现有代码,但显然标准 python 模块是 monkey-patched通过 gunicorn 在启动时(实际上是通过 eventlet 或 gevent),因此所有现有代码都可以在不更改的情况下运行,并且仍然可以与其他线程很好地运行。

gunicorn 中有很多参数可以调整,例如使用 gunicorn 的 worker_connections 的最大同时客户端数参数,使用 backlog 的最大挂起连接数参数等

太好了,我马上开始测试!

关于django - 在 nginx/gunicorn/django Web 架构中有效处理长时间运行的 HTTP 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11883214/

相关文章:

mysql - 我应该为我的大学使用社交网络应用程序的共享服务器吗?

ios - 使用 magento SOAP API 的 multicall 方法的正确方法是什么?

Django 还是佐佩?

performance - 如何加快 grails 测试执行速度

Django 在模板中使用链接参数的值

android - 我调用 finish() 和 startActivity() 的顺序有关系吗?

java - 使用 wsimport 解析 Salesforce 合作伙伴 WSDL 时出错

java - 如何使用 java 访问 Salesforce 附件正文(base64 二进制数据)?

django - 在 windows :Can't find msguniq. 中安装 gettext 确保您安装了 GNU gettext 工具 0.15 或更新版本

sql - Django QuerySet.extra() 和 PostgreSQL Age() 函数