nginx + fastCGI + Django - bị hỏng dữ liệu trong các phản hồi được gửi cho khách hàng


10

Tôi đang chạy Django phía sau nginx bằng FastCGI. Tôi đã phát hiện ra rằng trong một số phản hồi được gửi cho khách hàng, lỗi dữ liệu ngẫu nhiên xảy ra ở giữa các phản hồi (có thể là vài trăm byte hoặc hơn ở giữa).

Tại thời điểm này, tôi đã thu hẹp nó thành một lỗi trong trình xử lý FastCGI của nginx hoặc trình xử lý FastCGI của Django (có lẽ là lỗi trong flup), vì sự cố này không bao giờ xảy ra khi tôi chạy máy chủ Django ở runserverchế độ độc lập (tức là ). Nó chỉ xảy ra trong chế độ FastCGI.

Xu hướng thú vị khác:

  • Nó có xu hướng xảy ra trên các phản ứng lớn hơn. Khi một khách hàng đăng nhập lần đầu tiên, họ được gửi một loạt các đoạn 1 MB để đồng bộ hóa chúng với DB máy chủ. Sau lần đồng bộ đầu tiên đó, các phản hồi nhỏ hơn nhiều (thường là vài KB mỗi lần). Tham nhũng dường như luôn xảy ra trên các khối 1MB được gửi khi bắt đầu.

  • Nó xảy ra thường xuyên hơn khi máy khách được kết nối với máy chủ thông qua mạng LAN (tức là độ trễ thấp, kết nối băng thông cao). Điều này khiến tôi nghĩ rằng có một số loại điều kiện chủng tộc trong nginx hoặc flup bị trầm trọng hơn do tốc độ dữ liệu tăng lên.

Ngay bây giờ, tôi đã phải giải quyết vấn đề này bằng cách đưa thêm thông báo SHA1 vào tiêu đề phản hồi và yêu cầu khách hàng từ chối phản hồi trong đó tiêu đề không khớp với tổng kiểm tra cơ thể, nhưng đây là một giải pháp kinh khủng.

Có ai khác đã trải nghiệm bất cứ điều gì như thế này, hoặc có bất kỳ gợi ý nào về cách xác định xem đó là flup hoặc nginx có lỗi ở đây để tôi có thể gửi lỗi với nhóm thích hợp không?

Cảm ơn trước sự giúp đỡ nào.

Lưu ý: Tôi cũng đã đăng một lỗi tương tự trong lighttpd + FastCGI + Django một lúc trước tại đây: /programming/3714361/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to - thật bất ngờ ... mặc dù điều này không giống nhau (cắt ngắn và tham nhũng), nhưng nó bắt đầu giống như thủ phạm phổ biến là flup / Django chứ không phải là máy chủ web ..

Chỉnh sửa: Tôi cũng cần lưu ý môi trường của tôi là gì:

  • OSX 10.6.6 trên máy Mac Mini

  • Python 2.6.1 (Hệ thống)

  • Django 1.3 (từ tarball chính thức)

  • flup 1.0.2 (từ trứng Python trên trang web flup)

  • nginx + ssl 1.0.0 (từ Macports)

EDIT: Đáp lại bình luận của Jerhot, đường dẫn mã lắp ráp phản hồi trông giống như (được chỉnh sửa cho gọn gàng):

# 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

Tôi không nghĩ rằng có thể Độ dài nội dung sai dựa trên điều đó và AFAIK không có cách nào để đánh dấu một đối tượng Django HttpResponse là nhị phân rõ ràng trái ngược với văn bản. Ngoài ra, vì vấn đề chỉ xảy ra không liên tục, tôi không nghĩ rằng điều đó giải thích nó nếu không có lẽ bạn sẽ thấy nó theo mọi yêu cầu.

EDIT @ionelmc: Bạn phải đặt Độ dài nội dung trong Django - nginx không đặt điều này cho bạn, theo ví dụ dưới đây một khi tôi đã tắt cài đặt Độ dài nội dung một cách rõ ràng:

$ 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

