HDFS 是一個 Apache Software Foundation 項目,是 Apache Hadoop 項目的一個子項目。Hadoop 很是適於存儲大型數據(好比 terabytes和petabytes),並使用 HDFS 做爲其存儲系統。HDFS 容許您鏈接多個集羣中包含的節點 (普通我的計算機),那些集羣上分佈着一些數據文件。而後您能夠將那些數據文件做爲一個無縫文件系統來進行訪問和存儲。對數據文件的訪問經過一種流線型(streaming) 方式進行處理,這意味着應用程序或命令經過 MapReduce 處理模型直接執行(參見 參考資料)。HDFS 是容錯的,且提供對大數據集的高吞吐量訪問。html
HDFS 與其餘分佈式文件系統有許多類似點,但也有幾個不一樣點。一個明顯的區別是 HDFS 的 「一次寫入、屢次讀取(write-once-read-many)」 模型,該模型下降了併發性控制要求,簡化了數據聚合性,支持高吞吐量訪問。java
HDFS 的另外一個獨特的特性是下面這個觀點:將處理邏輯放置到數據附近一般比將數據移向應用程序空間更好。node
HDFS 將數據寫入嚴格限制爲一次一個寫入程序。字節老是被附加到一個流的末尾,字節流老是以寫入順序存儲。linux
HDFS 有許多目標,下面是一些最明顯的目標:web
經過檢測故障和應用快速、自動的恢復實現容錯性算法
經過 MapReduce 流進行數據訪問shell
簡單可靠的聚合模型apache
處理邏輯接近數據,而不是數據接近處理邏輯編程
跨異構普通硬件和操做系統的可移植性windows
可靠存儲和處理大量數據的可伸縮性
經過跨多個普通我的計算機集羣分佈數據和處理來節約成本
經過分佈數據和邏輯到數據所在的多個節點上進行平行處理來提升效率
經過自動維護多個數據副本和在故障發生時自動從新部署處理邏輯來實現可靠性
HDFS應用程序接口(API)
您能夠以多種不一樣的方法訪問 HDFS。HDFS 提供了一個原生 Java™ 應用程序編程接口(API重點介紹)和一個針對這個 Java API 的原生 C 語言封裝器。另外,您可使用一個 web 瀏覽器來瀏覽 HDFS 文件.例外還有如下能夠來訪問HDFS:
既然HDFS 是存取數據的分佈式文件系統,那麼對HDFS 的操做,就是文件系統的基本操做,好比文件的建立、修改、刪除、修改權限等,文件夾的建立、刪除、重命名等。對HDFS 的操做命令相似於lLinux 的shell 對文件的操做,如ls、mkdir、rm 等。咱們執行如下操做的時候,必定要肯定hadoop 是正常運行的,使用jps 命令確保看到各個hadoop 進程。SHELL操做較多,簡介見文檔Hadoop-Shell.pdf還有該連接http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html,就不一個一個介紹啦。
咱們經過hadoop shell 上傳的文件是存放在DataNode 的block 中,經過linux shell 是看不到文件的,只能看到block。能夠一句話描述HDFS:把客戶端的大文件存放在不少節點的數據塊中。在這裏,出現了三個關鍵詞:文件、節點、數據塊。HDFS 就是圍繞着這三個關鍵詞設計的,咱們在學習的時候也要緊抓住這三個關鍵詞來學習。
HDFS 由一些互聯的節點集羣組成,文件和目錄駐留在那些節點上。一個 HDFS 集羣包含一個節點,稱爲 NameNode,該節點管理文件系統名稱空間並規範客戶端對文件的訪問。另外, Data node (DataNodes)將數據做爲塊存儲在文件中。HDFS的架構圖以下:
由上圖可知:在 HDFS 中,一個給定的NameNode是整個文件系統的管理節點。它維護着整個文件系統的文件目錄樹,文件/目錄的元信息和每一個文件對應的數據塊列表兩套數據,Namenode還將數據塊映射到Data node,處理來自 HDFS 客戶端的讀寫請求。 Data node 還根據 Name node 的指令建立、刪除和複製數據塊。
其中的文件放在指定目錄(有配置文件core-site.xml的dfs.name.dir屬性決定).在該目錄下包括:
fsimage:元數據鏡像文件。存儲某一時段NameNode內存元數據信息。在內存...
edits:操做日誌文件。
fstime:保存最近一次checkpoint的時間
這些的文件保存在linux系統下的文件系統下.HDFS的客戶端全部的操做必須通過NameNode
提供真實文件的存儲服務.
文件塊(Block):最基本的存儲單位。對於文件內容而言,一個文件的長度大小是size,那麼從文件的0偏移開始,按照固定的大小,順序對文件進行劃分並編號,劃分好的每個塊稱一個Block。HDFS默認Block大小是128MB(可配置),以一個256MB文件,共有256/128=2個Block.block 本質上是一個邏輯概念,意味着block 裏面不會真正的存儲數據,只是劃分文件的.不一樣於普通文件系統的是,HDFS中,若是一個文件小於一個數據塊的大小,並不佔用整個數據塊存儲空間.
在每臺主機Linux文件系統中都能找到:
副本(replication):多副本,默認是三個.可配置:hdfs-site.xml中dfs.replication的屬性.機櫃意識:
一般,大型 HDFS 集羣跨多個安裝點(機櫃)排列。一個安裝中的不一樣節點之間的網絡流量一般比跨安裝點的網絡流量更高效。一個 Name node 儘可能將一個塊的多個副本放置到多個安裝上以提升容錯能力。可是,HDFS 容許管理員決定一個節點屬於哪一個安裝點。所以,每一個節點都知道它的機櫃 ID,也就是說,它具備機櫃意識。
見下圖:就不作解釋啦.
Data node 持續循環,詢問 Name node 的指令。 Name node 不能直接鏈接到 Data node ,它只是從 Data node 調用的函數返回值。每一個 Data node 都維護一個開放的服務器套接字,以便客戶端代碼或其餘 Data node 可以讀寫數據。 Name node 知道這個服務器的主機或端口,將信息提供給有關客戶端或其餘 Data node 。全部 HDFS 通訊協議都構建於 TCP/IP 協議之上。HDFS 客戶端鏈接到 Name node 上打開的一個 Transmission Control Protocol (TCP) 端口,而後使用一個基於 Remote Procedure Call (RPC) 的專有協議與 Name node 通訊。 Data node 使用一個基於塊的專有協議與 Name node 通訊。Hadoop整個生態系統都是基於RPC協議之上的。關於RPC的通訊原理將例外寫一篇博客.連接。。。
實際上,爲了提升整個集羣的可靠性和可維護性,各大公司和社區都提出來不少改進HDFS的方案,在這裏,我就暫時介紹HDFS其中的一種,之後博客會詳細描述HDFS HA的解決方案,而且進行總結.
Secondary NameNode經過按期下載NameNode的元數據和日誌文件,並進行合併更新,來對NameNode進行備份。當NameNode故障時,能夠經過Secondary NameNode進行恢復,可是不足之處在於Secondary NameNode的備份知識NameNode的Checkpoint,並無與NameNode實時同步,恢復後的數據存在必定的元信息丟失,因爲在恢復過程當中存在一段系統不可用的時間,該方案只能是一種備份方案,並非真正意義上的HA方案.該流程圖以下:
NameNode的執行:
Namenode始終在內存中保存metedata,用於處理「讀請求」. 等到有「寫請求」到來時,namenode會首先寫editlog到磁盤,即向edits文件中寫日誌,成功返回後,纔會修改內存,而且向客戶端返回。 Hadoop會維護一個fsimage文件,也就是namenode中metedata的鏡像,可是fsimage不會隨時與namenode內存中的metedata保持一致,而是每隔一段時間經過合併edits文件來更新內容。有誰來合併呢??---->Secondary namenode就是用來合併fsimage和edits文件來更新NameNode的metedata的。
Secondary namendoe的工做流程:
1.secondary通知namenode切換edits文件(這時NameNode會生成newedits文件) 2.secondary從namenode得到fsimage和edits(經過http) 3.secondary將fsimage載入內存,而後開始合併(以必定的算法)edits 4.secondary將新的fsimage發回給namenode 5.namenode用新的fsimage替換舊的fsimage
直接上代碼:
HadoopUtil.java package com.codewatching.hadoop.service; import java.net.URI; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; /** * Hadoop簡單工具類 * @author LISAI */ public class HadoopUtil { public static FileSystem getFileSystem(){ try { Configuration conf = new Configuration(); URI uri = new URI("hdfs://yun10-0:9000/"); FileSystem fileSystem = FileSystem.get(uri, conf, "lisai"); return fileSystem; } catch (Exception e) { e.printStackTrace(); } return null; } }
HadoopBasicAPIService.java package com.codewatching.hadoop.service; import java.io.FileOutputStream; import java.io.OutputStream; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; /** * Hadoop API的操做 * @author LISAI */ public class HadoopBasicAPIService { private FileSystem fileSystem = HadoopUtil.getFileSystem(); /** * 傳統方式---下載 */ @Deprecated public void downLoadTraditional(String uri,String dest) throws Exception{ FSDataInputStream dataInputStream = fileSystem.open(new Path(uri)); OutputStream outputStream = new FileOutputStream(dest); IOUtils.copyBytes(dataInputStream, outputStream, fileSystem.getConf()); } /** * 經常使用方式---下載(windows環境下注意事項) */ public void downLoadSimple(String src,String dest) throws Exception{ fileSystem.copyToLocalFile(new Path(src), new Path(dest)); } /** * 上傳 * @param src * @param dest * @throws Exception */ public void upload(String src,String dest) throws Exception{ fileSystem.copyFromLocalFile(new Path(src),new Path(dest)); } /** * 建立文件夾 * @param makeDir * @throws Exception */ public void mkdir(String makeDir) throws Exception{ fileSystem.mkdirs(new Path(makeDir)); } /** * 刪除文件夾 */ public void deldir(String delDir) throws Exception{ fileSystem.delete(new Path(delDir),true); } }
1.初始化FileSystem,而後客戶端(client)用FileSystem的open()函數打開文件 2.FileSystem用RPC調用元數據節點,獲得文件的數據塊信息,對於每個數據塊,元數據節點返回保存數據塊的數據節點的地址。 3.FileSystem返回FSDataInputStream給客戶端,用來讀取數據,客戶端調用stream的read()函數開始讀取數據。 4.DFSInputStream鏈接保存此文件第一個數據塊的最近的數據節點,data從數據節點讀到客戶端(client) 5.當此數據塊讀取完畢時,DFSInputStream關閉和此數據節點的鏈接,而後鏈接此文件下一個數據塊的最近的數據節點。 6.當客戶端讀取完畢數據的時候,調用FSDataInputStream的close函數。 7.在讀取數據的過程當中,若是客戶端在與數據節點通訊出現錯誤,則嘗試鏈接包含此數據塊的下一個數據節點。 8.失敗的數據節點將被記錄,之後再也不鏈接。
如下幾步,就是如何獲取建立和代理對象的過程..只有拿到客戶端的代理對象,咱們才能對HDFS進行相關操做。RPC過程的原理,之後的博客會有大幅邊幅談論.
dfs===========DFSClient[clientName=DFSClient_NONMAPREDUCE_1386880610_1, ugi=lisai (auth:SIMPLE)]
fs===========DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_1386880610_1, ugi=lisai (auth:SIMPLE)]]
初始化完畢。。。。。。
中間省略幾個方法調用..........
這下就拿到了FSDataInputStream流到客戶端。接下來的步驟就是COPY的事啦。。。
參考文章:http://www.ibm.com/developerworks/cn/web/wa-introhdfs/
http://www.ibm.com/developerworks/cn/linux/1406_jiangtao_camphadoop/