5

我们在 heroku 上运行 django/gunicorn 服务器。我们的大多数用户所在的国家/地区的移动网络都不是那么好,因此他们的连接经常不稳定。

我们的大多数请求都是来自移动设备的“原始帖子”,似乎即使 POST 请求没有完全传输,请求也已经被发送给 gunicorn worker 处理。当工作人员尝试处理请求并读取数据时,它只是挂起等待剩余的数据。虽然这种行为对于在“流”模式下读取文件/图像数据是有意义的,但在我们的案例中却没有意义,因为我们所有的帖子都相对较小,可以很容易地被整个 Web 服务器读取,然后才转发到我们的 gunicorn工人。

当我们有许多这样的并行请求时,这种早期切换会导致麻烦——因为所有工作人员都可能被阻塞。目前,我们通过增加工人/测功机的数量来解决这个问题,但这非常昂贵。我找不到任何方法来强制 Web 服务器或 gunicorn 等待,并且只有在请求完全传输后才将请求转发给工作人员。

有没有办法让heroku的Web服务器/gunicorn仅在客户端完全传输请求(服务器完全接收)时才将请求传输给gunicorn工作者?

一些示例代码(我们添加了 newrelic 'per-instruction' tracking 以确保这是导致问题的确切行):

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)

这是此示例慢速请求的 New Relic 测量结果(它是一个包含 7K 数据的 POST)。读取 POST 需要 99% 的方法时间....

在此处输入图像描述

4

2 回答 2

0

您可能希望阅读本文并研究一个请求缓冲 HTTP 服务器,例如 Waitress。

于 2015-03-16T20:16:36.300 回答
0

在我看来,这里真正的问题是 gunicorn 正在阻塞。这是因为 gunicorn(默认情况下)使用同步工作者来运行您的任务。这意味着当 Web 请求命中 gunicorn 时,它将阻塞,直到它返回响应 - 在您的情况下,很长一段时间。

为了解决这个问题,你可以使用 gevent 和 gunicorn 来做非阻塞 IO。由于您的大部分时间都花在做 IO 事情上,这将确保 gunicorn 可以并行处理更多的 Web 请求。

要将 gevent 与 gunicorn 一起使用,您需要安装 gevent ( pip install -U gevent),并通过添加更改您的 gunicorn 启动命令:(gunicorn -k gevent这将告诉 gunicorn 使用 gevent 作为工作器)。

于 2012-09-18T05:43:35.393 回答