Hadoop–HDFS

木南。發表於2018-12-20

Hadoop–HDFS

Edits和Fsimage機制詳解

概述

fsimage映象檔案包含了整個HDFS檔案系統的所有目錄和檔案的indoe(節點)資訊,比如:/node01/node,會記錄每個節點nodeid,以及節點之間父子路徑。

以及檔名,檔案大小,檔案被切成幾塊,每個資料塊描述資訊、修改時間、訪問時間等;此外還有對目錄的修改時間、訪問許可權控制資訊(目錄所屬使用者,所在組等)等。

另外,edits檔案主要是在NameNode已經啟動情況下對HDFS進行的各種更新操作進行記錄,比如 :hadoop fs -mkdir hadoop fs -delete hadoop fs -put等。

對於每次事務操作,都會用一個TXID來標識,OP_MKDIR OP_DELETE等。

Edits檔案儲存的操作,而fsimage檔案儲存的是執行操作後,變化的狀態。(後設資料)

HDFS客戶端執行所有的寫操作都會被記錄到edits檔案中。

關鍵點

1.當執行格式化指令時候,會在指定後設資料目錄生成 dfs/name/current/

最開始只有fsimage,沒有edits檔案(因為沒有啟動HDFS)

2.當初次啟動HFDS,會生成edits_inprogress_0000000000000000001,此檔案用於記錄事務(寫操作)

3.HDFS對於每次寫操作,都會用一個事務ID(TXID)來記錄,TXID是遞增的。

4.edits_0000000000000000003-0000000000000000007,數字表示的合併後起始的事務id和終止事務id

5.seen_txid 儲存的當前的事務id,和edits_inprogress最後的數字一致

6.datanode儲存塊的目錄路徑:/tmp/dfs/data/current/BP-859711469-192.168.150.137-1535216211704/current/finalized/subdir0/subdir0

7.finalized此目錄儲存的已經儲存完畢的資料塊,rbw目錄存的是正在寫但還未寫完的資料塊

檢視Edits檔案和Fsimage檔案

hdfs oev -i edits_0000000000000000001-0000000000000000003 -o edits.xml

hdfs oiv -i fsimage_0000000000000000012 -o fsimage.xml -p XML

HDFS API操作

1.建立java工程

2.匯入hadoop依賴jar包

連線namenode以及讀取hdfs中指定檔案
 
 
 
x
 
 
 
 
@Test
public void testConnectNamenode() throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.211:9000"), conf);
InputStream in=fs.open(new Path("/park/1.txt"));
OutputStream out=new FileOutputStream("1.txt");
IOUtils.copyBytes(in, out, conf);
}
 
上傳檔案到hdfs上
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testPut() throws Exception{
Configuration conf=new Configuration();
conf.set("dfs.replication","1");
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
ByteArrayInputStream in=new ByteArrayInputStream("hello hdfs".getBytes());
OutputStream out=fs.create(new Path("/park/2.txt"));
IOUtils.copyBytes(in, out, conf);
}
 
從hdfs上刪除檔案
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testDelete()throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
//true表示無論目錄是否為空,都刪除掉。可以刪除指定的檔案
fs.delete(new Path("/park01"),true);
//false表示只能刪除不為空的目錄。
fs.delete(new Path("/park01"),false);
fs.close();
}
 
在hdfs上建立資料夾
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testMkdir()throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.211:9000"),conf,"root");
fs.mkdirs(new Path("/park02"));
}
 
查詢hdfs指定目錄下的檔案
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testLs()throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.214:9000"),conf,"root");
RemoteIterator<LocatedFileStatus> rt=fs.listFiles(new Path("/"), true);
while(rt.hasNext()){
System.out.println(rt.next());
}
}
 
遞迴檢視指定目錄下的檔案
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testLs()throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.214:9000"),conf,"root");
RemoteIterator<LocatedFileStatus> rt=fs.listFiles(new Path("/"), true);
while(rt.hasNext()){
System.out.println(rt.next());
}
}
 

 

重新命名
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testCreateNewFile() throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.176:9000"),conf,"root");
fs.rename(new Path("/park"), new Path("/park01"));

}
 

 

獲取檔案的塊資訊
 
 
 
xxxxxxxxxx
 
 
 
 
@Test
public void testCopyFromLoaclFileSystem() throws Exception{
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.176:9000"),conf,"root");
BlockLocation[] data=fs.getFileBlockLocations(new Path("/park01/1.txt"),0,Integer.MaxValue);
for(BlockLocation bl:data){
System.out.println(bl);
}
}
 

從HDFS下載檔案過程

1.Client向namenode發起 Open file 請求。目的是獲取指定檔案的輸入流。

namenode收到請求之後,會檢查路徑的合法性,此外,還是檢查客戶端的操作許可權。如果檢測未通過,則直接報錯返回。後續過程不會發生。

2.Client也會向namenode發起:Getblockloaction請求,獲取指定檔案的後設資料資訊。如果第一步的檢測通過,namenode會將後設資料資訊封裝到輸入流裡,返回給客戶端。

