nginx + fastCGI + Django - mendapatkan korupsi data dalam respons yang dikirim ke klien

10

Saya menjalankan Django di belakang nginx menggunakan FastCGI. Saya telah menemukan bahwa di beberapa respons yang dikirim ke klien, korupsi data acak terjadi di tengah-tengah respons (mungkin beberapa ratus byte atau lebih di tengah).

Pada titik ini saya telah mempersempitnya menjadi bug dalam FastCGI handler nginx atau FastCGI handler Django (yaitu mungkin bug dalam flup), karena masalah ini tidak pernah terjadi ketika saya menjalankan server Django dalam runservermode standalone (yaitu ). Ini hanya terjadi dalam mode FastCGI.

Tren menarik lainnya:

  • Ini cenderung terjadi pada respons yang lebih besar. Ketika seorang klien login untuk pertama kalinya, mereka dikirim sekelompok potongan 1MB untuk menyinkronkan mereka ke server DB. Setelah sinkronisasi pertama itu, responsnya jauh lebih kecil (biasanya beberapa KB sekaligus). Korupsi sepertinya selalu terjadi pada potongan 1MB yang dikirim di awal.

  • Ini terjadi lebih sering ketika klien terhubung ke server melalui LAN (yaitu latensi rendah, koneksi bandwidth tinggi). Ini membuat saya berpikir ada semacam kondisi balapan di nginx atau flup yang diperburuk oleh peningkatan kecepatan data.

Saat ini, saya harus mengatasi ini dengan meletakkan intisari SHA1 tambahan di header respons, dan meminta klien menolak respons di mana header tidak cocok dengan checksum tubuh, tetapi ini adalah semacam solusi yang mengerikan.

Adakah orang lain yang mengalami hal seperti ini, atau memiliki petunjuk bagaimana mengidentifikasi apakah itu gagal atau nginx yang salah di sini sehingga saya dapat mengajukan bug ke tim yang sesuai?

Terima kasih sebelumnya atas bantuannya.

Catatan: Saya juga memposting bug serupa di lighttpd + FastCGI + Django beberapa waktu lalu di sini: /programming/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to -tidak terduga ... meskipun ini bukan hal yang sama (pemotongan vs korupsi), itu mulai terlihat seperti penyebab umum adalah flup / Django daripada server web ..

Sunting: Saya juga harus perhatikan apa lingkungan saya:

  • OSX 10.6.6 pada Mac Mini

  • Python 2.6.1 (Sistem)

  • Django 1.3 (dari tarball resmi)

  • flup 1.0.2 (dari Python egg di situs flup)

  • nginx + ssl 1.0.0 (dari Macports)

EDIT: Sebagai tanggapan terhadap komentar Jerzyk, jalur kode yang mengumpulkan respons terlihat seperti (diedit untuk ringkas):

# 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

Saya tidak berpikir itu mungkin bahwa Panjang Konten salah berdasarkan itu, dan AFAIK tidak ada cara untuk menandai objek Django HttpResponse secara eksplisit biner sebagai lawan dari teks. Juga, karena masalah ini hanya terjadi sebentar-sebentar, saya tidak berpikir itu menjelaskan kalau tidak Anda mungkin akan melihatnya pada setiap permintaan.

EDIT @ionelmc: Anda harus mengatur Panjang Konten di Django - nginx tidak mengatur ini untuk Anda, seperti contoh di bawah ini setelah saya menonaktifkan pengaturan Panjang Konten secara eksplisit:

$ 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
Glenc
sumber
Jika potongan awal tidak sering berubah atau tidak spesifik pengguna mungkin menulis ke disk dan melayani langsung melalui nginx adalah cara yang lebih baik?
sunn0
Sayangnya, potongan-potongannya khusus untuk pengguna dan sering berubah, jadi tidak ada caching seperti itu yang sesuai untuk aplikasi ini. Saya juga tertarik untuk mencari tahu apa yang sebenarnya menyebabkan korupsi data ini daripada hanya mengatasinya (yang sudah saya lakukan dengan intisari SHA1 tambahan di header).
glenc
Saya dapat memikirkan dua alasan yang mungkin: penyandian yang salah - HttpRespose sebagai teks vs header biner atau salah (terutama panjang konten)
Jerzyk
1
@glenc, apa tipe konten untuk respons ini? jika ini biner - dapatkah Anda mencoba mengaturnya? (mis. mimetype = 'application / x-ms-excel' atau lainnya)
Jerzyk
2
Anda tidak perlu mengatur panjang konten jika Transfer-Pengkodean Anda terpotong. rfc 2616 secara eksplisit melarang ini: "Bidang header Panjang Konten TIDAK HARUS dikirim jika dua panjang ini berbeda (yaitu, jika bidang header Transfer-Pengkodean hadir)."
ionelmc

Jawaban:

1

Apakah Anda memiliki arahan nginx caching (bypass / no_cache) apa pun yang aktif untuk respons fastcgi?

Di nginx '1.0.3 Changenote mereka memperbaiki respons korupsi:

Perbaikan bug: respons yang di-cache mungkin rusak jika "proxy / fastcgi / scgi / uwsgi_cache_bypass" dan "proxy / fastcgi / scgi / uwsgi_no_cache" nilai direktif berbeda; bug telah muncul di 0.8.46.

Sumber: http://nginx.org/en/CHANGES (bagian 1.0.3.)

Michel Feldheim
sumber
0

Mungkin korupsi sesekali hanya terjadi jika output mengandung setidaknya satu karakter UTF-8.

Panjang konten dan panjang string bukan hal yang sama, karena satu karakter UTF-8 dapat berisi 2 hingga 5 byte.

Andy Lee Robinson
sumber
Hmmmm .. sementara ini benar sepertinya tidak menjadi penyebabnya karena korupsi terjadi di tengah potongan data dan bukan hanya kasus hilangnya data pada akhirnya.
glenc
0

Salah satu cara untuk memecahkan masalah ini sedikit lebih banyak adalah dengan:

  • memiliki nginx dan Django berjalan pada perangkat keras yang berbeda (sehingga Anda dapat dengan mudah menangkap lalu lintas)
  • tangkap lalu lintas dari klien ke - / -> nginx dan nginx - / -> django (mis. gunakan wireshark)

Setelah Anda mendeteksi kesalahan di sisi klien (berdasarkan sha1), pergi ke tangkapan jaringan, lihat ke aliran yang direkam (TCP) dan cobalah untuk menemukan apakah masalah dihasilkan oleh nginx atau apakah itu datang (langsung) dari Django .

cipy
sumber
0

Saya memiliki masalah yang sangat mirip yang mengganggu saya selama saya memiliki pengaturan ini. Seperti Anda, saya menggunakan FastCGI, Nginx dan macOS, dan menemukan korupsi acak di tengah permintaan besar (sekitar 2% dari permintaan dokumen 1,5 MB).

Saya dapat memecahkan masalah saya dengan beralih ke soket Unix melalui TCP untuk koneksi FastCGI antara PHP-FPM (dalam kasus saya) dan Nginx. Saya tidak tahu bagian mana dari teka-teki yang bertanggung jawab atas korupsi, tetapi menghindari koneksi TCP internal memang memperbaikinya.

Robert
sumber