往期文章
1、拜託!面試請不要再問我Spring Cloud底層原理
2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?
3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰
4、微服務架構如何保障雙11狂歡下的99.99%高可用
5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理
6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問
7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍
歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)
週一至五早8點半!精品技術文章準時送上!
目錄
一、寫在前面
二、原始的檔案上傳方案
三、大規模分散式系統對大檔案上傳的效能優化
(1)Chunk緩衝機制
(2)Packet資料包機制
(3)記憶體佇列非同步傳送機制
四、總結
一、寫在前面
上一篇文章,我們聊了一下Hadoop中的NameNode裡的edits log寫機制。
主要分析了edits log寫入磁碟和網路的時候,是如何通過分段加鎖以及雙緩衝的機制,大幅度提升了多執行緒併發寫edits log的吞吐量,從而支援高併發的訪問。
如果沒看那篇文章的同學,可以回看一下:大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問。
這篇文章,我們來看看,Hadoop的HDFS分散式檔案系統的檔案上傳的效能優化。
首先,我們還是通過一張圖來回顧一下檔案上傳的大概的原理。
由上圖所示,檔案上傳的原理,其實說出來也簡單。
比如有個TB級的大檔案,太大了,HDFS客戶端會給拆成很多block,一個block就是128MB。
這個HDFS客戶端你可以理解為是雲盤系統、日誌採集系統之類的東西。
比如有人上傳一個1TB的大檔案到網盤,或者是上傳個1TB的大日誌檔案。
然後,HDFS客戶端把一個一個的block上傳到第一個DataNode
第一個DataNode會把這個block複製一份,做一個副本傳送給第二個DataNode。
第二個DataNode傳送一個block副本到第三個DataNode。
所以你會發現,一個block有3個副本,分佈在三臺機器上。任何一臺機器當機,資料是不會丟失的。
最後,一個TB級大檔案就被拆散成了N多個MB級的小檔案存放在很多臺機器上了,這不就是分散式儲存麼?
二、原始的檔案上傳方案
今天要討論的問題,就是那個HDFS客戶端上傳TB級大檔案的時候,到底是怎麼上傳呢?
我們先來考慮一下,如果用一個比較原始的方式來上傳,應該怎麼做?
大概能想到的是下面這個圖裡的樣子。
很多java的初學者,估計都知道這樣來上傳檔案,其實無非就是不停的從本地磁碟檔案用輸入流讀取資料,讀到一點,就立馬通過網路的輸出流寫到DataNode裡去。
上面這種流程圖的程式碼,估計剛畢業的同學都可以立馬寫出來。因為對檔案的輸入流最多就是個FileInputStream。
而對DataNode的輸出流,最多就是個Socket返回的OutputStream。
然後中間找一個小的記憶體byte[]陣列,進行流對拷就行了,從本地檔案讀一點資料,就給DataNode發一點資料。
但是如果你要這麼弄,那效能真是極其的低下了,網路通訊講究的是適當頻率,每次batch批量傳送,你得讀一大批資料,通過網路通訊發一批資料。
不能說讀一點點資料,就立馬來一次網路通訊,就發出去這一點點的資料。
如果按照上面這種原始的方式,絕對會導致網路通訊效率極其低下,大檔案上傳效能很差。
為什麼這麼說呢?
相當於你可能剛讀出來幾百個位元組的資料,立馬就寫網路,卡頓個比如幾百毫秒。
然後再讀下一批幾百個位元組的資料,再寫網路卡頓個幾百毫秒,這個效能很差,在工業級的大規模分散式系統中,是無法容忍的。
三、分散式系統對大檔案上傳的效能優化
好,看完了原始的檔案上傳,那麼我們來看看,Hadoop中的大檔案上傳是如何優化效能的呢?一起來看看下面那張圖。
首先你需要自己建立一個針對本地TB級磁碟檔案的輸入流。
然後讀到資料之後立馬寫入HDFS提供的FSDataOutputStream輸出流。
這個FSDataOutputStream輸出流在幹啥?
大家覺得他會天真的立馬把資料通過網路傳輸寫給DataNode嗎?
答案當然是否定的了!這麼幹的話,不就跟之前的那種方式一樣了!
1. Chunk緩衝機制
首先,資料會被寫入一個chunk緩衝陣列,這個chunk是一個512位元組大小的資料片段,你可以這麼來理解。
然後這個緩衝陣列可以容納多個chunk大小的資料在裡面緩衝。
光是這個緩衝,首先就可以讓客戶端快速的寫入資料了,不至於說幾百位元組就要進行一次網路傳輸,想一想,是不是這樣?
2. Packet資料包機制
接著,當chunk緩衝陣列都寫滿了之後,就會把這個chunk緩衝陣列進行一下chunk切割,切割為一個一個的chunk,一個chunk是一個資料片段。
然後多個chunk會直接一次性寫入另外一個記憶體緩衝資料結構,就是Packet資料包。
一個Packet資料包,設計為可以容納127個chunk,大小大致為64mb。所以說大量的chunk會不斷的寫入Packet資料包的記憶體緩衝中。
通過這個Packet資料包機制的設計,又可以在記憶體中容納大量的資料,進一步避免了頻繁的網路傳輸影響效能。
3. 記憶體佇列非同步傳送機制
當一個Packet被塞滿了chunk之後,就會將這個Packet放入一個記憶體佇列來進行排隊。
然後有一個DataStreamer執行緒會不斷的獲取佇列中的Packet資料包,通過網路傳輸直接寫一個Packet資料包給DataNode。
如果一個Block預設是128mb的話,那麼一個Block預設會對應兩個Packet資料包,每個Packet資料包是64MB。
也就是說,傳送兩個Packet資料包給DataNode之後,就會發一個通知說,一個Block的資料都傳輸完畢。
這樣DataNode就知道自己收到一個Block了,裡面包含了人家傳送過來的兩個Packet資料包。
四、總結
OK,大家看完了上面的那個圖以及Hadoop採取的大檔案上傳機制,是不是感覺設計的很巧妙?
說白了,工業級的大規模分散式系統,都不會採取特別簡單的程式碼和模式,那樣效能很低下。
這裡都有大量的併發優化、網路IO優化、記憶體優化、磁碟讀寫優化的架構設計、生產方案在裡面。
所以大家觀察上面那個圖,HDFS客戶端可以快速的將tb級大檔案的資料讀出來,然後快速的交給HDFS的輸出流寫入記憶體。
基於記憶體裡的chunk緩衝機制、packet資料包機制、記憶體佇列非同步傳送機制。絕對不會有任何網路傳輸的卡頓,導致大檔案的上傳速度變慢。
反而通過上述幾種機制,可以上百倍的提升一個TB級大檔案的上傳效能。
如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!
一大波微服務、分散式、高併發、高可用的原創系列
文章正在路上,歡迎掃描下方二維碼,持續關注:
石杉的架構筆記(id:shishan100)
十餘年BAT架構經驗傾囊相授