大文件傳輸主要技術瓶頸都有哪些?如何處理的?

首先,這個http協議的限制與2GB文件大小是什麼關係?個人覺得這個2GB大小限制是java數組Integer.maxValue導致的 位元組流一次性傳輸的上限(多線程分割處理和斷點續傳除外...),那麼http本身的一次請求是否有最大值限制?也是2GB?那麼之前提到的100MB又是怎麼回事?(希望這個地方能講解的詳細一些~)
調用連接: 基於HTTP的海量大文件上傳 (avg &>=100MB) 服務會面臨哪些技術難題,如何解決? - Web 開發

Apera官網給出的提示:

假設帶寬足夠大,那麼這種問題的可能性是否會改善?需要使用什麼樣的技術才能彌補?(最好對原理和協議方面進行一些敘述...)
求大腿們指點~ (┬_┬)↘


HTTP 協議本身沒聽說過有這種限制,畢竟Request和Response的格式和限制都應該差不多,而通過HTTP下載個超過2G的文件很顯然是可以做到的。

但是HTTP伺服器一般都會限制請求大小,這個限制非常小(一般就2M-4M),因為這個限制放大很容易被發起攻擊直接拖死伺服器。尤其是直接對internet提供伺服器的伺服器這個限制甚至可能只有512KB甚至更小,大部分大型網站都是用專用的伺服器來處理大文件上傳,避免Web伺服器被拖死。


所以你第一張截圖的說法,至少說是不嚴謹的。

第二張圖說的事情是存在的,TCP是一種基於通用目的的流式傳輸協議,這使得它在設計的時候性能最大化並不是最優先考慮的。所以重新設計一個性能優先的傳輸協議的確可以獲得更好的性能。


TCP的這個缺陷與帶寬的關係不是特別大,因為帶寬只是你家門口的路的寬度,如果在家門口之外的路上堵車了,照樣會影響。


沒看見滿意的答案,我簡單寫下,拋磚引玉。

HTTP的限制是自身協議的限制。你下面那個TCP對文件大小沒有限制,但是速度WAN很慢,為什麼哪呢?

因為TCP有個確認機制,你確認了,我繼續發,你不確認我等超時重傳,這就麻煩了,在RTT很大的管道中,速度始終發不起來。

有興趣可以查查 長肥管道

這個確實需要改,最簡單得方法是,把大文件分塊,然後起多條TCP傳輸,或者乾脆使用UDP。


謝邀。

看了前面的回答,感覺還沒太說透,我來試著答一下。

這實際上是幾個不同層面的問題。

1.

一般的Web開發框架(比如Java的Struts2、SpringMVC,dotNet的WebForm和MVC,NodeJS的Express、Koa),在基於Web Server(比如Tomcat、IIS、Apache、Nginx)處理HTTP Request的時候,都傾向於採用類似流水線的請求處理機制(新式框架多叫Web處理中間件)。

HTTP Request從被接收開始,作為一個整體一層層穿過不同的Middleware進行處理,最終輸出HTTP Response就算處理完一個請求了。這樣的處理方式更高效,可配置、可擴展性也更強。

但是這樣就要求在流水線的最開始,就要完整地接收整個HTTP Request,並封裝為一個可解析的對象,依次往下級傳遞,這實際上就是要把HTTP Request放在內存裡面。

一般的頁面請求或Ajax請求還好,因為都是文本,再大也沒多大。許多Web Server的默認設置都是可以為一個請求最多分配20M的伺服器內存,一般情況下是足夠的,想想看一個20MB大小的txt文件得有多長?

2.

但是如果HTTP Request中不是正常文本,而是帶著上傳的文件,這個時候就尷尬了。

比如這種情況下我要上傳一個最大100M的文件。

一種簡單的方式是還用流水線處理的方式。需要把Web Server的配置從20M提高到100M,就能上傳成功了。但是問題是這時候網站只要有一個人在上傳100M的文件,就需要佔用伺服器100M的內存,如果有10個人同時上傳1個G的內存可就沒了。

如果你的網站需要上傳最大1G的文件呢?你還捨得你的內存嗎?而且如果把這個設置提高,網站的安全性可就不好說了,隨便製造幾個文件上傳的HTTP Request就分分鐘可以把你伺服器搞到內存100%,你還怎麼愉快地玩耍?

題主問題中提到的FileNet以Web Service的方式上傳一般不能超過100MB,估計就是屬於以上情況,默認配置是最大佔用100M內存,儘管理論上還可以往上配更大的,但是處於安全形度,人家直接告訴你不能再大了。

3.