3.4 客戶端根據後設資料資訊,直接去對應的datanode讀取檔案塊,然後下載到本地(建立本地的輸出流,然後做流的對接)

5.讀完後,關流。

上傳檔案到HDFS

1.Client向namenode發現 Create file請求,目的是獲取HDFS檔案的輸出流。namenode收到請求後,會檢測路徑的合法性和許可權。如果檢測未通過,直接報錯返回。

如果通過檢測,namenode會將檔案的切塊資訊(比如檔案被切成幾塊,每個檔案塊的副本存在哪臺datanode上),然後把這些資訊封裝到輸出流裡,返回給客戶端。

所以注意:檔案塊的輸出(上傳)是客戶端直接和對應DN互動的,namenode的作用是告訴Client檔案塊要傳送給哪個datanode上。

 

2.Client通過輸出流,傳送檔案塊(底層會將一個檔案塊打散成一個一個的packet,每個packet的大小=64kb)。這個過程的機制,叫Pipeline(資料流管道機制)

這種機制的目的:

為了提高網路效率,我們採取了把資料流和控制流分開的措施。在控制流從客戶機到主Chunk、然後冉 到所有二級副本的同時,資料以管道的方式,順序的沿著一個精心選擇的Chunk伺服器鏈推送。我們的目標 是充分利用每臺機器的頻寬,避免網路瓶頸和高延時的連線,最小化推送所有資料的延時。 為了充分利用每臺機器的頻寬,資料沿著一個Chunk伺服器鏈順序的推送,而不是以其它拓撲形式分散 推送(例如,樹型拓撲結構)。線性推送模式下,每臺機器所有的出凵頻寬都用於以最快的速度傳輸資料,而 不是在多個接受者之間分配頻寬。

3.4.5 。通過資料流管道機制,實現資料的傳送和副本的複製。每臺datanode伺服器收到資料之後,會向上遊反饋ack確認機制。直到第五步的ack傳送給Client之後,再傳送下一個packet。依次迴圈,直到所有的資料都複製完畢。此外,在底層傳輸的過程中,會用到全雙工通訊。

補充:建議看《Google File System》的3.2節

6.資料上傳完之後,關流。

從HDFS刪除檔案的流程

1、客戶端向namenode發現 刪除檔案指令,比如:

 
 
 
xxxxxxxxxx
 
 
 
 
hadoop fs  -rm /park01/1.txt
 

2、namenode收到請求後,會檢查路徑的合法性以及許可權

3、如果檢測通過,會將對應的檔案從後設資料中刪除。(注意,此時這個檔案並沒有真正從叢集上被刪除)

4、每臺datanode會定期向namenode傳送心跳,會領取刪除的指令,找到對應的檔案塊,進行檔案塊的刪除。

HDFS的租約機制

HDFS的有個內部機制:不允許客戶端的並行寫。指的是同一時刻內,不允許多個客戶端向一個HDFS上寫資料。

所以要實現以上的機制,實現思路就是用互斥鎖,但是如果底層要是用簡單的互斥鎖,可能有與網路問題,造成客戶端不釋放鎖,而造成死鎖。所以Hadoop為了避免這種情況產生,引入租約機制。

租約鎖本質上就是一個帶有租期的互斥鎖。

Hadoop的思想來自於Google的論文,3.1

Hadoop 租約鎖對應的類:org.apache.hadoop.hdfs.server.namenode.LeaseManager.Lease

還有一個租約鎖管理者:

org.apache.hadoop.hdfs.server.namenode.LeaseManager

HDFS特點

1、分散式儲存架構,支援海量資料儲存。(GB、TB、PB級別資料)

2、高容錯性,資料塊擁有多個副本(副本冗餘機制)。副本丟失後,自動恢復。

3、低成本部署,Hadoop可構建在廉價的伺服器上。

4、能夠檢測和快速應對硬體故障,通過RPC心跳機制來實現。

5、簡化的一致性模型,這裡指的是使用者在使用HDFS時,所有關於檔案相關的操作,比如檔案切塊、塊的複製、塊的儲存等細節並不需要去關注,所有的工作都已被框架封裝完畢。使用者所需要的做的僅僅是將資料上傳到HDFS。這大大簡化了分散式檔案儲存操作的難度和管理的複雜度。

6、HDFS不能做到低延遲的資料訪問(毫秒級內給出響應)。但是Hadoop的優勢在於它的高吞吐率(吞吐率指的是:單位時間內產生的資料流)。可以說HDFS的設計是犧牲了低延遲的資料訪問,而獲取的是資料的高吞吐率。如果要想獲取低延遲的資料訪問,可以通過Hbase框架來實現。

7、HDFS不許修改資料,所以適用場景是:一次寫入,多次讀取(once-write-many-read)。注意:HDFS允許追加資料,但不允許修改資料。追加和修改的意義是不同的。

8、HDFS不支援併發寫入,一個檔案同一個時間只能有一個寫入者。

9、HDFS不適合儲存海量小檔案,因為會浪費namenode服務節點的記憶體空間

相關文章