[TOC]
# HDFS原理
## 1. HDFS前言
1) 設計思想
> 分而治之:將大文件、大批量文件,分布式存放在大量服務器上,以便于采取分而治之的方式對海量數據進行運算分析;
2) 在大數據系統中作用:
> 為各類分布式運算框架(如:mapreduce,spark,tez,……)提供數據存儲服務
3) 重點概念:文件切塊,副本存放,元數據
## 2. HDFS的概念和特性
> 首先,它是一個文件系統,用于存儲文件,通過統一的命名空間——目錄樹來定位文件
> 其次,它是分布式的,由很多服務器聯合起來實現其功能,集群中的服務器有各自的角色;
> 重要特性如下:
1) HDFS中的文件在物理上是分塊存儲(block),塊的大小可以通過配置參數( dfs.blocksize)來規定,默認大小在hadoop2.x版本中是128M,老版本中是64M
2) HDFS文件系統會給客戶端提供一個統一的抽象目錄樹,客戶端通過路徑來訪問文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
3) 目錄結構及文件分塊位置信息(元數據)的管理由namenode節點承擔
> ——namenode是HDFS集群主節點,負責維護整個hdfs文件系統的目錄樹,以及每一個路徑(文件)所對應的block塊信息(block的id,及所在的datanode服務器)
4) 文件的各個block的存儲管理由datanode節點承擔
> ---- datanode是HDFS集群從節點,每一個block都可以在多個datanode上存儲多個副本(副本數量也可以通過參數設置dfs.replication,默認是3)
5) HDFS是設計成適應一次寫入,多次讀出的場景,且不支持文件的修改
> (注:適合用來做數據分析,并不適合用來做網盤應用,因為,不便修改,延遲大,網絡開銷大,成本太高)
# ******HDFS基本操作篇******
## 3. HDFS的shell(命令行客戶端)操作
### 3.1 HDFS命令行客戶端使用
> HDFS提供shell命令行客戶端,使用方法如下:
> 可以使用一下兩種形式:
~~~
hadoop fs -… <args>
hdfs dfs -… <args>
~~~

