nginx + fastCGI + Django - отримання пошкодження даних у відповідях, що надсилаються клієнту


10

Я запускаю Django за nginx за допомогою FastCGI. Я виявив, що в деяких відповідях, що надсилаються клієнту, випадкові пошкодження даних трапляються в середині відповідей (це може бути пару сотень байт в середині).

На даний момент я звузив це до помилки або в обробнику FastCGI nginx, або в обробнику Django FastCGI (тобто, мабуть, помилка в потоці), оскільки ця проблема ніколи не виникає, коли я запускаю сервер Django в автономному (тобто runserver) режимі. Це відбувається лише в режимі FastCGI.

Інші цікаві тенденції:

  • Це, як правило, відбувається в більшій кількості реакцій. Коли клієнт входить у перший раз, йому надсилається купа шматів розміром 1 Мб для синхронізації їх із сервером БД. Після першої синхронізації відповіді значно менші (зазвичай це кілька кБ одночасно). Здається, що корупція завжди трапляється на тих шматочках розміром 1 МБ, які були надіслані на старті.

  • Це трапляється частіше, коли клієнт підключений до сервера через локальну мережу (тобто з низькою затримкою, високою пропускною здатністю). Це змушує мене думати, що існує якийсь стан перегонів у nginx або flup, який посилюється збільшенням швидкості передачі даних.

Зараз мені довелося обійти це питання, додавши додатковий дайджест SHA1 у заголовок відповіді та отримавши клієнт відхилити відповіді, коли заголовок не відповідає контрольній сумі тіла, але це своєрідне жахливе рішення.

Хто-небудь ще відчував щось подібне, чи є якісь вказівки щодо того, як визначити, чи винен тут флуп або nginx, щоб я міг подати помилку у відповідну команду?

Заздалегідь дякую за будь-яку допомогу.

Примітка. Я також опублікував аналогічну помилку в lighttpd + FastCGI + Django, а тут: /programming/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to -неочікувано ... навіть якщо це не те саме (укорочення проти корупції), воно починає виглядати так, що звичайним винуватцем є Flup / Django, а не веб-сервер ..

Редагувати: Я також повинен зазначити, що таке моє середовище:

  • OSX 10.6.6 на Mac Mini

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

  • Django 1.3 (від офіційного тарболу)

  • Flup 1.0.2 (від яйця Python на сайті Flup)

  • nginx + ssl 1.0.0 (від Macports)

EDIT: У відповідь на коментар Єжика шлях коду, який збирає відповідь, виглядає таким чином (відредагований для лаконічності):

# This returns an objc NSData object, which is an array.array 
# when pushed through the PyObjC bridge
ret = handler( request ) 

response = HttpResponse( ret )
response[ "Content-Length" ] = len( ret )
return response

Я не думаю, що неможливо, що довжина вмісту є помилковою на основі цього, і AFAIK не може позначати об'єкт Django HttpResponse як явно бінарний на відміну від тексту. Крім того, оскільки проблема трапляється лише з перервами, я не думаю, що це пояснює це інакше, імовірно, ви б бачили її при кожному запиті.

EDIT @ionelmc: Вам потрібно встановити довжину вмісту в Django - nginx не встановлює це для вас, як показано в наведеному нижче прикладі, як тільки я відключив встановлення довжини вмісту:

$ curl -i http://localhost/io/ping
HTTP/1.1 200 OK
Server: nginx/1.0.0
Date: Thu, 23 Jun 2011 13:37:14 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive

AKSJDHAKLSJDHKLJAHSD

Якщо початкові фрагменти не змінюються часто або не є певними користувачами, можливо, краще записати на диск і подати безпосередньо через nginx?
sunn0

На жаль, фрагменти є як певними користувачами, так і часто змінюються, тому жодне кешування такого роду не було б доречним для цієї програми. Я також хочу дізнатися, що насправді спричиняє корупцію цих даних, а не просто працювати над ними (що я вже роблю з додатковим дайджестом SHA1 у заголовку).
glenc

Я можу подумати про дві можливі причини: неправильне кодування - HttpRespose як текст проти бінарних або неправильних заголовків (особливо довжина вмісту)
Jerzyk

1
@glenc що таке тип вмісту для цієї відповіді? якщо це двійкове - чи можете ви спробувати його встановити? (наприклад, mimetype = 'application / x-ms-excel' або інше)
Jerzyk

2
Вам не потрібно встановлювати довжину вмісту, якщо ваше кодування Transfer-кодування відмінено. rfc 2616 явно забороняє це: "Поле заголовка довжини вмісту НЕ МОЖЕ надсилатися, якщо ці дві довжини відрізняються (тобто, якщо є поле заголовка Transfer-Encoding)."
ionelmc

Відповіді:


1

Чи є у вас будь-яка директива щодо кешування nginx (bypass / no_cache) для швидких відповідей?

У nginx '1.0.3 Changenotes вони виправили корупцію відповідей:

Виправлення: кешована відповідь може бути порушена, якщо значення директив "proxy / fastcgi / scgi / uwsgi_cache_bypass" та "proxy / fastcgi / scgi / uwsgi_no_cache" були різними; помилка з’явилася в 0.8.46.

Джерело: http://nginx.org/en/CHANGES (розділ 1.0.3.)


0

Можливо, випадкова корупція трапляється лише в тому випадку, якщо вихід містить хоча б один символ UTF-8.

Довжина вмісту та довжина рядка - це не одне і те ж, оскільки один символ UTF-8 може містити від 2 до 5 байт.


Хмммм .. хоча це правда, це, мабуть, не є причиною, оскільки корупція сталася посеред фрагментів даних і не була просто випадком відсутності даних наприкінці.
glenc

0

Одним із способів виправити цю справу трохи більше буде:

  • встановити nginx та django на різних апаратних засобах (щоб ви могли легко захоплювати трафік)
  • захоплення трафіку від клієнта до - / -> nginx і nginx - / -> django (тобто використовувати wireshark)

Як тільки ви виявите помилку на стороні клієнта (на основі sha1), перейдіть до мережевого захоплення, загляньте в записаний потік (TCP) і спробуйте знайти, чи проблема породжена nginx чи вона походить безпосередньо від django .


0

У мене була дуже схожа проблема, яка мучила мене так довго, як у мене це налаштування. Як і ви, я використовую FastCGI, Nginx та macOS і виявив випадкову пошкодження посеред великих запитів (це було близько 2% запитів документа 1,5 Мб).

Мені вдалося вирішити свою проблему, перейшовши на сокети Unix через TCP для FastCGI-з'єднання між PHP-FPM (у моєму випадку) та Nginx. Я не знаю, який фрагмент головоломки є причиною корупції, але уникнення внутрішнього TCP-з'єднання вирішило це.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.