[英]Slow access to Django's request.body
有些移動客戶端提交時,有時這行Django應用程序(使用Apache / mod_wsgi托管)需要花費大量時間來執行(例如99%的請求處理,如New Relic所測量的6秒):
raw_body = request.body
(其中request
是傳入請求)
我有的問題:
request.body
訪問速度呢? Django 在HttpRequest
的body
屬性是一個屬性 ,因此它真正解決了那里真正做的事情,以及如果可能的話,如何在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_proxy與ProxyIOBufferSize
, ProxyReceiveBufferSize
和環回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.