Min*_*ark 17 django performance web-services nginx gunicorn
我正在开发一个在nginx + gunicorn + django之上实现的Web服务.客户是智能手机应用程序.应用程序需要对外部API(Facebook,Amazon S3 ...)进行长时间运行调用,因此服务器只需将作业排队到作业服务器(使用Ceison over Redis).
只要有可能,一旦服务器对作业进行了排队,它就会立即返回,并且HTTP连接已关闭.这很好,并允许服务器承受非常高的负载.
client server job server
. | |
. | |
|------HTTP request----->| |
| |--------queue job------>|
|<--------close----------| |
. | |
. | |
Run Code Online (Sandbox Code Playgroud)
但在某些情况下,客户需要在作业完成后立即获得结果.不幸的是,一旦HTTP连接关闭,服务器就无法联系客户端.一种解决方案是依赖客户端应用程序每隔几秒轮询一次服务器,直到作业完成.如果可能的话,我想避免这种解决方案,主要是因为它会阻碍服务的反应性,还因为它会在服务器上加载许多不必要的轮询请求.
简而言之,我想保持HTTP连接正常运行,什么都不做(除了可能每隔一段时间发送一个空格以保持TCP连接活着,就像Amazon S3一样),直到工作完成,并且服务器返回结果.
client server job server
. | |
. | |
|------HTTP request----->| |
| |--------queue job------>|
|<------keep-alive-------| |
| [...] | |
|<------keep-alive-------| |
| |<--------result---------|
|<----result + close-----| |
. | |
. | |
Run Code Online (Sandbox Code Playgroud)
假设服务器处于非常高的负载状态,我怎样才能以有效的方式实现长时间运行的HTTP连接(目前情况并非如此,但目标是能够承受最高可能的负载,每秒有数百或数千个请求)?
将实际作业卸载到其他服务器应该确保服务器上的CPU使用率较低,但是如何避免堆积和使用所有服务器RAM的进程,或者由于打开连接太多而导致传入请求被丢弃?
这可能主要是正确配置nginx和gunicorn的问题.我已经阅读了一些基于gunicorn中的greenlets的异步工作者:文档说"异步工作者被" 应用程序进行长时间阻塞调用(即外部Web服务) "使用,这听起来很完美.它还说" 通常,应用程序应该能够使用这些工作类而不进行任何更改 ".听起来不错.对此有何反馈?
谢谢你的建议.
Min*_*ark 30
我正在回答我自己的问题,也许有人有更好的解决方案.
阅读gunicorn的文档更进一步,并阅读更多关于eventlet和gevent,我认为gunicorn完美地回答了我的问题.Gunicorn有一个管理工人池的主过程.每个worker可以是同步的(单线程,一次处理一个请求)或异步(每个worker几乎同时处理多个请求).
同步工作者很容易理解和调试,如果工作者失败,只会丢失一个请求.但是如果一个工人陷入长时间运行的外部API调用,它基本上就是在睡觉.因此,在高负载的情况下,所有工作人员可能在等待结果时最终都在睡觉,并且请求最终会被丢弃.
所以解决方案是将默认工作者类型从同步更改为异步(选择eventlet或gevent,这是一个比较).现在每个工作者都运行多个绿色线程,每个线程都非常轻量级.每当一个线程必须等待某个I/O时,另一个绿色线程将继续执行.这称为协作式多任务处理.它非常快,而且非常轻量级(如果等待I/O,单个工作程序可以处理数千个并发请求).正是我需要的.
我想知道我应该如何更改现有代码,但显然标准的python模块在启动时由gunicorn 进行猴子修补(实际上是由eventlet或gevent),因此所有现有代码都可以无变化地运行,并且仍然可以很好地与其他线程一起运行.
有许多参数可以在gunicorn中调整,例如使用gunicorn worker_connections参数的最大并发客户端数,使用该backlog参数的最大挂起连接数等.
这很棒,我马上开始测试!
| 归档时间: |
|
| 查看次数: |
8707 次 |
| 最近记录: |