慢慢访问Django的request.body

Tad*_*eck 12 python apache django performance request

有些移动客户端提交时,有时这行Django应用程序(使用Apache/mod_wsgi托管)需要花费大量时间来执行(例如99%的请求处理,如New Relic所测量的6秒):

raw_body = request.body
Run Code Online (Sandbox Code Playgroud)

(request传入请求在哪里)

我有的问题:

  1. 有什么可能减缓对request.body这么多的访问?
  2. 在调用Django直到客户端发送整个有效负载之前,Apache要等待的正确配置是什么?也许问题出在Apache配置中.

Django的body属性HttpRequest是一个属性,所以它真正解决了那里真正做的事情,以及如果可能的话,如何在Django应用程序之外实现它.我希望Apache在将其发送到Django应用程序之前等待完整请求.

Phi*_*lip 9

关于(1),一旦请求的头文件可用,Apache就会将控制权传递给mod_wsgi处理程序,然后mod_wsgi将控制传递给Python.然后,内部实现request.body调用read()最终调用mod_wsgi中的实现的方法,该方法从Apache请求请求的主体,如果尚未完全接收到Apache,则阻塞直到它可用.

关于(2),单独使用mod_wsgi是不可能的.至少,处理传入请求的钩子不提供阻塞机制,直到完整请求可用.另一张海报建议在回答这个重复问题时使用nginx作为代理.


sle*_*cal 9

有两种方法可以在Apache中解决这个问题.

您可以使用mod_buffer(可用)>=2.3,并更改BufferSize为最大预期有效负载大小.这应该使Apache在内存中保留请求,直到它完成发送或达到缓冲区.

对于旧版本的Apache < 2.3,您可以使用mod_proxy的联合ProxyIOBufferSize,ProxyReceiveBufferSize并回送虚拟主机.这涉及将您的真实虚拟主机置于环回接口上,并暴露连接回真实虚拟主机的代理虚拟主机.这样做的缺点是它使用了两倍的套接字,并且可能使资源计算变得困难.

但是,最理想的选择是在L4/L7负载均衡器上启用请求/响应缓冲.例如,haproxy允许您添加基于nginx的规则req_len和相同的规则.大多数优秀的商业负载均衡器还可以选择在发送之前缓冲请求.

所有这三种方法都依赖于缓冲完整的请求/响应有效负载,并且根据您的用例和可用资源存在性能考虑因素.您可以将整个有效负载缓存在内存中,但这可能会大大降低最大并发连接数.您可以选择将有效负载写入本地存储(最好是SSD),但是您会受到IO容量的限制.

您还需要考虑文件上传,因为这些不适合基于内存的有效负载缓冲.在大多数情况下,您将在Web服务器中处理上载请求,例如 HttpUploadModule,然后查询nginx以获取上载进度,而不是直接在WSGI中处理它.如果您正在缓冲负载均衡器,那么您可能希望从缓冲规则中排除文件上载.

您需要了解发生这种情况的原因,并且在发送响应和接收请求时都存在此问题.保持这些保护也是一个好主意,不仅仅是为了扩展性,而是出于安全考虑.