Lighttpd + fastcgi + django: усеченный ответ, отправленный клиенту из-за неожиданного EOF

Я пытаюсь привести свое веб-приложение на основе Django в рабочую конфигурацию развертывания, и, потратив кучу времени, пытаясь заставить его работать под lighttpd / fastcgi, не могу решить эту проблему. Когда клиент входит в систему в первый раз, он получает от сервера большой дамп данных, который разбивается на несколько блоков размером ~ 1 МБ, которые отправляются обратно в формате 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 

Я действительно выдергиваю волосы, пытаясь понять, почему это происходит (чего не происходит при запуске Django в ./manage.py runserver режиме). Следующие вещи, которые я пробовал, не дали результата:

  • Уменьшение размера блока с 1 МБ до 256 КБ. Несмотря на то, что усечение обычно происходит на отметке 600–900 КБ, у меня все же есть усечения ниже размера блока 256 КБ.

  • Установка значений minspare и maxchildren на runfgci в Django очень высокими, чтобы было много свободных потоков.

  • Установка maxchildren в 1, чтобы был только один поток.

  • Переключение между режимом сокета UNIX и режимом TCP / IP для соединения fastcgi между lighttpd и Django.

Я много искал в Google для этого, но не смог найти ничего, что казалось бы исправлением для Django (казалось, что любая помощь связана с настройкой настроек PHP).

Моя установка:

  • OSX 10.6.4

  • Python 2.6.1 (система)

  • lighttpd устанавливается с Macports (1.4.26_1 + ssl)

  • flup установлен из последней версии Python egg на веб-сайте flup (пробовал как стабильную версию 1.0.2, так и последнюю версию 1.0.3)

  • Django 1.2.1 установлен из архива на сайте Django

Блок FastCGI в моей конфигурации lighttpd:

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 отправляет TCP FIN в Django, что, по-видимому, является причиной разрыва соединения и вот как получается усечение.

На первый взгляд кажется, что это ошибка Lighttpd, так как похоже, что он выключает вещи раньше, чем предполагалось ... хотя я не уверен, что он этого не делает, потому что он получил некоторые неверные данные из Django, на который он реагирует завершением работы.


person glenc    schedule 15.09.2010    source источник


Ответы (2)


Чего бы это ни стоило, я в конечном итоге перескочил на nginx, и все, кажется, работает нормально, поэтому мои подозрения, что это была ошибка lighttpd, а не ошибочная реализация fcgi в Django, похоже, были обоснованными.

На самом деле я обнаружил, что установка nginx намного проще, чем lighttpd, не говоря уже о том, что вы можете установить macport nginx (port install nginx + ssl), который не содержит ошибку нарушения SSL, от которой страдает lighttpd здесь.

person glenc    schedule 16.09.2010

Вы уверены, что у вас что-то еще не прослушивает порт 8000. Этот порт обычно используется для HTTP-серверов по соглашению, и было бы плохой идеей запускать на нем процесс FASTCGI. Предлагаю вам использовать другой порт, где-то рядом с диапазоном 8xxx.

person Graham Dumpleton    schedule 15.09.2010
comment
Привет, Грэм. Да, я уверен, что порт 8000 не является проблемой, потому что (1) если что-то уже было привязано к порту 8000, тогда Django выйдет из строя при запуске с ошибкой не может привязать к адресу (2), если что-то еще, кроме моего Django сервер отправлял данные обратно в lighttpd через этот порт, я бы получал ошибки формата данных на клиенте при каждом ответе, а не периодически, как я вижу (3) та же проблема возникает при использовании сокетов UNIX, а не TCP / IP на порт 8000 (4) Я попробовал его на порте 34567 для полноты картины и получил усечение с первой попытки. - person glenc; 15.09.2010