Hadoop入門進階課程4--HDFS原理及操作


本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,博主為石山園,博客地址為 http://www.cnblogs.com/shishanyuan  。該系列課程是應邀實驗樓整理編寫的,這里需要贊一下實驗樓提供了學習的新方式,可以邊看博客邊上機實驗,課程地址為 https://www.shiyanlou.com/courses/237

【注】該系列所使用到安裝包、測試數據和代碼均可在百度網盤下載,具體地址為 http://pan.baidu.com/s/10PnDs,下載該PDF文件

   1環境說明

部署節點操作系統為CentOS,防火牆和SElinux禁用,創建了一個shiyanlou用戶並在系統根目錄下創建/app目錄,用於存放Hadoop等組件運行包。因為該目錄用於安裝hadoop等組件程序,用戶對shiyanlou必須賦予rwx權限(一般做法是root用戶在根目錄下創建/app目錄,並修改該目錄擁有者為shiyanlou(chown R shiyanlou:shiyanlou /app)。

Hadoop搭建環境:

l  虛擬機操作系統: CentOS6.6  64位,單核,1G內存

l  JDK1.7.0_55 64

l  Hadoop1.1.2

 2、HDFS原理

HDFSHadoop Distributed File System)是一個分布式文件系統,是谷歌的GFS山寨版本。它具有高容錯性並提供了高吞吐量的數據訪問,非常適合大規模數據集上的應用,它提供了一個高度容錯性和高吞吐量的海量數據存儲解決方案。

l高吞吐量訪問:HDFS的每個Block分布在不同的Rack上,在用戶訪問時,HDFS會計算使用最近和訪問量最小的服務器給用戶提供。由於Block在不同的Rack上都有備份,所以不再是單數據訪問,所以速度和效率是非常快的。另外HDFS可以並行從服務器集群中讀寫,增加了文件讀寫的訪問帶寬。

l高容錯性:系統故障是不可避免的,如何做到故障之后的數據恢復和容錯處理是至關重要的。HDFS通過多方面保證數據的可靠性,多份復制並且分布到物理位置的不同服務器上,數據校驗功能、后台的連續自檢數據一致性功能都為高容錯提供了可能。

l線性擴展:因為HDFSBlock信息存放到NameNode上,文件的Block分布到DataNode上,當擴充的時候僅僅添加DataNode數量,系統可以在不停止服務的情況下做擴充,不需要人工干預。

2.1HDFS架構

clip_image001[6]

如上圖所示HDFSMasterSlave的結構,分為NameNodeSecondary NameNodeDataNode三種角色。

lNameNode:在Hadoop1.X中只有一個Master節點,管理HDFS的名稱空間和數據塊映射信息、配置副本策略和處理客戶端請求;

lSecondary NameNode:輔助NameNode,分擔NameNode工作,定期合並fsimagefsedits並推送給NameNode,緊急情況下可輔助恢復NameNode

lDataNodeSlave節點,實際存儲數據、執行數據塊的讀寫並匯報存儲信息給NameNode

 

2.2HDFS讀操作

clip_image003[6]

1.     客戶端通過調用FileSystem對象的open()方法來打開希望讀取的文件,對於HDFS來說,這個對象時分布文件系統的一個實例;

2.     DistributedFileSystem通過使用RPC來調用NameNode以確定文件起始塊的位置,同一Block按照重復數會返回多個位置,這些位置按照Hadoop集群拓撲結構排序,距離客戶端近的排在前面;

3.     前兩步會返回一個FSDataInputStream對象,該對象會被封裝成DFSInputStream對象,DFSInputStream可以方便的管理datanodenamenode數據流,客戶端對這個輸入流調用read()方法;

4.     存儲着文件起始塊的DataNode地址的DFSInputStream隨即連接距離最近的DataNode,通過對數據流反復調用read()方法,可以將數據從DataNode傳輸到客戶端;

5.     到達塊的末端時,DFSInputStream會關閉與該DataNode的連接,然后尋找下一個塊的最佳DataNode,這些操作對客戶端來說是透明的,客戶端的角度看來只是讀一個持續不斷的流;

6.     一旦客戶端完成讀取,就對FSDataInputStream調用close()方法關閉文件讀取。

2.3HDFS寫操作

 

clip_image005[6]

1.     客戶端通過調用DistributedFileSystemcreate()方法創建新文件;