另外一種方式,就是放棄流水線的處理方式,為文件上傳單獨設置一條VIP通道,特殊處理。獲取到HTTP Request Stream,以數據流的方式去處理,這樣就不需要等到整個請求都接收完成,而是接收一點就處理一點。

好處是終於不那麼費內存了,也不用改Web Server內存配置了,壞處是實現起來會麻煩些,一般的Web開發框架會留給你單獨開口子的方式,由你自己在底層自行處理HTTP Request的原始內容,包括通過流的方式獲取請求內容。

題主問題中提到的FileNet使用EJB(IIOP)的方式,本質上應該就是屬於這種情況,所以可以支持更大的文件。

至於為什麼採用這種方式依然還有2G大小的限制呢?真的是由於HTTP的限制嗎?這就引出了下一個問題。

4.

基礎知識:

我們在程序裡面使用的整形數字,一般是Int類型,這個類型一般指代Int32,也就是用4個位元組來表示一個整數。

而用4個位元組來記錄一個有符號的整數(可正可負),其最大值用16進位表示是 0x7FFFFFFF ,摺合成10進位是 2^{31}-1=2,147,483,647

 1GB=1024	imes1MB=2^{10}	imes1MB=2^{20}	imes1KB=2^{30}	imes1Byte

所以,Int32的最大值 =  2^{31}-1= (2^{30})	imes2-1 = 1GB	imes2 -1 = 2GB - 1

結論是,如果用4個位元組的有符號整型來表示文件的長度,最多能表示大約2GB,再長就可能使長度變成負數了……

所以你知道2GB這個Magic Number是怎麼來的了吧……

事實上,有相當多的系統在建設的時候都沒有考慮大文件的問題,都是使用Int32來表示文件長度。而只要在文件發送、接收、處理、分析、存儲的任意一個環節沒有處理好這個問題,甚至只是一個外部依賴庫的問題,都會導致整個軟體系統不支持2GB以上的文件。

另外,如果使用4個位元組來表示一個無符號的整數(只有正數),那麼其最大值加倍,也就是最多能表示4GB文件的長度。

所以,這裡分享一個小Tip,如果想驗證一個系統是否真的支持大文件,先拿一個2.5GB文件試試第一道坎,如果通過的話,再拿一個4.5G的文件試試第二道坎。

5.

那麼我們再來看看HTTP協議對請求大小有限制嗎?

目前廣泛使用HTTP協議1.1版本的標準定義在RFC2616中有完整表述。

14.13 Content-Length

The Content-Length entity-header field indicates the size of the
entity-body, in decimal number of OCTETs, sent to the recipient or,
in the case of the HEAD method, the size of the entity-body that
would have been sent had the request been a GET.

Content-Length = "Content-Length" ":" 1DIGIT

An example is

Content-Length: 3495

其中表示消息體長度的欄位 Content-Length 的類型規定為Decimal,同時也並沒有對這一欄位的長度進行邏輯上的限制。Decimal類型是用16個位元組表示有符號整數,它能表示的最大值我們就不用算了,大到沒朋友。

所以先賢們在制定HTTP協議標準的時候已經充分考慮這個問題了,把2GB大小限制的鍋推給HTTP協議,W3C組織表示這鍋我們不背。

6.

那麼IBM為什麼不能把FileNet的這個問題改一改,直接讓FileNet支持2GB以上的文件呢?

而是如題主所說,推薦用戶體外循環,集成FTP、QuickFile或者Aspera等第三方服務來解決2GB以上文件的上傳問題呢?這就又引出了另外一個問題。

很重要的一個因素是,如果支持了2GB以上的大文件上傳,還會引來更多的新問題。

想像一下,如果一個用戶使用FileNet正在上傳一個3GB的文件,好不容易到傳到99%的時候,一不小心手欠把網頁關了或者網路斷了,回過頭來發現沒有斷點續傳功能,還得從頭開始上傳,用戶會不會精神崩潰,會不會組織起來抗議?

所以,一旦支持了2G以上的大文件,是不是就應該得有斷點續傳?上傳這麼大的文件,如果傳到最後內容出錯怎麼辦?是不是至少還得有文件校驗啊?校驗如果不對的話要不要自動重傳啊?這麼大的文件要不要考慮分塊上傳?要不要考慮並發控制?如果傳的文件多了要不要考慮排隊?……想想都沒頭,唉……

如果這樣,實際上就是逼著IBM把FileNet這麼一個內容管理系統,活生生地做成一個傳輸管理系統

所以,即便如IBM這般擁有強大技術實力的廠家,也會理智地劃清界限,如果有大文件需求,寧可集成第三方服務,也不再造一遍鎚子。更何況推薦的QuickFile和Aspera都是IBM自家產品,何樂而不為呢?

7.

至於題主在問題中提到的Ftrans的CUTP超高速傳輸協議,以及Aspera對於TCP協議瓶頸的描述,這些是傳輸協議以及協議加速方面的問題,其實與本題「大文件傳輸技術瓶頸」的關聯性不大。

我只想說:實際上,無論是Ftrans還是Aspera,都是先解決了大文件傳輸場景下的眾多技術問題,然後再疊加上更高效的傳輸協議來提升傳輸效率;而不是試圖只是通過一種特殊的傳輸協議來解決大文件傳輸問題。

利益相關:http://Ftrans.cn CTO

————————華麗的廣告分割線——————————

Ftrans 飛馳傳輸 一直致力於解決企業級場景下的文件大數據高速傳輸的問題。

僅從內容的角度來說,文件大數據至少包括大文件和海量文件。我們一直專註於解決這些場景所帶來的新挑戰,甚至包括TB級巨型文件以及百萬級海量文件傳輸的極端場景。

我們非常歡迎與對此方面感興趣的同學進行技術交流。

另外,與本題中提到的場景類似,企業中很現有的業務系統(如ERP、內容管理系統、媒資管理系統等),在涉及到大文件傳輸的場景時,通過自身升級改造來支持的方式在很多情況下是得不償失的。Ftrans也支持作為第三方的傳輸服務,快速集成到企業現有系統當中,使得企業可以迅速具備完善的文件大數據傳輸能力。


再往下看看socket和TCP/IP就明白了,大文件傳輸本身並沒有什麼瓶頸,有錢就加帶寬,沒錢就把分包和校驗演算法再優化一下。
至於什麼"CUTP超高速傳輸協議",就是一個應用層協議,而TCP是傳輸層協議,兩個不同層面上的放到一起對比,這家公司也是挺拼的。


著作權歸作者所有。
商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
作者:Ivony
鏈接:大文件傳輸主要技術瓶頸都有哪些?如何處理的? - Ivony 的回答
來源:知乎

但是HTTP伺服器一般都會限制請求大小,這個限制非常小(一般就2M-4M),因為這個限制放大很容易被發起攻擊直接拖死伺服器。尤其是直接對internet提供伺服器的伺服器這個限制甚至可能只有512KB甚至更小,大部分大型網站都是用專用的伺服器來處理大文件上傳,避免Web伺服器被拖死。

不是太明白怎麼就能拖死伺服器。

我問問大家,你們處理一個 200G 大小的文件的時候,會把它一次性全部讀入內存么?再具體一點舉一個例子,一個 200G 大小的 XML 文件,您會用 XmlDocument 全裝進去處理么?

文件一般是流式處理的。您會讀一點處理一點。如果文件有個記錄結構,一般您一次讀入一個記錄就可以了。用個循環把全部記錄處理完。XML 文件如果是有個容器根節點,您每次只要足以讀入一個二級節點,放進 XmlDocument 處理就可以了。目的很簡單,就是用很小的內存把事情辦了。這在 Web Server 要處理很大數量的並發請求的時候尤其重要。

假設遇到了一種極端情況,非要把 200G 的文件上載完以後才能處理,或者說直接存儲起來吧,那讓接收請求的模塊一邊接收一邊寫入文件就可以。硬碟的容量和內存比起來,就不是一個數量級了,容納很多並發的請求都在上傳大文件也沒什麼好怕的。我是說,它不會拖死伺服器。如果硬碟空間快用光了,切斷通訊就是,也不至於會拖死伺服器。

=== 回答題主的問題 ===

HTTP 協議對於所謂大文件傳輸,超高速傳輸之類是沒有限制的。估計所指的限制是說 TCP/IP 協議層面的問題。

HTTP 協議裡面,通訊包頭欄位以後的 entity 數據區,是很乾凈的數據區,沒有什麼邊角的浪費。如果能保持可靠的連接,您無休止傳輸一個永不知道最終大小的內容都是可行的。

如果通訊條件惡劣,下載大文件可以利用斷點續傳機制。上傳大文件的「斷點續傳」印象里 HTTP 沒有這方面的支持,但具體 Web 應用可以自定義一些機制。

=== 由於評論區有字數限制,我放在這裡回復 ===

entity數據區是什麼樣子的?我舉個例子說 表單提交 可以設置為是否是二進位提交方式 如果表單包含了文件處理的話 那麼 這個entity數據區就是一個IO流 包括裡面的名值對也被二進位拿出來了 如果不包含文件的表單 直接get提交 也會放在entity區中嗎?還有這個entity區就是一樓答主所說的 web網路緩存區?