Nếu các khối ban đầu không thay đổi thường xuyên hoặc không cụ thể người dùng có thể ghi vào đĩa và phục vụ trực tiếp qua nginx là cách tốt hơn?
sunn0

Thật không may, các khối đều dành riêng cho người dùng và thường xuyên thay đổi, vì vậy không có bộ nhớ đệm loại nào phù hợp với ứng dụng này. Tôi cũng muốn tìm hiểu điều gì thực sự gây ra tham nhũng dữ liệu này thay vì chỉ làm việc xung quanh nó (điều mà tôi đã làm với bản tóm tắt SHA1 bổ sung trong tiêu đề).
glenc

Tôi có thể nghĩ ra hai lý do có thể xảy ra: mã hóa sai - HttpRespose là văn bản so với tiêu đề nhị phân hoặc sai (đặc biệt là độ dài nội dung)
Jer:

1
@glenc một loại nội dung cho phản hồi này là gì? nếu đây là nhị phân - bạn có thể thử đặt nó không? (ví dụ: mimetype = 'application / x-ms-excel' hoặc cách khác)
Jer:

2
Bạn không cần đặt độ dài nội dung nếu Mã hóa chuyển của bạn bị chunk. rfc 2616 rõ ràng cấm điều này: "Trường tiêu đề Độ dài nội dung KHÔNG được gửi nếu hai độ dài này khác nhau (nghĩa là, nếu có trường tiêu đề Mã hóa chuyển)."
ionelmc

Câu trả lời:


1

Bạn có bất kỳ loại lệnh nginx cache (bypass / no_cache) nào đang hoạt động cho các phản hồi fastcgi không?

Trong nginx '1.0.3 Changenote, họ đã sửa lỗi phản hồi:

Sửa lỗi: một phản hồi được lưu trong bộ nhớ cache có thể bị phá vỡ nếu các giá trị chỉ thị "proxy / fastcgi / scgi / uwsgi_cache_bypass" và "proxy / fastcgi / scgi / uwsgi_no_cache" khác nhau; lỗi đã xuất hiện trong 0.8.46.

Nguồn: http://nginx.org/vi/CHANGES (phần 1.0.3.)


0

Có lẽ tham nhũng không thường xuyên chỉ xảy ra nếu đầu ra chứa ít nhất một ký tự UTF-8.

Độ dài nội dung và độ dài chuỗi không giống nhau, vì một ký tự UTF-8 có thể chứa 2 đến 5 byte.


Hmmmm .. trong khi điều này là đúng thì có vẻ như đó không phải là nguyên nhân vì tham nhũng đã xảy ra ở giữa các khối dữ liệu và không chỉ đơn giản là trường hợp mất dữ liệu ở cuối.
glenc

0

Một cách để khắc phục sự cố này thêm một chút là:

  • có nginx và django chạy trên phần cứng khác nhau (để bạn có thể dễ dàng nắm bắt lưu lượng truy cập)
  • nắm bắt lưu lượng truy cập từ máy khách đến - / -> nginx và nginx - / -> django (tức là sử dụng wireshark)

Khi bạn phát hiện ra lỗi ở phía máy khách (dựa trên sha1), hãy truy cập mạng chụp, xem xét luồng (TCP) đã ghi và thử tìm xem sự cố được tạo bởi nginx hay nó đến (trực tiếp) từ django .


0

Tôi đã có một vấn đề tương tự gây khó chịu cho tôi miễn là tôi có thiết lập này. Giống như bạn, tôi sử dụng FastCGI, Nginx và macOS và thấy tham nhũng ngẫu nhiên ở giữa các yêu cầu lớn (đó là khoảng 2% yêu cầu của tài liệu 1,5 MB).

Tôi đã có thể giải quyết vấn đề của mình bằng cách chuyển sang ổ cắm Unix qua TCP để kết nối FastCGI giữa PHP-FPM (trong trường hợp của tôi) và Nginx. Tôi không biết phần nào của câu đố chịu trách nhiệm cho tham nhũng, nhưng tránh kết nối TCP nội bộ đã khắc phục nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.