2.     DistributedFileSystem通過RPC調用NameNode去創建一個沒有Blocks關聯的新文件,創建前NameNode會做各種校驗,比如文件是否存在、客戶端有無權限去創建等。如果校驗通過,NameNode會為創建新文件記錄一條記錄,否則就會拋出IO異常;

3.     前兩步結束后會返回FSDataOutputStream的對象,和讀文件的時候相似,FSDataOutputStream被封裝成DFSOutputStreamDFSOutputStream可以協調NameNodeDatanode。客戶端開始寫數據到DFSOutputStreamDFSOutputStream會把數據切成一個個小的數據包,並寫入內部隊列稱為“數據隊列”(Data Queue)

4.     DataStreamer會去處理接受Data Queue,它先問詢NameNode這個新的Block最適合存儲的在哪幾個DataNode里,比如重復數是3,那么就找到3個最適合的DataNode,把他們排成一個pipeline.DataStreamerPacket按隊列輸出到管道的第一個Datanode中,第一個DataNode又把Packet輸出到第二個DataNode中,以此類推;

5.     DFSOutputStream還有一個對列叫Ack Quene,也是有Packet組成,等待DataNode的收到響應,當Pipeline中的所有DataNode都表示已經收到的時候,這時Akc Quene才會把對應的Packet包移除掉;

6.     客戶端完成寫數據后調用close()方法關閉寫入流;

7.     DataStreamer把剩余的包都刷到Pipeline里然后等待Ack信息,收到最后一個Ack后,通知NameNode把文件標示為已完成。

2.4HDFS中常用到的命令

lhadoop fs

hadoop fs -ls /

hadoop fs -lsr

hadoop fs -mkdir /user/hadoop

hadoop fs -put a.txt /user/hadoop/

hadoop fs -get /user/hadoop/a.txt /

hadoop fs -cp src dst

hadoop fs -mv src dst

hadoop fs -cat /user/hadoop/a.txt

hadoop fs -rm /user/hadoop/a.txt

hadoop fs -rmr /user/hadoop/a.txt

hadoop fs -text /user/hadoop/a.txt

hadoop fs -copyFromLocal localsrc dst hadoop fs -put功能類似。

hadoop fs -moveFromLocal localsrc dst 將本地文件上傳到hdfs,同時刪除本地文件。

lhadoop fsadmin

hadoop dfsadmin -report

hadoop dfsadmin -safemode enter | leave | get | wait

hadoop dfsadmin -setBalancerBandwidth 1000

lhadoop fsck

lstart-balancer.sh

 

相關HDFS API可以到Apache官網進行查看:

clip_image007[6]

 3測試例子1

3.1測試例子1內容

Hadoop集群中編譯並運行《權威指南》中的例3.2,讀取HDFS文件內容。

3.2  運行代碼

 1 import java.io.InputStream;
 2 
 3 import java.net.URI;
 4 import org.apache.hadoop.conf.Configuration;
 5 import org.apache.hadoop.fs.*;
 6 import org.apache.hadoop.io.IOUtils;
 7 
 8 public class FileSystemCat {
 9     public static void main(String[] args) throws Exception {
10         String uri = args[0];
11         Configuration conf = new Configuration();
12         FileSystem fs = FileSystem. get(URI.create (uri), conf);
13         InputStream in = null;
14     try {
15             in = fs.open( new Path(uri));
16             IOUtils.copyBytes(in, System.out, 4096, false);
17         } finally {
18             IOUtils.closeStream(in);
19         }
20     }
21 }

 

3.3實現過程

3.3.1創建代碼目錄

使用如下命令啟動Hadoop

cd /app/hadoop-1.1.2/bin

./start-all.sh

/app/hadoop-1.1.2目錄下使用如下命令建立myclassinput目錄:

cd /app/hadoop-1.1.2

mkdir myclass

mkdir input

clip_image009[6]

3.3.2建立例子文件上傳到HDFS

進入/app/hadoop-1.1.2/input目錄,在該目錄中建立quangle.txt文件

cd /app/hadoop-1.1.2/input

touch quangle.txt

vi quangle.txt

內容為:

On the top of the Crumpetty Tree

The Quangle Wangle sat,

But his face you could not see,

On account of his Beaver Hat.

clip_image011[6]

使用如下命令在hdfs中建立目錄/class4

hadoop fs -mkdir /class4

hadoop fs -ls /

(如果需要直接使用hadoop命令,需要把/app/hadoop-1.1.2加入到Path路徑中)

clip_image013[6]

把例子文件上傳到hdfs/class4文件夾中

cd /app/hadoop-1.1.2/input

hadoop fs -copyFromLocal quangle.txt /class4/quangle.txt

hadoop fs -ls /class4

clip_image015[6]

3.3.3配置本地環境

/app/hadoop-1.1.2/conf目錄中的hadoop-env.sh進行配置,如下如所示:

cd /app/hadoop-1.1.2/conf

sudo vi hadoop-env.sh

加入對HADOOP_CLASPATH變量值,值為/app/hadoop-1.1.2/myclass,設置完畢后編譯該配置文件,使配置生效

export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/app/hadoop-1.1.2/myclass

clip_image017[6]

3.3.4編寫代碼

進入/app/hadoop-1.1.2/myclass目錄,在該目錄中建立FileSystemCat.java代碼文件,命令如下:

cd /app/hadoop-1.1.2/myclass/

vi FileSystemCat.java

輸入代碼內容:

clip_image019[6]

3.3.5編譯代碼

/app/hadoop-1.1.2/myclass目錄中,使用如下命令編譯代碼:

javac -classpath ../hadoop-core-1.1.2.jar FileSystemCat.java

ls

clip_image021[6]

3.3.6使用編譯代碼讀取HDFS文件

使用如下命令讀取HDFS/class4/quangle.txt內容:

hadoop FileSystemCat /class4/quangle.txt

clip_image023[6]

 4測試例子2

4.1測試例子2內容

在本地文件系統生成一個大約100字節的文本文件,寫一段程序讀入這個文件並將其第101-120字節的內容寫入HDFS成為一個新文件。

4.2運行代碼

注意:在編譯前請先刪除中文注釋!

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.OutputStream;
 5 import java.net.URI;
 6 
 7 import org.apache.hadoop.conf.Configuration;
 8 import org.apache.hadoop.fs.FSDataInputStream;
 9 import org.apache.hadoop.fs.FileSystem;
10 import org.apache.hadoop.fs.Path;
11 import org.apache.hadoop.io.IOUtils;
12 import org.apache.hadoop.util.Progressable;
13 
14 public class LocalFile2Hdfs {
15     public static void main(String[] args) throws Exception {
16 
17         // 獲取讀取源文件和目標文件位置參數
18         String local = args[0];
19         String uri = args[1];
20         
21         FileInputStream in = null;
22         OutputStream out = null;
23         Configuration conf = new Configuration();
24         try {
25             // 獲取讀入文件數據
26             in = new FileInputStream(new File(local));
27 
28             // 獲取目標文件信息
29             FileSystem fs = FileSystem.get(URI.create(uri), conf);
30             out = fs.create(new Path(uri), new Progressable() {
31                 @Override
32                 public void progress() {
33                     System.out.println("*");
34                 }
35             });
36 
37             // 跳過前100個字符
38             in.skip(100);
39             byte[] buffer = new byte[20];
40                 
41             // 從101的位置讀取20個字符到buffer中
42             int bytesRead = in.read(buffer);
43             if (bytesRead >= 0) {
44                 out.write(buffer, 0, bytesRead);
45             }
46         } finally {
47             IOUtils.closeStream(in);
48             IOUtils.closeStream(out);
49         }        
50     }

 

4.3實現過程

4.3.1編寫代碼

進入/app/hadoop-1.1.2/myclass目錄,在該目錄中建立LocalFile2Hdfs.java代碼文件,命令如下:

cd /app/hadoop-1.1.2/myclass/

vi LocalFile2Hdfs.java

輸入代碼內容:

clip_image025[6]

4.3.2編譯代碼

/app/hadoop-1.1.2/myclass目錄中,使用如下命令編譯代碼:

javac -classpath ../hadoop-core-1.1.2.jar LocalFile2Hdfs.java

clip_image027[6]

4.3.3建立測試文件

進入/app/hadoop-1.1.2/input目錄,在該目錄中建立local2hdfs.txt文件

cd /app/hadoop-1.1.2/input/

vi local2hdfs.txt

內容為:

Washington (CNN) -- Twitter is suing the U.S. government in an effort to loosen restrictions on what the social media giant can say publicly about the national security-related requests it receives for user data.

The company filed a lawsuit against the Justice Department on Monday in a federal court in northern California, arguing that its First Amendment rights are being violated by restrictions that forbid the disclosure of how many national security letters and Foreign Intelligence Surveillance Act court orders it receives -- even if that number is zero.

Twitter vice president Ben Lee wrote in a blog post that it's suing in an effort to publish the full version of a "transparency report" prepared this year that includes those details.

The San Francisco-based firm was unsatisfied with the Justice Department's move in January to allow technological firms to disclose the number of national security-related requests they receive in broad ranges.

clip_image029[6]

4.3.4使用編譯代碼上傳文件內容到HDFS

使用如下命令讀取local2hdfs101-120字節的內容寫入HDFS成為一個新文件:

cd /app/hadoop-1.1.2/input

hadoop LocalFile2Hdfs local2hdfs.txt /class4/local2hdfs_part.txt

clip_image031[6]

4.3.5驗證是否成功

使用如下命令讀取local2hdfs_part.txt內容:

hadoop fs -cat /class4/local2hdfs_part.txt

clip_image033[6]

 5測試例子3

5.1測試例子3內容

測試例子2的反向操作,在HDFS中生成一個大約100字節的文本文件,寫一段程序讀入這個文件,並將其第101-120字節的內容寫入本地文件系統成為一個新文件。

5.2程序代碼

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.OutputStream;
 5 import java.net.URI;
 6 
 7 import org.apache.hadoop.conf.Configuration;
 8 import org.apache.hadoop.fs.FSDataInputStream;
 9 import org.apache.hadoop.fs.FileSystem;
10 import org.apache.hadoop.fs.Path;
11 import org.apache.hadoop.io.IOUtils;
12 
13 public class Hdfs2LocalFile {
14     public static void main(String[] args) throws Exception {
15 
16         String uri = args[0];
17         String local = args[1];
18         
19         FSDataInputStream in = null;
20         OutputStream out = null;
21         Configuration conf = new Configuration();
22         try {
23             FileSystem fs = FileSystem.get(URI.create(uri), conf);
24             in = fs.open(new Path(uri));
25             out = new FileOutputStream(local);
26 
27             byte[] buffer = new byte[20];
28             in.skip(100);
29             int bytesRead = in.read(buffer);
30             if (bytesRead >= 0) {
31                 out.write(buffer, 0, bytesRead);
32             }
33         } finally {
34             IOUtils.closeStream(in);
35             IOUtils.closeStream(out);
36         }    
37     }
38 }

5.3實現過程

5.3.1編寫代碼

進入/app/hadoop-1.1.2/myclass目錄,在該目錄中建立Hdfs2LocalFile.java代碼文件,命令如下:

cd /app/hadoop-1.1.2/myclass/

vi Hdfs2LocalFile.java

輸入代碼內容:

clip_image035[6]

5.3.2編譯代碼

/app/hadoop-1.1.2/myclass目錄中,使用如下命令編譯代碼:

javac -classpath ../hadoop-core-1.1.2.jar Hdfs2LocalFile.java

clip_image037[6]

5.3.3建立測試文件

進入/app/hadoop-1.1.2/input目錄,在該目錄中建立hdfs2local.txt文件

cd /app/hadoop-1.1.2/input/

vi hdfs2local.txt

內容為:

The San Francisco-based firm was unsatisfied with the Justice Department's move in January to allow technological firms to disclose the number of national security-related requests they receive in broad ranges.

"It's our belief that we are entitled under the First Amendment to respond to our users' concerns and to the statements of U.S. government officials by providing information about the scope of U.S. government surveillance -- including what types of legal process have not been received," Lee wrote. "We should be free to do this in a meaningful way, rather than in broad, inexact ranges."

clip_image039[6]

/app/hadoop-1.1.2/input目錄下把該文件上傳到hdfs/class4/文件夾中

hadoop fs -copyFromLocal hdfs2local.txt /class4/hdfs2local.txt

hadoop fs -ls /class4/

clip_image041[6]

5.3.4使用編譯代碼把文件內容從HDFS輸出到文件系統中

使用如下命令讀取hdfs2local.txt101-120字節的內容寫入本地文件系統成為一個新文件:

hadoop Hdfs2LocalFile /class4/hdfs2local.txt hdfs2local_part.txt

clip_image043[6]

5.3.5驗證是否成功

使用如下命令讀取hdfs2local_part.txt內容:

cat hdfs2local_part.txt

clip_image045[6]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM