Hadoop詳解(04)-Hdfs
HDFS概述
- HDFS產出背景及定義
背景:隨着數據量越來越大,在一個操作系統存不下所有的數據,那么就分配到更多的操作系統管理的磁盤中,但是不方便管理和維護,迫切需要一種系統來管理多台機器上的文件,這就是分布式文件管理系統。HDFS只是分布式文件管理系統中的一種。
定義:HDFS(Hadoop Distributed File System),它是一個文件系統,用於存儲文件,通過目錄樹來定位文件;其次,它是分布式的,由很多服務器聯合起來實現其功能,集群中的服務器有各自的角色。
使用場景:適合一次寫入,多次讀出的場景,且不支持文件的修改。適合用來做數據分析,並不適合用來做網盤應用。
- 優缺點
優點
高容錯性
(1)數據自動保存多個副本。它通過增加副本的形式,提高容錯性。
(2)某一個副本丟失以后,它可以自動恢復。
適合處理大數據
(1)數據規模:能夠處理數據規模達到GB、TB、甚至PB級別的數據;
(2)文件規模:能夠處理百萬規模以上的文件數量,數量相當之大。
3)可構建在廉價機器上,通過多副本機制,提高可靠性。
缺點
不適合低延時數據訪問,比如毫秒級的存儲數據,是做不到的。
無法高效的對大量小文件進行存儲。
(1)存儲大量小文件的話,它會占用NameNode大量的內存來存儲文件目錄和塊信息。這樣是不可取的,因為NameNode的內存總是有限的;
(2)小文件存儲的尋址時間會超過讀取時間,它違反了HDFS的設計目標
不支持並發寫入、文件隨機修改。
(1)一個文件只能有一個寫,不允許多個線程同時寫;
(2)僅支持數據append(追加),不支持文件的隨機修改。
- 組成架構
NameNode(nn)就是主節點Master,是一個主管、管理者。
(1)管理HDFS的名稱空間;
(2)配置副本策略;
(3)管理數據塊(Block)映射信息;
(4)處理客戶端讀寫請求。
DataNode:就是從節點Slave。NameNode下達命令,DataNode執行實際的操作。
(1)存儲實際的數據塊;
(2)執行數據塊的讀/寫操作。
Client:就是客戶端
(1)文件切分。文件上傳HDFS的時候,Client將文件切分成一個一個的Block,然后進行上傳;
(2)與NameNode交互,獲取文件的位置信息;
(3)與DataNode交互,讀取或者寫入數據;
(4)Client提供一些命令來管理HDFS,比如NameNode格式化;
(5)Client可以通過一些命令來訪問HDFS,比如對HDFS增刪查改操作;
Secondary NameNode:並非NameNode的熱備。當NameNode掛掉的時候,它並不能馬上替換NameNode並提供服務。
(1)輔助NameNode,分擔其工作量,比如定期合並Fsimage和Edits,並推送給NameNode ;
(2)在緊急情況下,可輔助恢復NameNode。
- HDFS文件塊大小(面試常問)
HDFS中的文件在物理上是分塊存儲(Block),塊的大小可以通過配置參數( dfs.blocksize)來規定,默認大小在Hadoop2.x版本中是128M,老版本中是64M。
為什么塊的大小不能設置太小,也不能設置太大?
(1)HDFS的塊設置太小,會增加尋址時間,程序一直在找塊的開始位置;
(2)如果塊設置的太大,從磁盤傳輸數據的時間會明顯大於定位這個塊開始位置所需的時間。導致程序在處理這塊數據時,會非常慢。
所以,HDFS塊的大小設置主要取決於磁盤傳輸速率。
如果尋址時間約為10ms,即查找到目標block的時間為10ms。
尋址時間為傳輸時間的1%時,則為最佳狀態。
因此,傳輸時間=10ms/0.01=1000ms=1s
而目前磁盤的傳輸速率普遍為100MB/s。
block大小=1s*100MB/s=100MB
HDFS的Shell操作
hadoop fs 和 hdfs dfs兩個命令是完全相同的
查看hdfs支持的命令
[hadoop@hadoop102 ~]$ hadoop fs
Usage: hadoop fs [generic options]
[-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] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-v] [-x] <path> ...]
[-expunge]
[-find <path> ... <expression> ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {-n name | -d} [-e en] <path>]
[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
[-head <file>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setfattr {-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] [-s <sleep interval>] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touch [-a] [-m] [-t TIMESTAMP ] [-c] <path> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
啟動hadoop集群
[hadoop@hadoop102 ~]$ cd /opt/module/hadoop-3.1.3/
[hadoop@hadoop102 hadoop-3.1.3]$ sbin/start-all.sh
幫助命令-help 可以輸出命令的幫助信息
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -help rm
-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ... :
Delete all files that match the specified file pattern. Equivalent to the Unix
command "rm <src>"
-f If the file does not exist, do not display a diagnostic message or
modify the exit status to reflect an error.
-[rR] Recursively deletes directories.
-skipTrash option bypasses trash, if enabled, and immediately deletes <src>.
-safely option requires safety confirmation, if enabled, requires
confirmation before deleting large directory with more than
<hadoop.shell.delete.limit.num.files> files. Delay is expected when
walking over large directory recursively to count the number of
files to be deleted before the confirmation.
- 上傳
-moveFromLocal:從本地剪切粘貼到HDFS
[hadoop@hadoop102 hadoop-3.1.3]$ touch a.txt
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -moveFromLocal ./a.txt /a.txt
-copyFromLocal:從本地文件系統中拷貝文件到HDFS路徑去
[hadoop@hadoop102 hadoop-3.1.3]$ touch b.txt
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -copyFromLocal ./b.txt /
-appendToFile:追加一個文件到已經存在的文件末尾
[hadoop@hadoop102 hadoop-3.1.3]$ echo abc >> ./c.txt
hadoop fs -appendToFile c.txt /a.txt
-put:等同於copyFromLocal
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -put ./c.txt /
- 下載
-copyToLocal:從HDFS拷貝到本地
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -copyToLocal /sanguo/shuguo/kongming.txt ./
2)-get:等同於copyToLocal,就是從HDFS下載文件到本地
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -get /sanguo/shuguo/kongming.txt ./
3)-getmerge:合並下載多個文件,比如HDFS的目錄 /user/test下有多個文件:log.1, log.2,log.3,...
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -getmerge /user/test/* ./zaiyiqi.txt
- HDFS直接操作
1)-ls: 顯示目錄信息
[hadoop@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /
Found 4 items
-rw-r--r-- 3 hadoop supergroup 4 2021-11-28 04:58 /a.txt
drwxr-xr-x - hadoop supergroup 0 2021-11-24 22:10 /input
drwx------ - hadoop supergroup 0 2021-11-24 23:27 /tmp
drwxr-xr-x - hadoop supergroup 0 2021-11-24 22:17 /user
2)-mkdir:在HDFS上創建目錄
[hadoop@hadoop102 ~]$ hadoop fs -mkdir -p /test1/test2
3)-cat:顯示文件內容
[hadoop@hadoop102 ~]$ hadoop fs -cat /a.txt
4)-chgrp 、-chmod、-chown:Linux文件系統中的用法一樣,修改文件所屬權限
[hadoop@hadoop102 ~]$ hadoop fs -chmod 666 /a.txt
[hadoop@hadoop102 ~]$ hadoop fs -chown hadoop:hadoop /a.txt
5)-cp :從HDFS的一個路徑拷貝到HDFS的另一個路徑
[hadoop@hadoop102 ~]$ hadoop fs -cp /a.txt /test1
6)-mv:在HDFS目錄中移動文件
[hadoop@hadoop102 ~]$ hadoop fs -mv /test1/a.txt /test1/test2/
7)-tail:顯示一個文件的末尾1kb的數據
[hadoop@hadoop102 ~]$ hadoop fs -tail /a.txt
8)-rm:刪除文件或文件夾
[hadoop@hadoop102 ~]$ hadoop fs -rm /test1/test2/a.txt
9)-rmdir:刪除空目錄
[hadoop@hadoop102 ~]$ hadoop fs -rmdir /test1/test2
10)-du統計文件夾的大小信息
[hadoop@hadoop102 ~]$ hadoop fs -du -s -h /
323.2 M 969.5 M /
11)-setrep:設置HDFS中文件的副本數量
[hadoop@hadoop102 ~]$ hadoop fs -setrep 10 /a.txt
HDFS Java客戶端操作
配置Windows開發環境
配置Windows開發環境請參考文檔《Hadoop詳解(04-1) - 基於hadoop3.1.3配置Windows10本地開發運行環境》
HDFS的API操作
- HDFS文件上傳(測試參數優先級)
-
@Test
-
public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {
-
// 1 獲取文件系統
-
Configuration configuration = new Configuration();
-
configuration.set("dfs.replication", "2");
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 2 上傳文件
-
fs.copyFromLocalFile(new Path("e:/banzhang.txt"), new Path("/banzhang6.txt"));
-
-
// 3 關閉資源
-
fs.close();
-
}
將hdfs-site.xml拷貝到項目的根目錄下
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
參數優先級排序:(1)客戶端代碼中設置的值 >(2)ClassPath下的用戶自定義配置文件 >(3)服務器的自定義配置(xxx-site.xml) >(4)服務器的默認配置(xxx-default.xml)
- HDFS文件下載
-
@Test
-
public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{
-
-
// 1 獲取文件系統
-
Configuration configuration = new Configuration();
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 2 執行下載操作
-
// boolean delSrc 指是否將原文件刪除
-
// Path src 指要下載的文件路徑
-
// Path dst 指將文件下載到的路徑
-
// boolean useRawLocalFileSystem 是否開啟文件校驗
-
fs.copyToLocalFile(false, new Path("/banzhang.txt"), new Path("e:/banhua.txt"), true);
-
-
// 3 關閉資源
-
fs.close();
-
}
- HDFS刪除文件和目錄
-
@Test
-
public void testDelete() throws IOException, InterruptedException, URISyntaxException{
-
-
// 1 獲取文件系統
-
Configuration configuration = new Configuration();
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 2 執行刪除
-
fs.delete(new Path("/2021"), true);
-
-
// 3 關閉資源
-
fs.close();
-
}
- HDFS文件更名和移動
-
@Test
-
public void testRename() throws IOException, InterruptedException, URISyntaxException{
-
-
// 1 獲取文件系統
-
Configuration configuration = new Configuration();
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 2 修改文件名稱
-
fs.rename(new Path("/banzhang.txt"), new Path("/banhua.txt"));
-
-
// 3 關閉資源
-
fs.close();
-
}
- HDFS文件詳情查看
查看文件名稱、權限、長度、塊信息
-
@Test
-
public void testListFiles() throws IOException, InterruptedException, URISyntaxException{
-
-
// 1獲取文件系統
-
Configuration configuration = new Configuration();
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 2 獲取文件詳情
-
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
-
-
while(listFiles.hasNext()){
-
LocatedFileStatus status = listFiles.next();
-
-
// 輸出詳情
-
System.out.println("------------------------");
-
// 文件名稱
-
System.out.println(status.getPath().getName());
-
// 長度
-
System.out.println(status.getLen());
-
// 權限
-
System.out.println(status.getPermission());
-
// 分組
-
System.out.println(status.getGroup());
-
-
// 獲取存儲的塊信息
-
BlockLocation[] blockLocations = status.getBlockLocations();
-
-
for (BlockLocation blockLocation : blockLocations) {
-
-
// 獲取塊存儲的主機節點
-
String[] hosts = blockLocation.getHosts();
-
-
for (String host : hosts) {
-
System.out.println(host);
-
}
-
}
-
}
-
// 3 關閉資源
-
fs.close();
-
}
- HDFS文件和文件夾判斷
-
@Test
-
public void testListStatus() throws IOException, InterruptedException, URISyntaxException{
-
-
// 1 獲取文件配置信息
-
Configuration configuration = new Configuration();
-
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "hadoop");
-
-
// 獲取文件列表
-
FileStatus[] listStatus = fs.listStatus(new Path("/"));
-
-
//2 循環遍歷文件列表並判斷是文件還是文件夾
-
for (FileStatus fileStatus : listStatus) {
-
// 如果是文件
-
if (fileStatus.isFile()) {
-
System.out.println("f:"+fileStatus.getPath().getName());
-
}else {
-
System.out.println("d:"+fileStatus.getPath().getName());
-
}
-
}
-
-
// 3 關閉資源
-
fs.close();
-
}
HDFS的上傳下載流程(面試常問)
上傳流程
(1)客戶端通過Distributed FileSystem模塊向NameNode請求上傳文件,NameNode檢查目標文件是否已存在,父目錄是否存在。
(2)NameNode返回是否可以上傳。
(3)客戶端請求第一個 Block上傳到哪幾個DataNode服務器上。
(4)NameNode返回3個DataNode節點,分別為dn1、dn2、dn3。
(5)客戶端通過FSDataOutputStream模塊請求dn1上傳數據,dn1收到請求會繼續調用dn2,然后dn2調用dn3,將這個通信管道建立完成。
(6)dn1、dn2、dn3逐級應答客戶端。
(7)客戶端開始往dn1上傳第一個Block(先從磁盤讀取數據放到一個本地內存緩存),以Packet為單位,dn1收到一個Packet就會傳給dn2,dn2傳給dn3;dn1每傳一個packet會放入一個應答隊列等待應答。
(8)當一個Block傳輸完成之后,客戶端再次請求NameNode上傳第二個Block的服務器。(重復執行3-7步)。
源碼:org.apache.hadoop.hdfs.DFSOutputStream
上傳文件副本節點的選擇
- 網絡拓撲-節點距離計算
在HDFS寫數據的過程中,NameNode會選擇距離待上傳數據最近距離的DataNode接收數據。那么這個最近距離怎么計算呢?
節點距離:兩個節點到達最近的共同祖先的距離總和。
- 副本存儲節點選擇(機架感知)
For the common case, when the replication factor is three, HDFS's placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack. This policy cuts the inter-rack write traffic which generally improves write performance. The chance of rack failure is far less than that of node failure; this policy does not impact data reliability and availability guarantees. However, it does reduce the aggregate network bandwidth used when reading data since a block is placed in only two unique racks rather than three. With this policy, the replicas of a file do not evenly distribute across the racks. One third of replicas are on one node, two thirds of replicas are on one rack, and the other third are evenly distributed across the remaining racks. This policy improves write performance without compromising data reliability or read performance.
對於常見的副本數量位3時的情況,HDFS的放置策略是,如果寫入程序位於datanode上,則將一個副本放置在本地計算機上,否則放置在隨機datanode上,另一個副本放置在不同(遠程)機架中的節點上,最后一個副本放置在同一遠程機架中的不同節點上。此策略減少機架間寫入通信量,這通常會提高寫入性能。機架故障的概率遠小於節點故障的概率;此策略不會影響數據可靠性和可用性保證。但是,它確實減少了讀取數據時使用的總網絡帶寬,因為一個塊只放在兩個而不是三個的機架中。使用此策略,文件的副本不會均勻分布在機架上。三分之一的副本位於一個節點上,三分之二的副本位於一個機架上,另三分之一均勻分布在其余機架上。此策略在不影響數據可靠性或讀取性能的情況下提高了寫入性能。
第一個副本在Client所處的節點上,如果客戶端在集群外,隨機選一個。
第二個副本在另一個機架的隨機一個節點
第三個副本在第二個副本所在機架的隨機節點
HDFS讀數據流程
(1)客戶端通過DistributedFileSystem向NameNode請求下載文件,NameNode通過查詢元數據,找到文件塊所在的DataNode地址。
(2)挑選一台DataNode(就近原則,然后隨機)服務器,請求讀取數據。
(3)DataNode開始傳輸數據給客戶端(從磁盤里面讀取數據輸入流,以Packet為單位來做校驗)。
(4)客戶端以Packet為單位接收,先在本地緩存,然后寫入目標文件。
NameNode和SecondaryNameNode(面試常問)
NN和2NN工作機制
NameNode中的元數據存儲在哪里
首先假設存儲在NameNode節點的磁盤中,因為經常需要進行隨機訪問,還有響應客戶請求,必然是效率過低。因此,元數據需要存放在內存中。但如果只存在內存中,一旦斷電,元數據丟失,整個集群就無法工作。因此產生了在磁盤中備份元數據的FsImage。
這樣又會帶來新的問題,當在內存中的元數據更新時,如果同時更新FsImage,就會導致效率過低,但如果不更新,就會發生一致性問題,一旦NameNode節點斷電,就會產生數據丟失。因此,引入Edits文件(只進行追加操作,效率很高)。每當元數據有更新或者添加元數據時,修改內存中的元數據並追加到Edits中。這樣,一旦NameNode節點斷電,可以通過FsImage和Edits的合並,合成元數據。
但是,如果長時間添加數據到Edits中,會導致該文件數據過大,效率降低,而且一旦斷電,恢復元數據需要的時間過長。因此,需要定期進行FsImage和Edits的合並,如果這個操作由NameNode節點完成,又會效率過低。因此,引入一個新的節點SecondaryNamenode,專門用於FsImage和Edits的合並。
- NN和2NN工作流程
第一階段:NameNode啟動
(1)第一次啟動NameNode格式化后,創建Fsimage和Edits文件。如果不是第一次啟動,直接加載編輯日志和鏡像文件到內存。
(2)客戶端對元數據進行增刪改的請求。
(3)NameNode記錄操作日志,更新滾動日志。
(4)NameNode在內存中對元數據進行增刪改。
2)第二階段:Secondary NameNode工作
(1)Secondary NameNode詢問NameNode是否需要CheckPoint。直接帶回NameNode是否檢查結果。
(2)Secondary NameNode請求執行CheckPoint。
(3)NameNode滾動正在寫的Edits日志。
(4)將滾動前的編輯日志和鏡像文件拷貝到Secondary NameNode。
(5)Secondary NameNode加載編輯日志和鏡像文件到內存,並合並。
(6)生成新的鏡像文件fsimage.chkpoint。
(7)拷貝fsimage.chkpoint到NameNode。
(8)NameNode將fsimage.chkpoint重新命名成fsimage。
- NN和2NN工作機制詳解
Fsimage:NameNode內存中元數據序列化后形成的文件。
Edits:記錄客戶端更新元數據信息的每一步操作(可通過Edits運算出元數據)。
NameNode啟動時,先滾動Edits並生成一個空的edits.inprogress,然后加載Edits和Fsimage到內存中,此時NameNode內存就持有最新的元數據信息。Client開始對NameNode發送元數據的增刪改的請求,這些請求的操作首先會被記錄到edits.inprogress中(查詢元數據的操作不會被記錄在Edits中,因為查詢操作不會更改元數據信息),如果此時NameNode掛掉,重啟后會從Edits中讀取元數據的信息。然后,NameNode會在內存中執行元數據的增刪改的操作。
由於Edits中記錄的操作會越來越多,Edits文件會越來越大,導致NameNode在啟動加載Edits時會很慢,所以需要對Edits和Fsimage進行合並(所謂合並,就是將Edits和Fsimage加載到內存中,照着Edits中的操作一步步執行,最終形成新的Fsimage)。SecondaryNameNode的作用就是幫助NameNode進行Edits和Fsimage的合並工作。
SecondaryNameNode首先會詢問NameNode是否需要CheckPoint(觸發CheckPoint需要滿足兩個條件中的任意一個,定時時間到和Edits中數據寫滿了)。直接帶回NameNode是否檢查結果。SecondaryNameNode執行CheckPoint操作,首先會讓NameNode滾動Edits並生成一個空的edits.inprogress,滾動Edits的目的是給Edits打個標記,以后所有新的操作都寫入edits.inprogress,其他未合並的Edits和Fsimage會拷貝到SecondaryNameNode的本地,然后將拷貝的Edits和Fsimage加載到內存中進行合並,生成fsimage.chkpoint,然后將fsimage.chkpoint拷貝給NameNode,重命名為Fsimage后替換掉原來的Fsimage。NameNode在啟動時就只需要加載之前未合並的Edits和Fsimage即可,因為合並過的Edits中的元數據信息已經被記錄在Fsimage中。
Fsimage和Edits解析
NameNode被格式化之后,將在/opt/module/hadoop-3.1.3/data/dfs/name/current目錄中產生如下文件
[hadoop@hadoop102 ~]$ cd /opt/module/hadoop-3.1.3/data/dfs/name/current
[hadoop@hadoop102 current]$ ll
total 3204
-rw-rw-r--. 1 hadoop hadoop 42 Nov 24 21:44 edits_0000000000000000001-0000000000000000002
-rw-rw-r--. 1 hadoop hadoop 1048576 Nov 24 22:17 edits_0000000000000000003-0000000000000000065
-rw-rw-r--. 1 hadoop hadoop 42 Nov 24 22:37 edits_0000000000000000066-0000000000000000067
-rw-rw-r--. 1 hadoop hadoop 35639 Nov 24 23:37 edits_0000000000000000068-0000000000000000343
-rw-rw-r--. 1 hadoop hadoop 42 Nov 25 00:37 edits_0000000000000000344-0000000000000000345
-rw-rw-r--. 1 hadoop hadoop 1048576 Nov 25 00:37 edits_0000000000000000346-0000000000000000346
-rw-rw-r--. 1 hadoop hadoop 1989 Nov 28 05:31 edits_0000000000000000347-0000000000000000371
-rw-rw-r--. 1 hadoop hadoop 799 Nov 28 17:22 edits_0000000000000000372-0000000000000000384
-rw-rw-r--. 1 hadoop hadoop 278 Nov 28 18:22 edits_0000000000000000385-0000000000000000390
-rw-rw-r--. 1 hadoop hadoop 42 Nov 28 19:22 edits_0000000000000000391-0000000000000000392
-rw-rw-r--. 1 hadoop hadoop 1124 Nov 28 20:22 edits_0000000000000000393-0000000000000000409
-rw-rw-r--. 1 hadoop hadoop 3261 Nov 28 21:22 edits_0000000000000000410-0000000000000000455
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 08:54 edits_0000000000000000456-0000000000000000457
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 09:54 edits_0000000000000000458-0000000000000000459
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 10:54 edits_0000000000000000460-0000000000000000461
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 11:54 edits_0000000000000000462-0000000000000000463
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 12:54 edits_0000000000000000464-0000000000000000465
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 14:07 edits_0000000000000000466-0000000000000000467
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 15:07 edits_0000000000000000468-0000000000000000469
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 16:07 edits_0000000000000000470-0000000000000000471
-rw-rw-r--. 1 hadoop hadoop 42 Nov 29 19:54 edits_0000000000000000472-0000000000000000473
-rw-rw-r--. 1 hadoop hadoop 1048576 Nov 29 19:54 edits_inprogress_0000000000000000474
-rw-rw-r--. 1 hadoop hadoop 2813 Nov 29 16:07 fsimage_0000000000000000471
-rw-rw-r--. 1 hadoop hadoop 62 Nov 29 16:07 fsimage_0000000000000000471.md5
-rw-rw-r--. 1 hadoop hadoop 2813 Nov 29 19:54 fsimage_0000000000000000473
-rw-rw-r--. 1 hadoop hadoop 62 Nov 29 19:54 fsimage_0000000000000000473.md5
-rw-rw-r--. 1 hadoop hadoop 4 Nov 29 19:54 seen_txid
-rw-rw-r--. 1 hadoop hadoop 219 Nov 28 04:41 VERSION
(1)Fsimage文件:HDFS文件系統元數據的一個永久性的檢查點,其中包含HDFS文件系統的所有目錄和文件inode的序列化信息
(2)Edits文件:存放HDFS文件系統的所有更新操作的路徑,文件系統客戶端執行的所有寫操作首先會被記錄到Edits文件中。
(3)seen_txid文件保存的是一個數字,就是最后一個edits_的數字
(4)每次NameNode啟動的時候都會將Fsimage文件讀入內存,加載Edits里面的更新操作,保證內存中的元數據信息是最新的、同步的,可以看成NameNode啟動的時候就將Fsimage和Edits文件進行了合並。
- oiv查看Fsimage文件
查看oiv和oev命令
[hadoop@hadoop102 current]$ hdfs
oev apply the offline edits viewer to an edits file
oiv apply the offline fsimage viewer to an fsimage
基本語法
hdfs oiv -p 文件類型 -i鏡像文件 -o 轉換后文件輸出路徑
測試
[hadoop@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000471 -o /opt/module/hadoop-3.1.3/fsimage.xml
2021-11-29 20:13:14,851 INFO offlineImageViewer.FSImageHandler: Loading 3 strings
將顯示的xml文件內容拷貝到本地並格式化。部分顯示結果如下。
<?xml version="1.0"?>
<fsimage>
<version>
<layoutVersion>-64</layoutVersion>
<onDiskVersion>1</onDiskVersion>
<oivRevision>ba631c436b806728f8ec2f54ab1e289526c90579</oivRevision>
</version>
<NameSection>
<namespaceId>1088051622</namespaceId>
<genstampV1>1000</genstampV1>
<genstampV2>1055</genstampV2>
<genstampV1Limit>0</genstampV1Limit>
<lastAllocatedBlockId>1073741879</lastAllocatedBlockId>
<txid>471</txid>
</NameSection>
<ErasureCodingSection>
<erasureCodingPolicy>
<policyId>1</policyId>
<policyName>RS-6-3-1024k</policyName>
<cellSize>1048576</cellSize>
<policyState>DISABLED</policyState>
<ecSchema>
<codecName>rs</codecName>
<dataUnits>6</dataUnits>
<parityUnits>3</parityUnits>
</ecSchema>
</erasureCodingPolicy>
<erasureCodingPolicy>
<policyId>2</policyId>
<policyName>RS-3-2-1024k</policyName>
<cellSize>1048576</cellSize>
<policyState>DISABLED</policyState>
<ecSchema>
<codecName>rs</codecName>
<dataUnits>3</dataUnits>
<parityUnits>2</parityUnits>
</ecSchema>
</erasureCodingPolicy>
根據上面內容可以看出,Fsimage中沒有記錄塊所對應DataNode,是因為在集群啟動后,DataNode會上報數據塊信息,並每間隔一段時間后再次上報。
- oev查看Edits文件
基本語法
hdfs oev -p 文件類型 -i編輯日志 -o 轉換后文件輸出路徑
測試
[hadoop@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000410-0000000000000000455 -o /opt/module/hadoop-3.1.3/edits1.xml
[hadoop@hadoop102 current]$ cat seen_txid
將顯示的xml文件內容拷貝到本地並格式化。部分顯示結果如下。
<EDITS>
<EDITS_VERSION>-64</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>410</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_MKDIR</OPCODE>
<DATA>
<TXID>411</TXID>
<LENGTH>0</LENGTH>
<INODEID>16495</INODEID>
<PATH>/2021/11/29</PATH>
<TIMESTAMP>1638102837152</TIMESTAMP>
<PERMISSION_STATUS>
<USERNAME>hadoop</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>493</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>412</TXID>
<LENGTH>0</LENGTH>
<INODEID>16496</INODEID>
<PATH>/banzhang.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1638103086863</MTIME>
<ATIME>1638103086863</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_1092320594_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.194.1</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>hadoop</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<ERASURE_CODING_POLICY_ID>0</ERASURE_CODING_POLICY_ID>
<RPC_CLIENTID>cd9f778c-8bc3-45e2-ba7d-0ff04ace0e45</RPC_CLIENTID>
<RPC_CALLID>1</RPC_CALLID>
</DATA>
</RECORD>
NameNode如何確定下次開機啟動的時候合並哪些Edits,
NameNode 每次會合並編號最靠后的 Edits
CheckPoint時間設置
通常情況下,SecondaryNameNode每隔一小時執行一次。
[hdfs-default.xml]
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600s</value>
</property>
一分鍾檢查一次操作次數,當操作次數達到1百萬時,SecondaryNameNode執行一次。
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作動作次數</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60s</value>
<description> 1分鍾檢查一次操作次數</description>
</property >
NameNode故障處理(了解)
NameNode故障后,可以采用如下兩種方法恢復數據。
- 將SecondaryNameNode中數據拷貝到NameNode存儲數據的目錄;
(1)kill -9 NameNode進程
(2)刪除NameNode存儲的數據(/opt/module/hadoop-3.1.3/data/dfs/name)
[hadoop@hadoop102 hadoop-3.1.3]$ rm -rf /opt/module/hadoop-3.1.3/data/name/*
(3)拷貝SecondaryNameNode中數據到原NameNode存儲數據目錄
[atguigu@hadoop104 dfs]$ scp -r hadoop@hadoop102:/opt/module/hadoop-3.1.3/data/namesecondary/* ./name/
(4)重新啟動NameNode
[hadoop@hadoop102 hadoop-3.1.3]$ hdfs --daemon start namenode
- 使用-importCheckpoint選項啟動NameNode守護進程,從而將SecondaryNameNode中數據拷貝到NameNode目錄中。
(1)修改hdfs-site.xml中的
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>120</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/module/hadoop-3.1.3/data/dfs/name</value>
</property>
(2)kill -9 NameNode進程
(3)刪除NameNode存儲的數據(/opt/module/hadoop-3.1.3/data/name)
[hadoop@hadoop102 hadoop-3.1.3]$ rm -rf /opt/module/hadoop-3.1.3/data/dfs/name/*
(4)如果SecondaryNameNode不和NameNode在一個主機節點上,需要將SecondaryNameNode存儲數據的目錄拷貝到NameNode存儲數據的平級目錄,並刪除in_use.lock文件
[hadoop@hadoop102 dfs]$ scp -r hadoop@hadoop104:/opt/module/hadoop-3.1.3/data/dfs/namesecondary ./
[hadoop@hadoop102 namesecondary]$ rm -rf in_use.lock
[hadoop@hadoop102 dfs]$ pwd
/opt/module/hadoop-3.1.3/data/dfs
[hadoop@hadoop102 dfs]$ ls
data name namesecondary
(5)導入檢查點數據(等待一會ctrl+c結束掉)
[hadoop@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode -importCheckpoint
(6)啟動NameNode
[hadoop@hadoop102 hadoop-3.1.3]$ hdfs --daemon start namenode
集群安全模式
- 安全模式描述
1、NameNode啟動
NameNode啟動時,首先將鏡像文件(Fsimage)載入內存,並執行編輯日志(Edits)中的各項操作。一旦在內存中成功建立文件系統元數據的映像,則創建一個空的編輯日志。此時,NameNode開始監聽DataNode請求。這個過程期間,NameNode一直運行在安全模式,即NameNode的文件系統對於客戶端來說是只讀的。
2、DataNode啟動
系統中的數據塊的位置並不是由NameNode維護的,而是以塊列表的形式存儲在DataNode中。在系統的正常操作期間,NameNode會在內存中保留所有塊位置的映射信息。在安全模式下,各個DataNode會向NameNode發送最新的塊列表信息,NameNode了解到足夠多的塊位置信息之后,即可高效運行文件系統。
3、安全模式退出判斷
如果滿足"最小副本條件",NameNode會在30秒鍾之后就退出安全模式。所謂的最小副本條件指的是在整個文件系統中99.9%的塊滿足最小副本級別(默認值:dfs.replication.min=1)。
在啟動一個剛剛格式化的HDFS集群時,因為系統中還沒有任何塊,所以NameNode不會進入安全模式。
- 安全模式測試
基本語法
集群處於安全模式,不能執行重要操作(寫操作)。集群啟動完成后,自動退出安全模式。
(1)bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式狀態)
(2)bin/hdfs dfsadmin -safemode enter (功能描述:進入安全模式狀態)
(3)bin/hdfs dfsadmin -safemode leave (功能描述:離開安全模式狀態)
(4)bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式狀態)
案例測試
1)查看當前模式
[hadoop@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -safemode get
Safe mode is OFF
2)先進入安全模式
[atguigu@hadoop102 hadoop-3.1.3]$ bin/hdfs dfsadmin -safemode enter
3)創建並執行下面的腳本
在/opt/module/hadoop-3.1.3路徑上,編輯一個腳本safemode.sh
[hadoop@hadoop102 hadoop-3.1.3]$ touch safemode.sh
[hadoop@hadoop102 hadoop-3.1.3]$ vim safemode.sh
#!/bin/bash
hdfs dfsadmin -safemode wait
hdfs dfs -put /opt/module/hadoop-3.1.3/README.txt /
[hadoop@hadoop102 hadoop-3.1.3]$ chmod 777 safemode.sh
[hadoop@hadoop102 hadoop-3.1.3]$ ./safemode.sh
4)再打開一個窗口,執行
[hadoop@hadoop102 hadoop-3.1.3]$ bin/hdfs dfsadmin -safemode leave
5)觀察
6)再觀察上一個窗口
Safe mode is OFF
7)HDFS集群上已經有上傳的數據了。
NameNode多目錄配置(了解)
NameNode的本地目錄可以配置成多個,且每個目錄存放內容相同,增加了可靠性
具體配置如下
(1)在hdfs-site.xml文件中添加如下內容
<name>dfs.namenode.name.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/name1,file://${hadoop.tmp.dir}/dfs/name2</value>
</property>
(2)停止集群,刪除三台節點的data和logs中所有數據。
[hadoop@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/
[hadoop@hadoop103 hadoop-3.1.3]$ rm -rf data/ logs/
[hadoop@hadoop104 hadoop-3.1.3]$ rm -rf data/ logs/
(3)格式化集群並啟動。
[hadoop@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode –format
[hadoop@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh
(4)查看結果
[hadoop@hadoop102 dfs]$ ll
總用量 12
drwx------. 3 atguigu atguigu 4096 12月 11 08:03 data
drwxrwxr-x. 3 atguigu atguigu 4096 12月 11 08:03 name1
drwxrwxr-x. 3 atguigu atguigu 4096 12月 11 08:03 name2
DataNode(面試常問)
DataNode工作機制
(1)一個數據塊在DataNode上以文件形式存儲在磁盤上,包括兩個文件,一個是數據本身,一個是元數據,元數據包括數據塊的長度,塊數據的校驗和,以及時間戳。
(2)DataNode啟動后向NameNode注冊,並周期性(1小時)的向NameNode上報所有的塊信息。
(3)心跳是每3秒一次,心跳返回結果帶有NameNode給該DataNode的命令如復制塊數據到另一台機器,或刪除某個數據塊。如果超過10分鍾沒有收到某個DataNode的心跳,則認為該節點不可用。
(4)集群運行中可以安全加入和退出一些機器。
數據完整性
假設電腦磁盤里面存儲的數據是控制高鐵信號燈的紅燈信號(1)和綠燈信號(0),如果存儲該數據的磁盤壞了,一直顯示是綠燈,就會很危險。同理DataNode節點上的數據損壞了,NameNode沒有發現,也是很危險的。
如下是DataNode節點保證數據完整性的方法。
(1)當DataNode讀取Block的時候,它會計算CheckSum。
(2)如果計算后的CheckSum,與Block創建時值不一樣,說明Block已經損壞。
(3)Client讀取其他DataNode上的Block。
(4)常見的校驗算法 crc(32),md5(128),sha1(160)
(5)DataNode在其文件創建后周期驗證CheckSum。
掉線時限參數設置
1、DataNode進程死亡或者網絡故障造成DataNode無法與NameNode通信
2、NameNode不會立即把該節點判定為死亡,要經過一段時間,這段時間暫稱作超時時長。
3、HDFS默認的超時時長為10分鍾+30秒。
4、如果定義超時時間為TimeOut,則超時時長的計算公式為:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
而默認的dfs.namenode.heartbeat.recheck-interval 大小為5分鍾,dfs.heartbeat.interval默認為3秒。
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的單位為毫秒,dfs.heartbeat.interval的單位為秒。
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
</property>
服役新數據節點
- 需求
隨着公司業務的增長,數據量越來越大,原有的數據節點的容量已經不能滿足存儲數據的需求,需要在原有集群基礎上動態添加新的數據節點。
- 環境准備
(1)在hadoop104主機上再克隆一台hadoop105主機
(2)修改IP地址和主機名稱
(3)刪除原來HDFS文件系統留存的文件(/opt/module/hadoop-3.1.3/data和logs)
(4)source一下配置文件
[atguigu@hadoop105 hadoop-3.1.3]$ source /etc/profile
- 服役新節點具體步驟
直接啟動DataNode,即可關聯到集群
[hadoop@hadoop105 hadoop-3.1.3]$ hdfs --daemon start datanode
[hadoop@hadoop105 hadoop-3.1.3]$ yarn --daemon start nodemanager
在hadoop105上上傳文件
[hadoop@hadoop105 hadoop-3.1.3]$ hadoop fs -put /opt/module/hadoop-3.1.3/LICENSE.txt /
如果數據不均衡,可以用命令實現集群的再平衡
[hadoop@hadoop102 sbin]$ ./start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-atguigu-balancer-hadoop102.out
Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved
退役舊數據節點
- 添加白名單和黑名單
白名單和黑名單是hadoop管理集群主機的一種機制。
添加到白名單的主機節點,都允許訪問NameNode,不在白名單的主機節點,都會被退出。添加到黑名單的主機節點,不允許訪問NameNode,會在數據遷移后退出。
實際情況下,白名單用於確定允許訪問NameNode的DataNode節點,內容配置一般與workers文件內容一致。 黑名單用於在集群運行過程中退役DataNode節點。
- 配置白名單和黑名單的具體步驟如下:
1)在NameNode節點的/opt/module/hadoop-3.1.3/etc/hadoop目錄下分別創建whitelist 和blacklist文件
[hadoop@hadoop102 hadoop]$ pwd
/opt/module/hadoop-3.1.3/etc/hadoop
[hadoop@hadoop102 hadoop]$ touch whitelist
[hadoop@hadoop102 hadoop]$ touch blacklist
在whitelist中添加如下主機名稱,假如集群正常工作的節點為102 103 104 105
hadoop102
hadoop103
hadoop104
hadoop105
黑名單暫時為空。
2)在hdfs-site.xml配置文件中增加dfs.hosts和 dfs.hosts.exclude配置參數
<value>/opt/module/hadoop-3.1.3/etc/hadoop/whitelist</value>
<name>dfs.hosts.exclude</name>
<value>/opt/module/hadoop-3.1.3/etc/hadoop/blacklist</value>
3)分發配置文件whitelist,blacklist,hdfs-site.xml (注意:105節點也要發一份)
[hadoop@hadoop102 etc]$ xsync hadoop/
[hadoop@hadoop102 etc]$ rsync -av hadoop/ atguigu@hadoop105:/opt/module/hadoop-3.1.3/etc/hadoop/
4)重新啟動集群(注意:105節點沒有添加到workers,因此要單獨起停)
[hadoop@hadoop102 hadoop-3.1.3]$ stop-dfs.sh
[hadoop@hadoop102 hadoop-3.1.3]$ start-dfs.sh
[hadoop@hadoop105 hadoop-3.1.3]$ hdfs –daemon start datanode
1)編輯/opt/module/hadoop-3.1.3/etc/hadoop目錄下的blacklist文件
[hadoop@hadoop102 hadoop] vim blacklist
[hadoop@hadoop102 etc]$ xsync hadoop/
[hadoop@hadoop102 etc]$ rsync -av hadoop/ atguigu@hadoop105:/opt/module/hadoop-3.1.3/etc/hadoop/
3)刷新NameNode、刷新ResourceManager
[hadoop@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -refreshNodes
[hadoop@hadoop102 hadoop-3.1.3]$ yarn rmadmin -refreshNodes
17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033
4)檢查Web瀏覽器,退役節點的狀態為decommission in progress(退役中),說明數據節點正在復制塊到其他節點
5)等待退役節點狀態為decommissioned(所有塊已經復制完成),停止該節點及節點資源管理器。注意:如果副本數是3,服役的節點小於等於3,是不能退役成功的,需要修改副本數后才能退役
[hadoop@hadoop105 hadoop-3.1.3]$ hdfs --daemon stop datanode
[hadoop@hadoop105 hadoop-3.1.3]$ yarn --daemon stop nodemanager
[hadoop@hadoop102 hadoop-3.1.3]$ sbin/start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-atguigu-balancer-hadoop102.out
Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being Moved
注意:不允許白名單和黑名單中同時出現同一個主機名稱,既然使用了黑名單blacklist成功退役了hadoop105節點,因此要將白名單whitelist里面的hadoop105去掉。
DataNode多目錄配置
DataNode可以配置成多個目錄,每個目錄存儲的數據不一樣。即:數據不是副本
<name>dfs.datanode.data.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/data1,file://${hadoop.tmp.dir}/dfs/data2</value>
(2)停止集群,刪除三台節點的data和logs中所有數據。
[hadoop@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/
[hadoop@hadoop103 hadoop-3.1.3]$ rm -rf data/ logs/
[hadoop@hadoop104 hadoop-3.1.3]$ rm -rf data/ logs/
[hadoop@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode –format
[hadoop@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh
drwx------. 3 atguigu atguigu 4096 4月 4 14:22 data1
drwx------. 3 atguigu atguigu 4096 4月 4 14:22 data2