我试图让我的基于 Django 的 webapp 进入一个有效的部署配置,并且在花了很多时间试图让它在 lighttpd / fastcgi 下工作之后,无法解决这个问题。当客户端第一次登录时,他们会收到来自服务器的大量数据转储,这些转储数据被分成几个约 1MB 大小的块,以 JSON 的形式发回。
每隔一段时间,客户端就会收到一个对其中一个块的截断响应,我会在 lighttpd 日志中看到这条消息:
2010-09-14 23:25:01: (mod_fastcgi.c.2582) unexpected end-of-file (perhaps the fastcgi process died): pid: 0 socket: tcp:127.0.0.1:8000
2010-09-14 23:25:01: (mod_fastcgi.c.3382) response already sent out, but backend returned error on socket: tcp:127.0.0.1:8000 for /myapp.fcgi?, terminating connection
我真的很想弄清楚为什么会发生这种情况(在./manage.py runserver
模式下运行 Django 时不会发生这种情况)。以下是我尝试过的没有效果的事情:
将块大小从 1MB 减少到 256K。尽管截断通常发生在 600K - 900K 标记附近,但我仍然在 256K 块大小以下截断。
将Django 的
minspare
and值设置得非常高,这样会有很多闲置线程。maxchildren
runfgci
设置
maxchildren
为 1 以便只有一个线程。针对 lighttpd 和 Django 之间的 fastcgi 连接在 UNIX 套接字模式和 TCP/IP 模式之间切换。
我在谷歌上搜索了很多东西,但找不到任何似乎可以修复 Django 的东西(任何帮助似乎都围绕着调整 PHP 设置)。
我的设置是:
OSX 10.6.4
Python 2.6.1(系统)
从 Macports 安装的 lighttpd (1.4.26_1+ssl)
从flup网站上最新的Python egg安装的flup(尝试了1.0.2 stable和最新的1.0.3 devel)
从 Django 网站上的 tarball 安装的 Django 1.2.1
我的 lighttpd 配置中的 FastCGI 块是:
fastcgi.server = ("/myapp.fcgi" =>
("django" =>
(
#"socket" => lighttpd_base + "fcgi.sock",
"host" => "127.0.0.1",
"port" => 8000,
"check-local" => "disable",
"max-procs" => 1,
"debug" => 1
)
)
)
runfcgi
我用来启动 Django的命令目前是:
./manage.py runfcgi daemonize=false debug=true host=127.0.0.1 port=8000
method=threaded maxchildren=1
如果有人对如何阻止这种情况发生有任何见解,我们将不胜感激。如果我不能相对快速地解决这个问题,我将不得不放弃 lighttpd + fastcgi 并查看 Apache + mod_wsgi 或者可能是 nginx + fastcgi,并且进入另一个网络服务器配置的前景不是我期待的......
提前感谢您的帮助。
编辑:附加信息
我在轻量级论坛上发现了这个页面,表明这可能是 Django 的错……在那种情况下,PHP 崩溃了。我检查了我的 Django 端的东西,发现即使在截断之后,发送截断响应的 Python 线程仍然会在之后运行并为后续请求提供服务,所以看起来流没有被线程打破异常并崩溃。
我想弄清楚是 Django 的 fcgi impl 还是 Lighttpd 出了问题(因为这将决定迁移到 nginx + fastcgi 是否真的可以解决任何问题),所以我查看了 Wireshark 中的数据包跟踪. 截断之前发生的事情的简化日志如下:
No. Time Info
30082 233.411743 django > lighttpd [PSH, ACK] Seq=860241 Ack=869 Win=524280 Len=8184 TSV=417114153 TSER=417114153
30083 233.411749 lighttpd > django [ACK] Seq=869 Ack=868425 Win=524280 Len=0 TSV=417114153 TSER=417114153
30084 233.412235 django > lighttpd [PSH, ACK] Seq=868425 Ack=869 Win=524280 Len=8 TSV=417114153 TSER=417114153
30085 233.412250 lighttpd > django [ACK] Seq=869 Ack=868433 Win=524280 Len=0 TSV=417114153 TSER=417114153
30086 233.412615 django > lighttpd [PSH, ACK] Seq=868433 Ack=869 Win=524280 Len=8184 TSV=417114153 TSER=417114153
30087 233.412628 lighttpd > django [ACK] Seq=869 Ack=876617 Win=524280 Len=0 TSV=417114153 TSER=417114153
30088 233.412723 lighttpd > django [FIN, ACK] Seq=869 Ack=876617 Win=524280 Len=0 TSV=417114153 TSER=417114153
30089 233.412734 django > lighttpd [ACK] Seq=876617 Ack=870 Win=524280 Len=0 TSV=417114153 TSER=417114153
30090 233.412740 [TCP Dup ACK 30088#1] lighttpd > django [ACK] Seq=870 Ack=876617 Win=524280 Len=0 TSV=417114153 TSER=417114153
30091 233.413051 django > lighttpd [PSH, ACK] Seq=876617 Ack=870 Win=524280 Len=8 TSV=417114153 TSER=417114153
30092 233.413070 lighttpd > django [RST] Seq=870 Win=0 Len=0
好的数据包在开始时来自 Django(30082 为 8184 字节,然后再次在 30086 为另一个 8184 字节),然后由于某种原因在条目 30088 处 Lighttpd 向FIN
Django 发送了一个 TCP,这可能是导致连接终止的原因,这就是你如何得到截断。
从表面上看,这似乎是 Lighttpd 的错,因为它看起来像是在它应该关闭之前关闭了东西......虽然我不确定它没有这样做,因为它收到了一些坏数据来自 Django,它通过关闭来做出反应。