1. 程式人生 > >有必要了解的大資料知識(一) Hadoop

有必要了解的大資料知識(一) Hadoop

#前言 之前工作中,有接觸到大資料的需求,雖然當時我們體系有專門的大資料部門,但是由於當時我們中臺重構,整個體系的開發量巨大,共用一個大資料部門,人手已經忙不過來,沒法辦,為了趕時間,我自己負責的系統的大資料相關操作,由我們自己承擔了。此前對大資料的知識瞭解的很少,於是晚上回去花時間突擊大資料知識,白天就開始上手幹,一邊學一邊做,總算在部門規定的時間,跟系統一起上線了。後來的維護迭代就交給大資料去了,雖然接觸大資料的時間不長,但是對我來說,確是很有意思的一段經歷,覺得把當時匆匆學的知識點,再仔細回顧回顧,整理下。 #大資料概述 ​ 大資料: 就是對海量資料進行分析處理,得到一些有價值的資訊,然後幫助企業做出判斷和決策. ​ 處理流程: ​ 1:獲取資料 ​ 2:處理資料 ​ 3:展示結果 #Hadoop介紹 Hadoop是一個分散式系基礎框架,它允許使用簡單的程式設計模型跨大型計算機的大型資料集進行分散式處理.它主要解決兩個問題 ​ **大資料儲存問題**: HDFS ​ **大資料計算問題**:MapReduce ##問題一: 大檔案怎麼儲存? > 假設一個檔案非常非常大,大小為1PB/a.txt, 大到世界上所有的高階計算機都儲存不下, 怎麼辦? - 為了儲存大檔案, 需要把檔案放在多個機器上 - 檔案要分塊 block(128M) - 不同的塊放在不同的 `HDFS` 節點 - 同時為了對外提供統一的訪問, 讓外部可以像是訪問本機一樣訪問分散式檔案系統 - 有一個統一的 `HDFS Master` - 它儲存整個系統的檔案資訊 - 所有的檔案元資料的修改都從 `Master` 開始 ##問題二: 大資料怎麼計算? > 從一個網路日誌檔案中計算獨立 IP, 以及其出現的次數 > 如果資料量特別大,我們可以將,整個任務拆開, 劃分為比較小的任務, 從而進行計算呢。 ##問題三: 如何將這些計算任務跑在叢集中? > 如果能夠在不同的節點上並行執行, 更有更大的提升, 如何把這些任務跑在叢集中? * 可以設定一個叢集的管理者, 這個地方叫做 `Yarn` * 這個叢集管理者有一個 `Master`, 用於接收和分配任務 * 這個叢集管理者有多個 `Slave`, 用於執行任務 ##Hadoop 的組成 - **Hadoop分散式檔案系統(HDFS)** 提供對應用程式資料的高吞吐量訪問的分散式檔案系統 * **Hadoop Common** 其他Hadoop模組所需的Java庫和實用程式。這些庫提供檔案系統和作業系統級抽象,幷包含啟動Hadoop所需的必要Java檔案和指令碼 * **Hadoop MapReduce** 基於YARN的大型資料集並行處理系統 * **Hadoop YARN** 作業排程和叢集資源管理的框架 ## Hadoop前生今世 1. Hadoop最早起源於**Nutch**。Nutch的設計目標是構建一個大型的全網搜尋引擎,包括網頁抓取、索引、查詢等功能,但隨著抓取網頁數量的增加,遇到了嚴重的可擴充套件性問題——如何解決數十億網頁的儲存和索引問題。 2. 2003年、2004年穀歌發表的兩篇論文為該問題提供了可行的解決方案。 ——分散式檔案系統(GFS),可用於處理海量網頁的**儲存** ——分散式計算框架MAPREDUCE,可用於處理海量網頁的**索引計算**問題。 3. Nutch的開發人員完成了相應的開源實現**HDFS**和**MAPREDUCE**,並從Nutch中剝離成為獨立專案HADOOP,到2008年1月,HADOOP成為Apache頂級專案. **狹義上來說,hadoop就是單獨指代hadoop這個軟體,** HDFS :分散式檔案系統 MapReduce : 分散式計算系統 **廣義上來說,hadoop指代大資料的一個生態圈,包括很多其他的軟體** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113455788-411343913.jpg) ##hadoop的架構模型 **1.x的版本架構模型介紹** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113501437-1613542301.jpg) 檔案系統核心模組: NameNode:叢集當中的主節點,管理元資料(檔案的大小,檔案的位置,檔案的許可權),主要用於管理叢集當中的各種資料 secondaryNameNode:主要能用於hadoop當中元資料資訊的輔助管理 DataNode:叢集當中的從節點,主要用於儲存叢集當中的各種資料 資料計算核心模組: JobTracker:接收使用者的計算請求任務,並分配任務給從節點 TaskTracker:負責執行主節點JobTracker分配的任務 **2.x的版本架構模型介紹** **第一種:NameNode與ResourceManager單節點架構模型** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113507622-1981201384.jpg) 檔案系統核心模組: NameNode:叢集當中的主節點,主要用於管理叢集當中的各種資料 secondaryNameNode:主要能用於hadoop當中元資料資訊的輔助管理 DataNode:叢集當中的從節點,主要用於儲存叢集當中的各種資料 資料計算核心模組: ResourceManager:接收使用者的計算請求任務,並負責叢集的資源分配 NodeManager:負責執行主節點APPmaster分配的任務 **第二種:NameNode單節點與ResourceManager高可用架構模型** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113513735-1686921655.jpg) 檔案系統核心模組: NameNode:叢集當中的主節點,主要用於管理叢集當中的各種資料 secondaryNameNode:主要能用於hadoop當中元資料資訊的輔助管理 DataNode:叢集當中的從節點,主要用於儲存叢集當中的各種資料 資料計算核心模組: ResourceManager:接收使用者的計算請求任務,並負責叢集的資源分配,以及計算任務的劃分,通過zookeeper實現ResourceManager的高可用 NodeManager:負責執行主節點ResourceManager分配的任務 **第三種:NameNode高可用與ResourceManager單節點架構模型** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113540083-1933747310.jpg) 檔案系統核心模組: NameNode:叢集當中的主節點,主要用於管理叢集當中的各種資料,其中nameNode可以有兩個,形成高可用狀態 DataNode:叢集當中的從節點,主要用於儲存叢集當中的各種資料 JournalNode:檔案系統元資料資訊管理 資料計算核心模組: ResourceManager:接收使用者的計算請求任務,並負責叢集的資源分配,以及計算任務的劃分 NodeManager:負責執行主節點ResourceManager分配的任務 **第四種:NameNode與ResourceManager高可用架構模型** ![](https://img2020.cnblogs.com/blog/874710/202103/874710-20210316113548410-2063979202.jpg) 檔案系統核心模組: NameNode:叢集當中的主節點,主要用於管理叢集當中的各種資料,一般都是使用兩個,實現HA高可用 JournalNode:元資料資訊管理程序,一般都是奇數個 DataNode:從節點,用於資料的儲存 資料計算核心模組: ResourceManager:Yarn平臺的主節點,主要用於接收各種任務,通過兩個,構建成高可用 NodeManager:Yarn平臺的從節點,主要用於處理ResourceManager分配的任務 # Hadoop 核心介紹 ## 1. HDFS HDFS(Hadoop Distributed File System) 是一個 Apache Software Foundation 專案, 是 Apache Hadoop 專案的一個子專案. Hadoop 非常適於儲存大型資料 (比如 TB 和 PB), 其就是使用 HDFS 作為儲存系統. HDFS 使用多臺計算機儲存檔案, 並且提供統一的訪問介面, 像是訪問一個普通檔案系統一樣使用分散式檔案系統. HDFS 對資料檔案的訪問通過流的方式進行處理, 這意味著通過命令和 MapReduce 程式的方式可以直接使用 HDFS. HDFS 是容錯的, 且提供對大資料集的高吞吐量訪問. HDFS 的一個非常重要的特點就是**一次寫入、多次讀取**, 該模型降低了對併發控制的要求, 簡化了資料聚合性, 支援高吞吐量訪問. 而吞吐量是大資料系統的一個非常重要的指標, 吞吐量高意味著能處理的資料量就大. ### 1.1. 設計目標 - 通過跨多個廉價計算機叢集分佈資料和處理來節約成本 - 通過自動維護多個數據副本和在故障發生時來實現可靠性 - 它們為儲存和處理超大規模資料提供所需的擴充套件能力。 ### 1.2. HDFS 的歷史 1. Doug Cutting 在做 Lucene 的時候, 需要編寫一個爬蟲服務, 這個爬蟲寫的並不順利, 遇到了一些問題, 諸如: 如何儲存大規模的資料, 如何保證叢集的可伸縮性, 如何動態容錯等 2. 2013年的時候, Google 釋出了三篇論文, 被稱作為三駕馬車, 其中有一篇叫做 GFS, 是描述了 Google 內部的一個叫做 GFS 的分散式大規模檔案系統, 具有強大的可伸縮性和容錯性 3. Doug Cutting 後來根據 GFS 的論文, 創造了一個新的檔案系統, 叫做 HDFS ### 1.3. HDFS 的架構 1. NameNode 是一箇中心伺服器, 單一節點(簡化系統的設計和實現), 負責管理檔案系統的名字空間(NameSpace)以及客戶端對檔案的訪問 2. 檔案操作, NameNode 是負責檔案元資料的操作, DataNode 負責處理檔案內容的讀寫請求, 跟檔案內容相關的資料流不經過 NameNode, 只詢問它跟哪個 DataNode聯絡, 否則 NameNode 會成為系統的瓶頸 3. 副本存放在哪些 DataNode 上由 NameNode 來控制, 根據全域性情況作出塊放置決定, 讀取檔案時 NameNode 儘量讓使用者先讀取最近的副本, 降低讀取網路開銷和讀取延時 4. NameNode 全權管理資料庫的複製, 它週期性的從叢集中的每個DataNode 接收心跳信合和狀態報告, 接收到心跳訊號意味著 DataNode 節點工作正常, 塊狀態報告包含了一個該 DataNode 上所有的資料列表 | NameNode | DataNode | | :----------------------------------- | :----------------------------------------- | | 儲存元資料 | 儲存檔案內容 | | 元資料儲存在記憶體中 | 檔案內容儲存在磁碟 | | 儲存檔案, block, DataNode 之間的關係 | 維護了 block id 到 DataNode 檔案之間的關係 | ### 1.4. HDFS 檔案副本和 Block 塊儲存 所有的檔案都是以 block 塊的方式存放在 HDFS 檔案系統當中, 在 Hadoop1 當中, 檔案的 block 塊預設大小是64M, hadoop2 當中, 檔案的 block 塊大小預設是 128M, block 塊的大小可以通過 hdfs-site.xml 當中的配置檔案進行指定 ``` dfs.block.size
塊大小 以位元組為單位
``` #### 1.4.1. 引入塊機制的好處 1. 一個檔案有可能大於叢集中任意一個磁碟 2. 使用塊抽象而不是檔案可以簡化儲存子系統 3. 塊非常適合用於資料備份進而提供資料容錯能力和可用性 #### 1.4.2. 塊快取 通常 DataNode 從磁碟中讀取塊, 但對於訪問頻繁的檔案, 其對應的塊可能被顯式的快取在 DataNode 的記憶體中, 以堆外塊快取的形式存在. 預設情況下,一個塊僅快取在一個 DataNode 的記憶體中,當然可以針對每個檔案配置 DataNode 的數量. 作業排程器通過在快取塊的 DataNode 上執行任務, 可以利用塊快取的優勢提高讀操作的效能. 例如: 連線(join) 操作中使用的一個小的查詢表就是塊快取的一個很好的候選 使用者或應用通過在快取池中增加一個 Cache Directive 來告訴 NameNode 需要快取哪些檔案及存多久. 快取池(Cache Pool) 是一個擁有管理快取許可權和資源使用的管理性分組. 例如一個檔案 130M, 會被切分成 2 個 block 塊, 儲存在兩個 block 塊裡面, 實際佔用磁碟 130M 空間, 而不是佔用256M的磁碟空間 #### 1.4.3. HDFS 檔案許可權驗證 HDFS 的檔案許可權機制與 Linux 系統的檔案許可權機制類似 ``` r:read w:write x:execute ``` 許可權 `x` 對於檔案表示忽略, 對於資料夾表示是否有許可權訪問其內容 如果 Linux 系統使用者 zhangsan 使用 Hadoop 命令建立一個檔案, 那麼這個檔案在 HDFS 當中的 Owner 就是 zhangsan HDFS 檔案許可權的目的, 防止好人做錯事, 而不是阻止壞人做壞事. HDFS相信你告訴我你是誰, 你就是誰 ### 1.5. HDFS 的元資訊和 SecondaryNameNode 當 Hadoop 的叢集當中, 只有一個 NameNode 的時候, 所有的元資料資訊都儲存在了 FsImage 與 Eidts 檔案當中, 這兩個檔案就記錄了所有的資料的元資料資訊, 元資料資訊的儲存目錄配置在了 `hdfs-site.xml` 當中 ``` dfs.namenode.name.dir
file:///export/servers/hadoop-3.1.1/datas/namenode/namenodedatas
dfs.namenode.edits.dir file:///export/servers/hadoop-3.1.1/datas/dfs/nn/edits ``` #### 1.5.1. FsImage 和 Edits 詳解 - `edits` - `edits` 存放了客戶端最近一段時間的操作日誌 - 客戶端對 HDFS 進行寫檔案時會首先被記錄在 `edits` 檔案中 - `edits` 修改時元資料也會更新 - 每次 HDFS 更新時 `edits` 先更新後客戶端才會看到最新資訊 - `fsimage` - NameNode 中關於元資料的映象, 一般稱為檢查點, `fsimage` 存放了一份比較完整的元資料資訊 - 因為 `fsimage` 是 NameNode 的完整的映象, 如果每次都載入到記憶體生成樹狀拓撲結構,這是非常耗記憶體和CPU, 所以一般開始時對 NameNode 的操作都放在 edits 中 - `fsimage` 內容包含了 NameNode 管理下的所有 DataNode 檔案及檔案 block 及 block 所在的 DataNode 的元資料資訊. - 隨著 `edits` 內容增大, 就需要在一定時間點和 `fsimage` 合併 #### 1.5.2. fsimage 中的檔案資訊檢視 [官方檢視文件](http://hadoop.apache.org/docs/r3.1.1/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html) 使用命令 `hdfs oiv` ``` cd /export/servers/hadoop-3.1.1/datas/namenode/namenodedatas hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml ``` #### 1.5.3. edits 中的檔案資訊檢視 [官方檢視文件](http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.14.0/hadoop-project-dist/hadoop-hdfs/HdfsEditsViewer.html) 使用命令 `hdfs oev` ``` cd /export/servers/hadoop-3.1.1/datas/dfs/nn/edits hdfs oev -i edits_0000000000000000865-0000000000000000866 -o myedit.xml -p XML ``` #### 1.5.4. SecondaryNameNode 如何輔助管理 fsimage 與 edits 檔案? - SecondaryNameNode 定期合併 fsimage 和 edits, 把 edits 控制在一個範圍內 - 配置 SecondaryNameNode - SecondaryNameNode 在 `conf/masters` 中指定 - 在 masters 指定的機器上, 修改 `hdfs-site.xml` ``` dfs.http.address
host:50070
``` - 修改 `core-site.xml`, 這一步不做配置保持預設也可以 ``` fs.checkpoint.period 3600 ``` ``` fs.checkpoint.size 67108864 ``` 1. SecondaryNameNode 通知 NameNode 切換 editlog 2. SecondaryNameNode 從 NameNode 中獲得 fsimage 和 editlog(通過http方式) 3. SecondaryNameNode 將 fsimage 載入記憶體, 然後開始合併 editlog, 合併之後成為新的 fsimage 4. SecondaryNameNode 將新的 fsimage 發回給 NameNode 5. NameNode 用新的 fsimage 替換舊的 fsimage ##### 特點 - 完成合並的是 SecondaryNameNode, 會請求 NameNode 停止使用 edits, 暫時將新寫操作放入一個新的檔案中 `edits.new` - SecondaryNameNode 從 NameNode 中通過 Http GET 獲得 edits, 因為要和 fsimage 合併, 所以也是通過 Http Get 的方式把 fsimage 載入到記憶體, 然後逐一執行具體對檔案系統的操作, 與 fsimage 合併, 生成新的 fsimage, 然後通過 Http POST 的方式把 fsimage 傳送給 NameNode. NameNode 從 SecondaryNameNode 獲得了 fsimage 後會把原有的 fsimage 替換為新的 fsimage, 把 edits.new 變成 edits. 同時會更新 fstime - Hadoop 進入安全模式時需要管理員使用 dfsadmin 的 save namespace 來建立新的檢查點 - SecondaryNameNode 在合併 edits 和 fsimage 時需要消耗的記憶體和 NameNode 差不多, 所以一般把 NameNode 和 SecondaryNameNode 放在不同的機器上 ### 1.6 HDFS 檔案寫入過程 1. Client 發起檔案上傳請求, 通過 RPC 與 NameNode 建立通訊, NameNode 檢查目標檔案是否已存在, 父目錄是否存在, 返回是否可以上傳 2. Client 請求第一個 block 該傳輸到哪些 DataNode 伺服器上 3. NameNode 根據配置檔案中指定的備份數量及機架感知原理進行檔案分配, 返回可用的 DataNode 的地址如: A, B, C - Hadoop 在設計時考慮到資料的安全與高效, 資料檔案預設在 HDFS 上存放三份, 儲存策略為本地一份, 同機架內其它某一節點上一份, 不同機架的某一節點上一份。 4. Client 請求 3 臺 DataNode 中的一臺 A 上傳資料(本質上是一個 RPC 呼叫,建立 pipeline ), A 收到請求會繼續呼叫 B, 然後 B 呼叫 C, 將整個 pipeline 建立完成, 後逐級返回 client 5. Client 開始往 A 上傳第一個 block(先從磁碟讀取資料放到一個本地記憶體快取), 以 packet 為單位(預設64K), A 收到一個 packet 就會傳給 B, B 傳給 C. A 每傳一個 packet 會放入一個應答佇列等待應答 6. 資料被分割成一個個 packet 資料包在 pipeline 上依次傳輸, 在 pipeline 反方向上, 逐個傳送 ack(命令正確應答), 最終由 pipeline 中第一個 DataNode 節點 A 將 pipelineack 傳送給 Client 7. 當一個 block 傳輸完成之後, Client 再次請求 NameNode 上傳第二個 block 到服務 1 ### 1.7. HDFS 檔案讀取過程 1. Client向NameNode發起RPC請求,來確定請求檔案block所在的位置; 2. NameNode會視情況返回檔案的部分或者全部block列表,對於每個block,NameNode 都會返回含有該 block 副本的 DataNode 地址; 這些返回的 DN 地址,會按照叢集拓撲結構得出 DataNode 與客戶端的距離,然後進行排序,排序兩個規則:網路拓撲結構中距離 Client 近的排靠前;心跳機制中超時彙報的 DN 狀態為 STALE,這樣的排靠後; 3. Client 選取排序靠前的 DataNode 來讀取 block,如果客戶端本身就是DataNode,那麼將從本地直接獲取資料(短路讀取特性); 4. 底層上本質是建立 Socket Stream(FSDataInputStream),重複的呼叫父類 DataInputStream 的 read 方法,直到這個塊上的資料讀取完畢; 5. 當讀完列表的 block 後,若檔案讀取還沒有結束,客戶端會繼續向NameNode 獲取下一批的 block 列表; 6. 讀取完一個 block 都會進行 checksum 驗證,如果讀取 DataNode 時出現錯誤,客戶端會通知 NameNode,然後再從下一個擁有該 block 副本的DataNode 繼續讀。 7. read 方法是並行的讀取 block 資訊,不是一塊一塊的讀取;NameNode 只是返回Client請求包含塊的DataNode地址,並不是返回請求塊的資料; 8. 最終讀取來所有的 block 會合併成一個完整的最終檔案。 ### 1.9. HDFS 的 API 操作 #### 1.9.1. 匯入 Maven 依賴 ``` cloudera https://repository.cloudera.com/artifactory/cloudera-repos/ jdk.tools jdk.tools 1.8 system ${JAVA_HOME}/lib/tools.jar org.apache.hadoop hadoop-common 3.0.0 provided org.apache.hadoop hadoop-hdfs 3.0.0 org.apache.hadoop hadoop-hdfs-client 3.0.0 provided org.apache.hadoop hadoop-client 3.0.0 junit junit 4.12 test ``` #### 1.9.2. 概述 在 Java 中操作 HDFS, 主要涉及以下 Class: - `Configuration` - 該類的物件封轉了客戶端或者伺服器的配置 - `FileSystem` - 該類的物件是一個檔案系統物件, 可以用該物件的一些方法來對檔案進行操作, 通過 FileSystem 的靜態方法 get 獲得該物件 ``` FileSystem fs = FileSystem.get(conf) ``` - `get` 方法從 `conf` 中的一個引數 `fs.defaultFS` 的配置值判斷具體是什麼型別的檔案系統 - 如果我們的程式碼中沒有指定 `fs.defaultFS`, 並且工程 ClassPath 下也沒有給定相應的配置, `conf` 中的預設值就來自於 Hadoop 的 Jar 包中的 `core-default.xml` - 預設值為 `file:///`, 則獲取的不是一個 DistributedFileSystem 的例項, 而是一個本地檔案系統的客戶端物件 #### 1.9.3. 獲取 FileSystem 的幾種方式 - 第一種方式 ``` @Test public void getFileSystem() throws URISyntaxException, IOException { Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), configuration); System.out.println(fileSystem.toString()); } ``` - 第二種方式 ``` @Test public void getFileSystem2() throws URISyntaxException, IOException { Configuration configuration = new Configuration(); configuration.set("fs.defaultFS","hdfs://192.168.52.250:8020"); FileSystem fileSystem = FileSystem.get(new URI("/"), configuration); System.out.println(fileSystem.toString()); } ``` - 第三種方式 ``` @Test public void getFileSystem3() throws URISyntaxException, IOException { Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://192.168.52.250:8020"), configuration); System.out.println(fileSystem.toString()); } ``` - 第四種方式 ``` @Test public void getFileSystem4() throws Exception{ Configuration configuration = new Configuration(); configuration.set("fs.defaultFS","hdfs://192.168.52.250:8020"); FileSystem fileSystem = FileSystem.newInstance(configuration); System.out.println(fileSystem.toString()); } ``` #### 1.9.4. 遍歷 HDFS 中所有檔案 - 遞迴遍歷 ``` @Test public void listFile() throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.100:8020"), new Configuration()); FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/")); for (FileStatus fileStatus : fileStatuses) { if(fileStatus.isDirectory()){ Path path = fileStatus.getPath(); listAllFiles(fileSystem,path); }else{ System.out.println("檔案路徑為"+fileStatus.getPath().toString()); } } } public void listAllFiles(FileSystem fileSystem,Path path) throws Exception{ FileStatus[] fileStatuses = fileSystem.listStatus(path); for (FileStatus fileStatus : fileStatuses) { if(fileStatus.isDirectory()){ listAllFiles(fileSystem,fileStatus.getPath()); }else{ Path path1 = fileStatus.getPath(); System.out.println("檔案路徑為"+path1); } } } ``` - 使用 API 遍歷 ``` @Test public void listMyFiles()throws Exception{ //獲取fileSystem類 FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration()); //獲取RemoteIterator 得到所有的檔案或者資料夾,第一個引數指定遍歷的路徑,第二個引數表示是否要遞迴遍歷 RemoteIterator locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true); while (locatedFileStatusRemoteIterator.hasNext()){ LocatedFileStatus next = locatedFileStatusRemoteIterator.next(); System.out.println(next.getPath().toString()); } fileSystem.close(); } ``` #### 1.9.5. 下載檔案到本地 ``` @Test public void getFileToLocal()throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration()); FSDataInputStream open = fileSystem.open(new Path("/test/input/install.log")); FileOutputStream fileOutputStream = new FileOutputStream(new File("c:\\install.log")); IOUtils.copy(open,fileOutputStream ); IOUtils.closeQuietly(open); IOUtils.closeQuietly(fileOutputStream); fileSystem.close(); } ``` #### 1.9.6. HDFS 上建立資料夾 ``` @Test public void mkdirs() throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration()); boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test")); fileSystem.close(); } ``` #### 1.9.7. HDFS 檔案上傳 ``` @Test public void putData() throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration()); fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test")); fileSystem.close(); } ``` #### 1.9.8. 偽造使用者 1. 停止hdfs叢集,在node01機器上執行以下命令 ``` cd /export/servers/hadoop-3.1.1 sbin/stop-dfs.sh ``` 1. 修改node01機器上的hdfs-site.xml當中的配置檔案 ``` cd /export/servers/hadoop-3.1.1/etc/hadoop vim hdfs-site.xml dfs.permissions.enabled true ``` 1. 修改完成之後配置檔案傳送到其他機器上面去 ``` scp hdfs-site.xml node02:$PWD scp hdfs-site.xml node03:$PWD ``` 1. 重啟hdfs叢集 ``` cd /export/servers/hadoop-3.1.1 sbin/start-dfs.sh ``` 1. 隨意上傳一些檔案到我們hadoop叢集當中準備測試使用 ``` cd /export/servers/hadoop-3.1.1/etc/hadoop hdfs dfs -mkdir /config hdfs dfs -put *.xml /config hdfs dfs -chmod 600 /config/core-site.xml ``` 1. 使用程式碼準備下載檔案 ``` @Test public void getConfig()throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration(),"hadoop"); fileSystem.copyToLocalFile(new Path("/config/core-site.xml"),new Path("file:///c:/core-site.xml")); fileSystem.close(); } ``` #### 1.9.9. 小檔案合併 由於 Hadoop 擅長儲存大檔案,因為大檔案的元資料資訊比較少,如果 Hadoop 叢集當中有大量的小檔案,那麼每個小檔案都需要維護一份元資料資訊,會大大的增加叢集管理元資料的記憶體壓力,所以在實際工作當中,如果有必要一定要將小檔案合併成大檔案進行一起處理 在我們的 HDFS 的 Shell 命令模式下,可以通過命令列將很多的 hdfs 檔案合併成一個大檔案下載到本地 ``` cd /export/servers hdfs dfs -getmerge /config/*.xml ./hello.xml ``` 既然可以在下載的時候將這些小檔案合併成一個大檔案一起下載,那麼肯定就可以在上傳的時候將小檔案合併到一個大檔案裡面去 ``` @Test public void mergeFile() throws Exception{ //獲取分散式檔案系統 FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250:8020"), new Configuration(),"hadoop"); FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.xml")); //獲取本地檔案系統 LocalFileSystem local = FileSystem.getLocal(new Configuration()); //通過本地檔案系統獲取檔案列表,為一個集合 FileStatus[] fileStatuses = local.listStatus(new Path("file:///F:\\傳智播客大資料離線階段課程資料\\3、大資料離線第三天\\上傳小檔案合併")); for (FileStatus fileStatus : fileStatuses) { FSDataInputStream inputStream = local.open(fileStatus.getPath()); IOUtils.copy(inputStream,outputStream); IOUtils.closeQuietly(inputStream); } IOUtils.closeQuietly(outputStream); local.close(); fileSystem.close(); } ``` 下一遍將介紹 [MapReduce](https://www.cnblogs.com/whgk/p/14544473.html)