这看起来像是 Nginx+uWSGI 超时的一个众所周知的问题,但我的设置不同,我找不到有关它的信息。
我在 uWSGI 上运行 Flask 应用,使用 http 协议(不是套接字)。当我查询 API 时,有时会收到错误:
uwsgi_response_write_body_do() TIMEOUT !!!
IOError: : write error
我在“工作时间”收到此错误的频率更高,即晚上收到此错误的频率较低。我查询的是长 JSON 数据(地理坐标,最大 50 MB),有时完全没有响应,有时只收到部分响应。以下是 Pythonrequests
请求中的错误:
requests.exceptions.ConnectionError: ('Connection aborted.', error(104, 'Connection reset by peer'))
requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
ValueError: Expecting object: line 1 column 5590371 (char 5590370)
ValueError: Unterminated string starting at: line 1 column 20998536 (char 20998535)
ValueError: end is out of bounds
# when I set `timeout=None` in Python
requests.exceptions.ReadTimeout: HTTPConnectionPool(host='mydomain.com', port=80): Read timed out. (read timeout=None)
连接是通过普通 HTTP(无 S)进行的。我的 uWSGI 配置如下:
[uwsgi]
module = run:app
pidfile = /tmp/app.pid
logto = /var/log/uwsgi/%n.log
master = true
processes = 2
http-socket = 0.0.0.0:someport
http-timeout = 300
die-on-term = true
我使用 运行此程序uwsgi /path/to/inifile
。没有 Nginx,但实际上之前使用 Nginx 时,我也遇到过同样的问题。所以我排除了这个。
我怎样才能避免这些超时?
答案1
我也使用 nginx + uwsgi 生成大文件,并遇到同样的问题。我通过在 nginx 使用指令中禁用 uwsgi 临时文件缓冲区解决了此问题uwsgi_max_temp_file_size 0;
。
我认为从 nginx 到客户端的传输速度远远慢于从 uwsgi 到 nginx 的速度。而且 nginx 的缓冲区已满,因此 uwsgi 需要等待很长时间才能有空间让 nginx 接收新数据,这会导致 uwsgi 的写入请求超时。
我在我的博客中发表了一篇博客来分析这个问题。
答案2
在 uwsgi 源代码中,只有两处出现该错误字符串。两者周围的代码看起来相似,因此让我们专注于其中之一:
ret = uwsgi_wait_write_req(wsgi_req);
if (ret < 0) { wsgi_req->write_errors++; return -1;}
if (ret == 0) {
// here we use the parent name
uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
wsgi_req->write_errors++;
return -1;
}
看起来如果的返回值uwsgi_wait_write_req
为零,则会触发TIMEOUT !!!
错误。uwsgi_wait_write_req
定义在uwsgi.h
作为:
#define uwsgi_wait_write_req(x) uwsgi.wait_write_hook( \
x->fd, uwsgi.socket_timeout) ; x->switches++
如果不深入挖掘,我不能 100% 确定这里socket_timeout
和uwsgi--socket-timeout
选项。
但是,我可以说,添加--socket-timeout 1200
到我的 uwsgi 调用确实修复了一种非常可靠的方法,可以TIMEOUT !!!
在通过慢速连接从 Python→uwsgi→nginx 设置下载相当大的文件时重现错误。
因此我认为增加--socket-timeout
是最好的选择,尽管我不确定是否还需要 nginx 配置中的其他缓冲设置。