Asp.Net 上傳大檔案專題(1)--概述:上傳大檔案的難點

iDotNetSpace發表於2009-06-03

正文部分:

        注意:以下紅色部分字型說明該內容引用於微軟的相關網站

        因為要做一個視訊網站,所以需要提供使用者上傳視訊的功能。可是ASP.Net自帶的上傳控制元件只能用於上傳小檔案,這顯然無法滿足需要。有些朋友可能要問了"為什麼需要用那個呀,直接FTP傳不就好了",是的,用FTP傳就方便了很多,但是FTP在使用者上傳後,無法對上傳的檔案進行線上編輯(比如格式轉換,新增到資料庫呀等),所有這些可以由網站自動完成的煩瑣的任務則都將交由管理人員來完成,這對於一個商業網站來說無疑增加了用人成本。而且這些重複的低腦力活的工作,看起來就和體力活沒什麼區別,這不又從另一個側面降低了我們這些IT人員的價值。扯遠了,言歸正傳,那MS為什麼要將這個上傳控制元件的能力限制這麼小呢?在MSDN以及微軟的其它網站上我們可以瞭解到:"
web.config 配置檔案中的 節的 maxRequestLength 引數的預設值為 4096 (4 MB)。所以,預設情況下不能上傳大於這個值的檔案。這也是為了防止拒絕服務攻擊。"

       可是,這樣一來就對我們上傳大檔案造成了麻煩。有些朋友可能發現既然限制上傳檔案大小是由於maxRequestLength 這個引數,那將這個值改大點不就OK了。的確,這樣做便可輕輕鬆鬆提高檔案上傳大小的限制,可是在"
上傳過程中,ASP.NET 首先將整個檔案載入到記憶體中,然後使用者才可以將該檔案儲存到磁碟。"也就是說,如果使用者上傳的檔案大小為100M,那麼伺服器的記憶體中就要拿出100M來存放使用者上傳的檔案;如果是10個使用者在同時上傳,暫且不提並行性的問題,那10個使用者就要佔用1000M的記憶體;如果是100、1000、甚至是幾萬個使用者呢?那麼,再大的記憶體都不夠你拿來提供使用者上傳的。   

        
"另外,其他因素也會影響可以上載的最大檔案大小。這些因素包括可用記憶體、可用硬碟空間、處理器速度和當前網路流量。對於上載的常規流量的檔案,Microsoft 建議您讓最大檔案大小介於 10 到 20 MB 之間。如果您很少上載檔案,則最大檔案大小可以為 100 MB。"

        一個企業內部的視訊網站,估且算它的日流量為1000人次,那麼按照微軟的建議,所上傳的檔案大小應儘量控制在20M以內,可是這樣的大小還是很容易造成伺服器的癱瘓,綜合考慮後,我把大小控制在6M以內(為什麼在這個範圍,後面會有提到,提早告訴大家,是為了讓文章能連貫一點)。大家一定會奇怪“一般一部視訊大小都至少有個100~200M,小於6M的不多吧?” 是的,這個問題就是我們要解決的關鍵。

        在解決這個問題前,大家必須先清楚一件事,我們這裡所說的檔案大小"6M","200M"指的是針對伺服器端而言呢,還是客戶端而言呢?正確的理解如下:200M是針對客戶端使用者而言的大小,一般情況下允許使用者上傳最大600M大小的檔案(這個600M是考慮到我伺服器的硬碟大小,大家可以靈活掌握,不過一般最好不要超過1G);6M則指的是伺服器端所能接收的檔案大小,這樣才能不讓伺服器的記憶體因為上傳檔案而被吞噬光。

        那麼,現在我們就可以把問題轉化為:如何讓伺服器以小於6M的大小來接收使用者上傳的200M視訊的?

        大家是不是看得有點暈,那我拿“奧運會門票出售的情況”來舉個例子。

        這幾天是出售奧運會門票的最後一個階段,為了能在最後一階段買到門票,很多人都提早好幾天等在售票視窗前。我們假設有10W人需要門票(就好像使用者上傳200M的視訊),理想的情況自然是開10W個視窗來出售門票(這裡的視窗相當於伺服器可以接收的檔案大小,而10W則相當於我們將maxRequestLength等相關元素設定很大)。可是想一想就知道,這樣做是不可能的(原因自己想吧~)。那怎麼解決的呢?只有將視窗數按照某種規則限制在一定數量(比如20個),然後想買票的人排隊買票。

        相信通過這個例子,有些朋友可能已經想到了如何解決我們之前的問題了。辦法就是在伺服器端通過某種方法將請求分組接收。

        這部分先寫到這了。

        [補充] 很多朋友提出類似:"Asp.Net 2.0以上版本好像已經不全部放入記憶體"的意見,首先我很感謝大家的支援,發現自己的確對於這些內容掌握的還不夠深入。在大家的提醒下,查閱了一些相關資料,所以再做一個補充,以免其他人和我犯一樣的錯誤。以下內容摘自:隨便說說:在ASP.NET應用程式中上傳檔案

   對於某些伺服器端的技術,例如Spring Framework,或者早期ASP.NET 1.1時,為了供程式處理,都會將使用者上傳的內容完全載入記憶體,這的確會帶來問題。但是其實協議本身並沒有規定伺服器端應該使用何種方式來處理上傳的檔案。例如在現在的ASP.NET 2.0中就已經會在使用者上傳資料超過一定數量之後將其存在硬碟中的臨時檔案中,而這點對於開發人員完全透明,也就是說,開發人員可以像以前一樣進行資料流的處理。

  ASP.NET 2.0啟用硬碟臨時檔案的閾值(threshold)是可配置的:

<system.web>
  <httpRuntime
    maxRequestLength="Int32"
    requestLengthDiskThreshold="Int32" />
system.web>

  maxRequestLength自不必說,剛接觸ASP.NET的朋友總會發現上傳檔案不能超過4M,這就是因為maxRequestLength的大小預設為4096,這就限制著每個請求的大小不得超過4096KB。這麼做的目的是為了保護應用程式不受惡意請求的危害。當請求超過maxRequestLength之後,ASP.NET處理程式將不會處理該請求。這裡和ASP.NET丟擲一個異常是不同的,這就是為什麼如果使用者上傳檔案太大,看到的並非是ASP.NET應用程式中指定的錯誤頁面(或者預設的),因為ASP.NET還沒有對這個請求進行處理。   
   requestLengthDiskThreshold就是剛才所提到的閾值,其預設值為256,即一個請求內容超過256KB時就會啟用硬碟作為快取。這個閾值理論上和客戶端是否是在上傳內容無關,只要客戶端發來的請求大於這個值即可。因此,在ASP.NET 2.0中伺服器的記憶體不會因為客戶端的異常請求而耗盡。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-605014/,如需轉載,請註明出處,否則將追究法律責任。

相關文章