nginx + fastCGI + Django - รับความเสียหายของข้อมูลในการตอบสนองที่ส่งไปยังลูกค้า


10

ฉันใช้ Django ที่อยู่เบื้องหลัง nginx โดยใช้ FastCGI ฉันได้ค้นพบว่าในการตอบสนองบางอย่างที่ส่งไปยังลูกค้าการสุ่มข้อมูลเกิดขึ้นกลางการตอบสนอง (อาจเป็นสองร้อยไบต์หรือประมาณกลาง)

ณ จุดนี้ฉันได้แคบลงไปทั้งเป็นบั๊กในตัวจัดการ FastCGI ของ nginx หรือตัวจัดการ FastCGI ของ Django (เช่นอาจเป็นจุดบกพร่องใน flup) เนื่องจากปัญหานี้ไม่เคยเกิดขึ้นเมื่อฉันเรียกใช้เซิร์ฟเวอร์ Django ในrunserverโหมดสแตนด์อโลน (เช่น) มันเกิดขึ้นในโหมด FastCGI เท่านั้น

แนวโน้มที่น่าสนใจอื่น ๆ :

  • มันมีแนวโน้มที่จะเกิดขึ้นกับการตอบสนองที่มากขึ้น เมื่อลูกค้าเข้าสู่ระบบเป็นครั้งแรกพวกเขาจะถูกส่งจำนวนชิ้น 1MB เพื่อซิงค์พวกเขาไปยังเซิร์ฟเวอร์ฐานข้อมูล หลังจากซิงค์ครั้งแรกคำตอบจะเล็กกว่ามาก (โดยปกติจะมีไม่กี่ KB ต่อครั้ง) ความเสียหายมักจะเกิดขึ้นกับชิ้นส่วนขนาด 1MB ที่ส่งไปเมื่อเริ่มต้น

  • มันเกิดขึ้นบ่อยครั้งเมื่อไคลเอนต์เชื่อมต่อกับเซิร์ฟเวอร์ผ่าน LAN (เช่นการเชื่อมต่อที่มีความหน่วงต่ำการเชื่อมต่อที่มีแบนด์วิธสูง) นี่ทำให้ฉันคิดว่ามีสภาพการแข่งขันบางอย่างใน nginx หรือ flup ที่เลวร้ายลงด้วยอัตราข้อมูลที่เพิ่มขึ้น

ตอนนี้ฉันต้องหลีกเลี่ยงปัญหานี้โดยใส่ SHA1 แยกย่อยไว้ในส่วนหัวการตอบกลับและให้ลูกค้าปฏิเสธการตอบกลับโดยที่ส่วนหัวไม่ตรงกับการตรวจร่างกาย แต่นี่เป็นวิธีการแก้ปัญหาที่น่ากลัว

มีคนอื่นที่เคยมีประสบการณ์เช่นนี้หรือมีพอยน์เตอร์ใด ๆ เกี่ยวกับวิธีการระบุว่ามันเป็น flup หรือ 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 (จาก tarball อย่างเป็นทางการ)

  • flup 1.0.2 (จาก Python egg บนไซต์ flup)

  • nginx + ssl 1.0.0 (จาก Macports)

แก้ไข: ในการตอบสนองต่อความคิดเห็นของ Jerzyk เส้นทางรหัสที่ประกอบการตอบสนองดูเหมือน (แก้ไขเพื่อความชัดเจน):

# 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 เป็นไบนารีอย่างชัดเจนเมื่อเทียบกับข้อความ นอกจากนี้เนื่องจากปัญหาเกิดขึ้นเป็นระยะ ๆ เท่านั้นฉันไม่คิดว่าจะอธิบายเป็นอย่างอื่นอย่างที่คุณเห็นในทุกคำขอ

แก้ไข @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

