我们在heroku上运行django / gunicorn服务器。我们的大多数用户都位于移动网络不是那么好的国家,因此他们经常会有不稳定的连接。
我们的大多数请求都是来自移动设备的“原始帖子”,似乎即使POST请求未完全传输,该请求也已被发送,由一名枪支工作人员处理。当工作人员试图处理请求并读取数据时,它只是挂起等待剩余的数据。虽然这种行为对于以“流”模式读取文件/图像数据是有意义的,但在我们的情况下没有任何意义,因为我们的所有帖子都相对较小,并且可以由Web服务器作为一个整体轻松读取,然后转发给我们的gunicorn工人。
当我们并行提出许多此类请求时,这种早期切换会导致麻烦 - 因为所有工作人员都可能被阻止。目前,我们通过增加工人/动力的数量来解决这个问题,但这是相当昂贵的。我找不到任何方法强制Web服务器或gunicorn等待,只有在完全传输后才将请求转发给工作人员。
有没有办法让heroku的web服务器/ gunicorn只在从客户端完全传输(由服务器完全接收)时将请求转移给gunicorn worker?
一些示例代码(我们添加了新的'per-instruction'跟踪以确保这是导致问题的确切行:)
def syncGameState(request):
transaction = agent.current_transaction()
with agent.FunctionTrace(transaction, "syncGameState_raw_post_data", 'Python/EndPoint'):
data = request.raw_post_data
with agent.FunctionTrace(transaction, "syncGameState_gameStateSyncRequest", 'Python/EndPoint'):
sync_request = sync_pb2.gameStateSyncRequest()
with agent.FunctionTrace(transaction, "syncGameState_ParseFromString", 'Python/EndPoint'):
sync_request.ParseFromString(data)
以下是此示例慢速请求的新Relic测量值(它是一个带有7K数据的POST)。阅读POST需要花费99%的方法时间....
答案 0 :(得分:0)
在我看来,真正的问题是枪炮是阻挡的。这是因为gunicorn(默认情况下)使用同步工作程序来运行您的任务。这意味着当一个Web请求到达gunicorn时它会阻塞,直到它返回一个响应 - 在你的情况下,很长一段时间。
要解决此问题,您可以使用gevent和gunicorn来执行非阻塞IO。由于大部分时间花在做IO事情上,这将确保gunicorn可以并行处理更多的Web请求。
要将gevent与gunicorn一起使用,您需要安装gevent(pip install -U gevent
),并通过添加:gunicorn -k gevent
来更改您的gunicorn启动命令(这将告诉gunicorn使用gevent作为工作者)。
答案 1 :(得分:0)
You might want to give this article a read并调查缓冲HTTP服务器(如Waitress)的请求。