Form 提交可以是兩個方式,一個是 Get,表單數據放在 URL 參數裡面,也就是在 HTTP 通訊包的第一行發送出去;一個是 Post,表單數據放在 entity 裡面。由於擔心被攻擊,Web Server 一般都限定了 URL 行的最大尺寸,所以稍大一些的表單一般都是通過 Post 方式提交的。

如果需要「提交」二進位的內容,比如上傳一個很大的文件,那麼整個文件都是放在 entity 裡面就可以了。不過 HTTP 裡面提供了上傳文件的特定方式,RFC1867,樣子和一般 Form 提交有點類似,文件內容(和表單普通欄位內容一起)是用一種 multipart 方式打包的,我在網上隨便找了一段例子:
POST xxxx HTTP/1.1
Host: xxxx
Content-Length: 473
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryW49oa00LU29E4c5U
------WebKitFormBoundaryW49oa00LU29E4c5U
Content-Disposition: form-data; name="myText"

hello world
------WebKitFormBoundaryW49oa00LU29E4c5U
Content-Disposition: form-data; name="upload1"; filename="file1.txt"
Content-Type: text/plain

This is file1.
------WebKitFormBoundaryW49oa00LU29E4c5U
Content-Disposition: form-data; name="upload2"; filename="file2.txt"
Content-Type: text/plain

This is file2, it"s bigger.
------WebKitFormBoundaryW49oa00LU29E4c5U--

這個 multipart 方式大概是從 SMTP 協議裡面借鑒過來的。如果用這種方式上傳文件,那麼很多現有的 Web Server 都可以理解的,開發成本較低。Web 瀏覽器的 file upload 機制就是用的上述方式,開發起來直接用,很方便。

但這不是唯一的方式。前端可以和 Web Server 或者其下具體的 Web 應用約定好,HTTP 請求裡面的 entity 具體採用什麼打包方式。比如前端是一個專用 App,不是瀏覽器。

===

您所提到的網路緩存區是個什麼概念我還不太清楚。

我聯想到 http://ASP.NET 如果 Server 響應請求,要往 Response 裡面寫入 entity 部分,如果 Server 不暫時緩衝的話,也就是說真的立即寫出的話,你會發現一旦寫出以後,你再修改 header 就會拋出異常。這個道理很簡單,因為 headers 是先寫出去的(為了後面順次寫出 entity),只要你發出了你就無法後悔了,不可能搶過去修改已經發送給前端的部分內容。所以,http://ASP.NET 在特定狀態下是在內存緩存了這些 entity 內容,以便你後來可以修改 headers,然後它擇機全部寫出去。當然這時候就有個緩衝區最大尺寸了,比如 8M,記得是配置在 web.config 裡面的(或者更全局的什麼 .config 裡面的)。如果 entity 寫入 response 的時候強行隨時 Flush(),等於取消了這種緩存,就沒有什麼限制了,愛發出多大內容就可以。

這些其實都是 Web Server 和 Web 應用的一些具體實現策略和特點了,可能有些具體的技術難處,但不是 HTTP 層面的問題。

上傳的時候不清楚。沒深究過。也許和上述下載過程一樣,有些什麼具體技術方面的考量?只是一些聯想。我想只要具體框架允許程序拿到一個 Stream 對象加以操作就可以了,它就是上傳的東西。


我長期工作在內容管理系統,文件傳輸系統。在我看來,瓶頸應該是網路質量(不僅僅是帶寬,ISP也是很重要一方面)和距離。

距離:
我司北歐和美東的分公司離中國是在太遠了,什麼樣網路都很慢,舉個例子,大量文件拷貝網路傳輸還不如直接複製到硬碟上然後出差帶回來快。

網路質量:
部分客戶網路真的不行,ISP太差。我這使用aspera丟包率還在90%以上,客戶不同樓層,不同辦公室網路都不一樣。

我在文件傳輸推廣了一年多的aspera,大部分客戶使用反饋都良好。但客戶不願意安裝aspera,現在aspera的使用比較還是不到一半。我們現在在http上傳採用HTML5 分塊上傳,傳輸失敗就一直重試直到成功。我的客戶其實對速度不感冒,就圖省事和穩。


推薦閱讀:

HTTPS除了使用CA機構頒發的數字證書外,有沒有使用數字簽名技術驗證內容的完整性?
如何去分析開源的代碼,例如tomcat?
RPC框架和簡單的request - reponse的web框架有什麼區別?
JVM 常量池中存儲的是對象還是引用呢?
jvm內存回收詭異現象,求解?

TAG:Java | 計算機網路 | TCP | 大文件傳輸 |