น่าเสียดายที่ chunks นั้นมีทั้งแบบเฉพาะผู้ใช้และมีการเปลี่ยนแปลงบ่อยดังนั้นจึงไม่มีการแคชชนิดนั้นที่เหมาะสมสำหรับแอปพลิเคชันนี้ ฉันยังกระตือรือร้นที่จะค้นหาว่าอะไรคือสาเหตุที่ทำให้เกิดความเสียหายของข้อมูลมากกว่าที่จะหลีกเลี่ยงสิ่งนี้
glenc

ฉันสามารถคิดด้วยเหตุผลสองประการเป็นไปได้: การเข้ารหัสผิด - HttpRespose เป็นไบนารีข้อความเมื่อเทียบกับส่วนหัวหรือผิด (โดยเฉพาะเนื้อหาที่มีความยาว)
Jerzyk

1
@glenc เป็นประเภทเนื้อหาสำหรับการตอบสนองนี้คืออะไร? ถ้านี่เป็นเลขฐานสอง - คุณลองตั้งมันได้ไหม (เช่น mimetype = 'application / x-ms-excel' หรืออื่น ๆ )
Jerzyk

2
คุณไม่จำเป็นต้องตั้งค่าความยาวเนื้อหาหากการเข้ารหัสการถ่ายโอนของคุณเป็นก้อน rfc 2616 ห้ามอย่างชัดเจน: "ฟิลด์ส่วนหัวความยาวเนื้อหาต้องไม่ถูกส่งหากความยาวทั้งสองนี้แตกต่างกัน (เช่นถ้ามีส่วนหัวฟิลด์การเข้ารหัสการโอนย้ายอยู่)"
ionelmc

คำตอบ:


1

คุณมีคำสั่งแคช nginx (บายพาส / no_cache) ใด ๆ ที่แอ็คทีฟสำหรับการตอบกลับ fastcgi หรือไม่?

ใน 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 ไบต์


Hmmmm .. ในขณะนี้เป็นจริงมันไม่น่าจะเป็นสาเหตุเพราะความเสียหายที่เกิดขึ้นในช่วงกลางของชิ้นข้อมูลและไม่ได้เป็นเพียงแค่กรณีของข้อมูลที่ขาดหายไปในตอนท้าย
glenc

0

วิธีหนึ่งในการแก้ไขปัญหากรณีนี้อีกเล็กน้อยจะเป็น:

  • ให้ nginx และ django ทำงานบนฮาร์ดแวร์ที่แตกต่างกัน (เพื่อให้คุณสามารถจับภาพการรับส่งข้อมูลได้อย่างง่ายดาย)
  • จับภาพการรับส่งข้อมูลจากไคลเอ็นต์ไปยัง - / -> nginx และ nginx - / -> django (เช่นใช้ wireshark)

เมื่อคุณตรวจพบข้อผิดพลาดในฝั่งไคลเอ็นต์ (ตาม sha1) ให้ไปที่การดักจับเครือข่ายดูในสตรีมที่บันทึก (TCP) แล้วลองค้นหาว่าปัญหาถูกสร้างขึ้นโดย nginx หรือมาจาก django โดยตรง .


0

ฉันมีปัญหาที่คล้ายกันมากซึ่งทำให้ฉันรำคาญตราบใดที่ฉันมีการตั้งค่านี้ เช่นเดียวกับคุณฉันใช้ FastCGI, Nginx และ macOS และพบความเสียหายแบบสุ่มในระหว่างการร้องขอขนาดใหญ่ (ประมาณ 2% ของการร้องขอของเอกสาร 1.5 MB)

ฉันสามารถแก้ปัญหาของฉันได้โดยสลับไปใช้ Unix sockets ผ่าน TCP สำหรับการเชื่อมต่อ FastCGI ระหว่าง PHP-FPM (ในกรณีของฉัน) และ Nginx ฉันไม่รู้ว่าตัวต่อชิ้นใดรับผิดชอบต่อความเสียหาย แต่การหลีกเลี่ยงการเชื่อมต่อ TCP ภายในไม่สามารถแก้ไขได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.