3.2 命令行客戶端支持的命令參數
~~~
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] <localsrc> ... <dst>]
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] <path> ...]
[-cp [-f] [-p] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] <path> ...]
[-expunge]
[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getmerge [-nl] <src> <localdst>]
[-help [cmd ...]]
[-ls [-d] [-h] [-R] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touchz <path> ...]
[-usage [cmd ...]]
~~~
### 3.2 常用命令參數介紹
> -help
> 功能:輸出這個命令參數手冊
> -ls
> 功能:顯示目錄信息
> 示例: hadoop fs -ls hdfs://hadoop-server01:9000/
> 備注:這些參數中,所有的hdfs路徑都可以簡寫
> -->hadoop fs -ls / 等同于上一條命令的效果
> -mkdir
> 功能:在hdfs上創建目錄
> 示例:hadoop fs -mkdir -p /aaa/bbb/cc/dd
> -moveFromLocal
> 功能:從本地剪切粘貼到hdfs
> 示例:hadoop fs - moveFromLocal /home/hadoop/a.txt /aaa/bbb/cc/dd
> -moveToLocal
> 功能:從hdfs剪切粘貼到本地
> 示例:hadoop fs - moveToLocal /aaa/bbb/cc/dd /home/hadoop/a.txt
> --appendToFile
> 功能:追加一個文件到已經存在的文件末尾
> 示例:hadoop fs -appendToFile ./hello.txt hdfs://hadoop-server01:9000/hello.txt
> 可以簡寫為:
> Hadoop fs -appendToFile ./hello.txt /hello.txt
> -cat
> 功能:顯示文件內容
> 示例:hadoop fs -cat /hello.txt
> -tail
> 功能:顯示一個文件的末尾
> 示例:hadoop fs -tail /weblog/access_log.1
> -text
> 功能:以字符形式打印一個文件的內容
> 示例:hadoop fs -text /weblog/access_log.1
> -chgrp
> -chmod
> -chown
> 功能:linux文件系統中的用法一樣,對文件所屬權限
> 示例:
> hadoop fs -chmod 666 /hello.txt
> hadoop fs -chown someuser:somegrp /hello.txt
> -copyFromLocal
> 功能:從本地文件系統中拷貝文件到hdfs路徑去
> 示例:hadoop fs -copyFromLocal ./jdk.tar.gz /aaa/
> -copyToLocal
> 功能:從hdfs拷貝到本地
> 示例:hadoop fs -copyToLocal /aaa/jdk.tar.gz
> -cp
> 功能:從hdfs的一個路徑拷貝hdfs的另一個路徑
> 示例: hadoop fs -cp /aaa/jdk.tar.gz /bbb/jdk.tar.gz.2
> -mv
> 功能:在hdfs目錄中移動文件
> 示例: hadoop fs -mv /aaa/jdk.tar.gz /
> -get
> 功能:等同于copyToLocal,就是從hdfs下載文件到本地
> 示例:hadoop fs -get /aaa/jdk.tar.gz
> 功能:合并下載多個文件
> 示例:比getmerge 如hdfs的目錄 /aaa/下有多個文件:log.1, log.2,log.3,...
> hadoop fs -getmerge /aaa/log.* ./log.sum
> -put
> 功能:等同于copyFromLocal
> 示例:hadoop fs -put /aaa/jdk.tar.gz /bbb/jdk.tar.gz.2
> -rm
> 功能:刪除文件或文件夾
> 示例:hadoop fs -rm -r /aaa/bbb/
> -rmdir
> 功能:刪除空目錄
> 示例:hadoop fs -rmdir /aaa/bbb/ccc
> -df
> 功能:統計文件系統的可用空間信息
> 示例:hadoop fs -df -h /
> -du
> 功能:統計文件夾的大小信息
> 示例:
> hadoop fs -du -s -h /aaa/*
> -count
> 功能:統計一個指定目錄下的文件節點數量
> 示例:hadoop fs -count /aaa/
> -setrep
> 功能:設置hdfs中文件的副本數量
> 示例:hadoop fs -setrep 3 /aaa/jdk.tar.gz
> 補充:查看dfs集群工作狀態的命令
~~~
hdfs dfsadmin -report
~~~
# ******HDFS原理篇******
## 4. hdfs的工作機制
> (工作機制的學習主要是為加深對分布式系統的理解,以及增強遇到各種問題時的分析解決能力,形成一定的集群運維能力)
> 注:很多不是真正理解hadoop技術體系的人會常常覺得HDFS可用于網盤類應用,但實際并非如此。要想將技術準確用在恰當的地方,必須對技術有深刻的理解
### 4.1 概述
1. HDFS集群分為兩大角色:NameNode、DataNode (Secondary Namenode)
2. NameNode負責管理整個文件系統的元數據
3. DataNode 負責管理用戶的文件數據塊
4. 文件會按照固定的大小(blocksize)切成若干塊后分布式存儲在若干臺datanode上
5. 每一個文件塊可以有多個副本,并存放在不同的datanode上
6. Datanode會定期向Namenode匯報自身所保存的文件block信息,而namenode則會負責保持文件的副本數量
7. HDFS的內部工作機制對客戶端保持透明,客戶端請求訪問HDFS都是通過向namenode申請來進行
?
### 4.2 HDFS寫數據流程
#### 4.2.1 概述
> 客戶端要向HDFS寫數據,首先要跟namenode通信以確認可以寫文件并獲得接收文件block的datanode,然后,客戶端按順序將文件逐個block傳遞給相應datanode,并由接收到block的datanode負責向其他datanode復制block的副本
### 4.2.2 詳細步驟圖


#### 4.2.3 詳細步驟解析
1. 根namenode通信請求上傳文件,namenode檢查目標文件是否已存在,父目錄是否存在
2. namenode返回是否可以上傳
3. client請求第一個 block該傳輸到哪些datanode服務器上
4. namenode返回3個datanode服務器ABC
5. client請求3臺dn中的一臺A上傳數據(本質上是一個RPC調用,建立pipeline),A收到請求會繼續調用B,然后B調用C,將真個pipeline建立完成,逐級返回客戶端
6. client開始往A上傳第一個block(先從磁盤讀取數據放到一個本地內存緩存),以packet為單位,A收到一個packet就會傳給B,B傳給C;A每傳一個packet會放入一個應答隊列等待應答
7. 當一個block傳輸完成之后,client再次請求namenode上傳第二個block的服務器。
### 4.3. HDFS讀數據流程
#### 4.3.1 概述
> 客戶端將要讀取的文件路徑發送給namenode,namenode獲取文件的元信息(主要是block的存放位置信息)返回給客戶端,客戶端根據返回的信息找到相應datanode逐個獲取文件的block并在客戶端本地進行數據追加合并從而獲得整個文件
#### 4.3.2 詳細步驟圖

#### 4.3.3 詳細步驟解析
1. 跟namenode通信查詢元數據,找到文件塊所在的datanode服務器
2. 挑選一臺datanode(就近原則,然后隨機)服務器,請求建立socket流
3. datanode開始發送數據(從磁盤里面讀取數據放入流,以packet為單位來做校驗)
4. 客戶端以packet為單位接收,現在本地緩存,然后寫入目標文件
## 5 NAMENODE工作機制
> 學習目標:理解namenode的工作機制尤其是元數據管理機制,以增強對HDFS工作原理的理解,及培養hadoop集群運營中“性能調優”、“namenode”故障問題的分析解決能力
> 問題場景:
1) 集群啟動后,可以查看目錄,但是上傳文件時報錯,打開web頁面可看到namenode正處于safemode狀態,怎么處理?
> 解釋:
> safemode是namenode的一種狀態(active/standby/safemode安全模式)
> namenode進入安全模式的原理:
1) namenode發現集群中的block丟失率達到一定比例時(0.01%),namenode就會進入安全模式,在安全模式下,客戶端不能對任何數據進行操作,只能查看元數據信息(比如ls/mkdir)
2) 如何退出安全模式?
> 找到問題所在,進行修復(比如修復宕機的datanode)
> 或者可以手動強行退出安全模式(沒有真正解決問題): hdfs namenode --safemode leave
3) 在hdfs集群正常冷啟動時,namenode也會在safemode狀態下維持相當長的一段時間,此時你不需要去理會,等待它自動退出安全模式即可
> 原理:
> namenode的內存元數據中,包含文件路徑、副本數、blockid,及每一個block所在datanode的信息,而fsimage中,不包含block所在的datanode信息,那么,當namenode冷啟動時,此時內存中的元數據只能從fsimage中加載而來,從而就沒有block所在的datanode信息——>就會導致namenode認為所有的block都已經丟失——>進入安全模式——>datanode啟動后,會定期向namenode匯報自身所持有的blockid信息,——>隨著datanode陸續啟動,從而陸續匯報block信息,namenode就會將內存元數據中的block所在datanode信息補全更新——>找到了所有block的位置,從而自動退出安全模式)
2) Namenode服務器的磁盤故障導致namenode宕機,如何挽救集群及數據?
3) Namenode是否可以有多個?namenode內存要配置多大?namenode跟集群數據存儲能力有關系嗎?
4) 文件的blocksize究竟調大好還是調小好?--結合mapreduce
5) ……
> 諸如此類問題的回答,都需要基于對namenode自身的工作原理的深刻理解
### 5.1 NAMENODE職責
> NAMENODE職責:
1. 負責客戶端請求的響應
2. 元數據的管理(查詢,修改)
#### 5.2 元數據管理
> namenode對數據的管理采用了三種存儲形式:
1. 內存元數據(NameSystem)
2. 磁盤元數據鏡像文件
3. 數據操作日志文件(可通過日志運算出元數據)
> namenode元數據恢復

##### 5.2.1 元數據存儲機制
1) 內存中有一份完整的元數據(內存meta data)
2) 磁盤有一個“準完整”的元數據鏡像(fsimage)文件(在namenode的工作目錄中)
3) 用于銜接內存metadata和持久化元數據鏡像fsimage之間的操作日志(edits文件)注:當客戶端對hdfs中的文件進行新增或者修改操作,操作記錄首先被記入edits日志文件中,當客戶端操作成功后,相應的元數據會更新到內存meta.data中
##### 5.2.2 元數據手動查看
> 可以通過hdfs的一個工具來查看edits中的信息
~~~
bin/hdfs oev -i edits -o edits.xml
bin/hdfs oiv -i fsimage_0000000000000000087 -p XML -o fsimage.xml
~~~
##### 5.2.3 元數據的checkpoint
> 每隔一段時間,會由secondary namenode將namenode上積累的所有edits和一個最新的fsimage下載到本地,并加載到內存進行merge(這個過程稱為checkpoint)
> checkpoint的詳細過程

> checkpoint操作的觸發條件配置參數
~~~
dfs.namenode.checkpoint.check.period=60 #檢查觸發條件是否滿足的頻率,60秒
dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary
#以上兩個參數做checkpoint操作時,secondary namenode的本地工作目錄
dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}
dfs.namenode.checkpoint.max-retries=3 #最大重試次數
dfs.namenode.checkpoint.period=3600 #兩次checkpoint之間的時間間隔3600秒
dfs.namenode.checkpoint.txns=1000000 #兩次checkpoint之間最大的操作記錄
~~~
> checkpoint的附帶作用
> namenode和secondary namenode的工作目錄存儲結構完全相同,所以,當namenode故障退出需要重新恢復時,可以從secondary namenode的工作目錄中將fsimage拷貝到namenode的工作目錄,以恢復namenode的元數據
##### 5.2.4 元數據目錄說明
> 在第一次部署好Hadoop集群的時候,我們需要在NameNode(NN)節點上格式化磁盤:
~~~
$HADOOP_HOME/bin/hdfs namenode -format
~~~
> 格式化完成之后,將會在$dfs.namenode.name.dir/current目錄下如下的文件結構
~~~
current/
|-- VERSION
|-- edits_*
|-- fsimage_0000000000008547077
|-- fsimage_0000000000008547077.md5
~~~
> -- seen_txid
> 其中的dfs.name.dir是在hdfs-site.xml文件中配置的,默認值如下:
~~~
<property>
<name>dfs.name.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/name</value>
</property>
hadoop.tmp.dir是在core-site.xml中配置的,默認值如下
<property>
<name>hadoop.tmp.dir</name>
<value>/tmp/hadoop-${user.name}</value>
<description>A base for other temporary directories.</description>
</property>
~~~
> dfs.namenode.name.dir屬性可以配置多個目錄,
> 如/data1/dfs/name,/data2/dfs/name,/data3/dfs/name,....。各個目錄存儲的文件結構和內容都完全一樣,相當于備份,這樣做的好處是當其中一個目錄損壞了,也不會影響到Hadoop的元數據,特別是當其中一個目錄是NFS(網絡文件系統Network File System,NFS)之上,即使你這臺機器損壞了,元數據也得到保存。
> 下面對$dfs.namenode.name.dir/current/目錄下的文件進行解釋。
1) VERSION文件是Java屬性文件,內容大致如下:
~~~
#Fri Nov 15 19:47:46 CST 2013
namespaceID=934548976
clusterID=CID-cdff7d73-93cd-4783-9399-0a22e6dce196
cTime=0
storageType=NAME_NODE
blockpoolID=BP-893790215-192.168.24.72-1383809616115
layoutVersion=-47
~~~
> 其中
* namespaceID是文件系統的唯一標識符,在文件系統首次格式化之后生成的;
* storageType說明這個文件存儲的是什么進程的數據結構信息(如果是DataNode,storageType=DATA_NODE);
* cTime表示NameNode存儲時間的創建時間,由于我的NameNode沒有更新過,所以這里的記錄值為0,以后對NameNode升級之后,cTime將會記錄更新時間戳;
* layoutVersion表示HDFS永久性數據結構的版本信息, 只要數據結構變更,版本號也要遞減,此時的HDFS也需要升級,否則磁盤仍舊是使用舊版本的數據結構,這會導致新版本的NameNode無法使用;
* clusterID是系統生成或手動指定的集群ID,在-clusterid選項中可以使用它;如下說明
a) 使用如下命令格式化一個Namenode:
~~~
$HADOOP_HOME/bin/hdfs namenode -format [-clusterId <cluster_id>]
~~~
> 選擇一個唯一的cluster_id,并且這個cluster_id不能與環境中其他集群有沖突。如果沒有提供cluster_id,則會自動生成一個唯一的ClusterID。
b) 使用如下命令格式化其他Namenode:
~~~
$HADOOP_HOME/bin/hdfs namenode -format -clusterId <cluster_id>
~~~
c) 升級集群至最新版本。在升級過程中需要提供一個ClusterID,例如:
~~~
$HADOOP_PREFIX_HOME/bin/hdfs start namenode --config $HADOOP_CONF_DIR -upgrade -clusterId <cluster_ID>
~~~
如果沒有提供ClusterID,則會自動生成一個ClusterID。
* blockpoolID:是針對每一個Namespace所對應的blockpool的ID,上面的這個BP-893790215-192.168.24.72-1383809616115就是在我的ns1的namespace下的存儲塊池的ID,這個ID包括了其對應的NameNode節點的ip地址。
2) $dfs.namenode.name.dir/current/seen_txid非常重要,是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾數,namenode重啟的時候,會按照seen_txid的數字,循序從頭跑edits_0000001~到seen_txid的數字。所以當你的hdfs發生異常重啟的時候,一定要比對seen_txid內的數字是不是你edits最后的尾數,不然會發生建置namenode時metaData的資料有缺少,導致誤刪Datanode上多余Block的資訊。
3) $dfs.namenode.name.dir/current目錄下在format的同時也會生成fsimage和edits文件,及其對應的md5校驗文件。
> 補充:seen_txid
> 文件中記錄的是edits滾動的序號,每次重啟namenode時,namenode就知道要將哪些edits進行加載edits
## 6. DATANODE的工作機制
> 問題場景:
1. 集群容量不夠,怎么擴容?
2. 如果有一些datanode宕機,該怎么辦?
3. datanode明明已啟動,但是集群中的可用datanode列表中就是沒有,怎么辦?
> 以上這類問題的解答,有賴于對datanode工作機制的深刻理解
### 6.1 概述
1) Datanode工作職責:
> 存儲管理用戶的文件塊數據
> 定期向namenode匯報自身所持有的block信息(通過心跳信息上報)
> (這點很重要,因為,當集群中發生某些block副本失效時,集群如何恢復block初始副本數量的問題)
~~~
<property>
<name>dfs.blockreport.intervalMsec</name>
<value>3600000</value>
<description>Determines block reporting interval in milliseconds.</description>
</property>
~~~
2) Datanode掉線判斷時限參數
> datanode進程死亡或者網絡故障造成datanode無法與namenode通信,namenode不會立即把該節點判定為死亡,要經過一段時間,這段時間暫稱作超時時長。HDFS默認的超時時長為10分鐘+30秒。如果定義超時時間為timeout,則超時時長的計算公式為:
~~~
timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval。
~~~
> 而默認的heartbeat.recheck.interval 大小為5分鐘,dfs.heartbeat.interval默認為3秒。
> 需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的單位為毫秒,dfs.heartbeat.interval的單位為秒。所以,舉個例子,如果heartbeat.recheck.interval設置為5000(毫秒),dfs.heartbeat.interval設置為3(秒,默認),則總的超時時間為40秒。
~~~
<property>
<name>heartbeat.recheck.interval</name>
<value>2000</value>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>1</value>
</property>
~~~
### 6.2 觀察驗證DATANODE功能
> 上傳一個文件,觀察文件的block具體的物理存放情況:
> 在每一臺datanode機器上的這個目錄中能找到文件的切塊:
~~~
/home/hadoop/app/hadoop-2.4.1/tmp/dfs/data/current/BP-193442119-192.168.2.120-1432457733977/current/finalized
~~~
- hadoop
- linux基礎
- Linux入門
- Linux進階
- shell
- Zookeeper
- Zookeeper簡介及部署
- Zookeeper使用及API
- Redis
- Redis簡介安裝部署
- Redis使用及API
- Java高級增強
- Java多線程增強
- Maven簡介及搭建
- Hive
- Hive簡介及安裝
- Hive操作
- HIve常用函數
- Hive數據類型
- Flume
- Flume簡介及安裝
- flume 攔截器(interceptor)
- azkaban
- azKaban簡介及安裝
- Sqoop
- Sqoop簡介及安裝
- HDFS
- HDFS原理
- HDFS操作API
- MAPREDUCE原理
- MAPREDUCE圖片資源
- MAPREDUCE加強
- HBASE
- HBASE簡介及安裝
- HBASE操作及API
- HBASE內部原理
- Storm
- Storm簡介及安裝
- Storm原理
- kafka
- kafka簡介及安裝
- kafka常用操作及API
- kafka原理
- kafka配置詳解
- Scala
- Scala簡介及安裝
- Scala基礎語法
- Scala實戰