簡體   English   中英

慢慢訪問Django的request.body

[英]Slow access to Django's request.body

有些移動客戶端提交時,有時這行Django應用程序(使用Apache / mod_wsgi托管)需要花費大量時間來執行(例如99%的請求處理,如New Relic所測量的6秒):

raw_body = request.body

(其中request是傳入請求)

我有的問題:

  1. 有什么可能放慢對request.body訪問速度呢?
  2. 在調用Django直到客戶端發送整個有效負載之前,Apache要等待的正確配置是什么? 也許問題出在Apache配置中。

Django HttpRequestbody屬性是一個屬性 ,因此它真正解決了那里真正做的事情,以及如果可能的話,如何在Django應用程序之外實現它。 我希望Apache在將其發送到Django應用程序之前等待完整請求。

關於(1),一旦請求的頭文件可用,Apache就會將控制權傳遞給mod_wsgi處理程序,然后mod_wsgi將控制傳遞給Python。 然后, request.body的內部實現調用read()方法,該方法最終調用mod_wsgi中的實現,該實現從Apache請求請求的主體 ,如果Apache尚未完全接收,則阻塞直到它可用。

關於(2),單獨使用mod_wsgi是不可能的。 至少, 處理傳入請求的鈎子不提供阻塞機制,直到完整請求可用。 另一張海報建議在回答這個重復問題時使用nginx作為代理。

有兩種方法可以在Apache中解決這個問題。

您可以使用>=2.3提供的mod_buffer ,並將BufferSize更改為最大預期有效負載大小。 這應該使Apache在內存中保留請求,直到它完成發送或達到緩沖區。

對於較舊的Apache版本< 2.3 ,您可以將mod_proxyProxyIOBufferSizeProxyReceiveBufferSize和環回vhost結合使用。 這涉及將您的真實虛擬主機置於環回接口上,並暴露連接回真實虛擬主機的代理虛擬主機。 這樣做的缺點是它使用了兩倍的套接字,並且可能使資源計算變得困難。

但是,最理想的選擇是在L4 / L7負載均衡器上啟用請求/響應緩沖。 例如, haproxy允許您基於req_len添加規則 ,同樣適用於nginx 大多數優秀的商業負載均衡器還可以選擇在發送之前緩沖請求。

所有這三種方法都依賴於緩沖完整的請求/響應有效負載,並且根據您的使用案例和可用資源存在性能考慮因素。 您可以將整個有效負載緩存在內存中,但這可能會大大降低最大並發連接數。 您可以選擇將有效負載寫入本地存儲(最好是SSD),但是您會受到IO容量的限制。

您還需要考慮文件上傳,因為這些不適合基於內存的有效負載緩沖。 在大多數情況下,您將在Web服務器中處理上載請求,例如HttpUploadModule ,然后查詢nginx以獲取上載進度 ,而不是直接在WSGI中處理它。 如果您正在緩沖負載均衡器,那么您可能希望從緩沖規則中排除文件上載。

您需要了解發生這種情況的原因 ,並且在發送響應和接收請求時都存在此問題。 保持這些保護也是一個好主意,不僅僅是為了擴展性,而是出於安全考慮

我擔心問題可能在於您傳輸的數據量以及可能的連接速度慢。 另請注意,上傳帶寬通常遠低於下載帶寬。

正如已經指出的那樣,當你使用request.body Django將等待整個主體從客戶端完全轉移並在服務器上內存(或在磁盤上,根據配置和大小)。

如果客戶端連接到連接到服務器本身的WiFi接入點,我建議你嘗試使用相同的請求會發生什么,看看它是否有所改進。 如果這是不可能的,也許只需在客戶端上運行像speedtest.net這樣的工具,獲取請求大小並進行數學計算,看看理論上需要多長時間(我預計時間大約為20) % 更多)。 請注意,網絡速度通常以每秒位數為單位,而文件大小則以字節為單位。

在某些情況下,如果需要對數據進行大量處理,則可以方便地read()請求並在移動中進行計算,或者可能直接將request對象傳遞給任何可以從中讀取的函數。 - 稱為“類文件對象”而不是字符串。

但是,在您的具體情況下,我擔心這只會影響從網絡接收身體所花費的1%的時間。

編輯:

對不起,現在我已經注意到了賞金中的額外描述。 我恐怕無法幫助你,但請問,有什么意義? 我猜這只會節省一點服務器資源,以保持python線程閑置一段時間,而不會在請求上有任何明顯的性能提升......

看看Django源代碼,它看起來就像你調用request時實際發生的那樣request.body是通過從流中讀取來將請求體加載到內存中。

https://github.com/django/django/blob/stable/1.4.x/django/http/ init .py#L390-L392

如果請求很大,可能的時間實際上只是將其加載到內存中。 Django在請求上有方法處理作為流的主體,這取決於正在消耗的內容是什么,可以讓您更有效地處理請求。

https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.read

例如,您可以一次讀取一行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM