5

我在 Heroku 上运行一个 Flask 应用程序,使用 gunicorn 和 eventlet 工作人员。我的应用程序上的一个特定路由经常接收带有一些相当大的字段的 POST 数据(x-www-form-urlencoded)——最多大约 500KB。

这在本地运行时工作正常,但在 Heroku 上,对该路由的请求需要 5 到 30 秒才能完成——并且几乎 100% 的时间都花在了第一次访问 request.form 上:

t = time.time()
action = str(request.form['action'])
dt = time.time() - t  # Often 10 seconds or more!

Newrelic 慢速请求跟踪也证实了这一点。数据库操作在这里或那里有几毫秒,然后是 Python 代码中的大量时间,显然花在等待一些 i/o 上,因为报告的 CPU 时间通常不到一毫秒。

我完全无法在本地环境中使用我在生产中使用的相同 gunicorn/eventlet 设置来重现这一点。即使是内置的调试 WSGI 服务器也能以闪电般的速度处理这些请求。

有人知道可能出了什么问题吗?是 Flask 的问题,还是我需要联系 Heroku 支持的问题?

4

1 回答 1

3

我想我弄清楚到底发生了什么。TL;DR 在服务器端实际上并没有很慢,我只是被 Newrelic 报告的响应时间误导了!

我尝试在 dotCloud 的沙箱上运行与@AllanAnderson 建议的相同的代码。我首先创建了一个简化的测试用例:一个简单的 HTML 表单,其中预先加载了大约 900KB 数据的几个隐藏字段,以及一个视图函数,除了从 request.form 字典中读取之外什么都不做,并使用测量每次访问的经过时间时间。时间()。

在 Heroku 上,结果如下所示:

5.87100 seconds: read field "p1": 786432 bytes
0.00019 seconds: read field "p2": 131072 bytes
0.00003 seconds: read field "p3": 12288 bytes
0.00001 seconds: read field "p4": 1024 bytes

在 dotCloud 上:

0.00096 seconds: read field "p1": 786432 bytes
0.00019 seconds: read field "p2": 131072 bytes
0.00003 seconds: read field "p3": 12288 bytes
0.00001 seconds: read field "p4": 1024 bytes

然而,这两个测试在我的浏览器中似乎花费了相同的时间......现在你可能已经猜到了这个“问题”的真正答案。:-)

事实证明,Heroku 上的 gunicorn 在收到标头后立即执行视图功能,并且对 request.form 的第一次访问被阻止,直到收到请求的其余部分。因此,Newrelic 看到了所有这些非常慢的响应时间,这实际上只是通过糟糕的网络连接上传 POST 数据的结果。dotCloud 的设置显然只是等到收到整个请求。

这使得 Newrelic 的指标不那么有用,但它实际上并不是最终用户体验的问题。

于 2013-02-12T23:48:41.527 回答