本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,博主爲石山園,博客地址爲 http://www.cnblogs.com/shishanyuan 。該系列課程是應邀實驗樓整理編寫的,這裏須要贊一下實驗樓提供了學習的新方式,能夠邊看博客邊上機實驗,課程地址爲 https://www.shiyanlou.com/courses/237java
【注】該系列所使用到安裝包、測試數據和代碼都可在百度網盤下載,具體地址爲 http://pan.baidu.com/s/10PnDs,下載該PDF文件node
部署節點操做系統爲CentOS,防火牆和SElinux禁用,建立了一個shiyanlou用戶並在系統根目錄下建立/app目錄,用於存放Hadoop等組件運行包。由於該目錄用於安裝hadoop等組件程序,用戶對shiyanlou必須賦予rwx權限(通常作法是root用戶在根目錄下建立/app目錄,並修改該目錄擁有者爲shiyanlou(chown –R shiyanlou:shiyanlou /app)。linux
Hadoop搭建環境:apache
l 虛擬機操做系統: CentOS6.6 64位,單核,1G內存服務器
l JDK:1.7.0_55 64位架構
l Hadoop:1.1.2app
HDFS(Hadoop Distributed File System)是一個分佈式文件系統,是谷歌的GFS山寨版本。它具備高容錯性並提供了高吞吐量的數據訪問,很是適合大規模數據集上的應用,它提供了一個高度容錯性和高吞吐量的海量數據存儲解決方案。分佈式
l高吞吐量訪問:HDFS的每一個Block分佈在不一樣的Rack上,在用戶訪問時,HDFS會計算使用最近和訪問量最小的服務器給用戶提供。因爲Block在不一樣的Rack上都有備份,因此再也不是單數據訪問,因此速度和效率是很是快的。另外HDFS能夠並行從服務器集羣中讀寫,增長了文件讀寫的訪問帶寬。ide
l高容錯性:系統故障是不可避免的,如何作到故障以後的數據恢復和容錯處理是相當重要的。HDFS經過多方面保證數據的可靠性,多份複製而且分佈到物理位置的不一樣服務器上,數據校驗功能、後臺的連續自檢數據一致性功能都爲高容錯提供了可能。oop
l線性擴展:由於HDFS的Block信息存放到NameNode上,文件的Block分佈到DataNode上,當擴充的時候僅僅添加DataNode數量,系統能夠在不中止服務的狀況下作擴充,不須要人工干預。
如上圖所示HDFS是Master和Slave的結構,分爲NameNode、Secondary NameNode和DataNode三種角色。
lNameNode:在Hadoop1.X中只有一個Master節點,管理HDFS的名稱空間和數據塊映射信息、配置副本策略和處理客戶端請求;
lSecondary NameNode:輔助NameNode,分擔NameNode工做,按期合併fsimage和fsedits並推送給NameNode,緊急狀況下可輔助恢復NameNode;
lDataNode:Slave節點,實際存儲數據、執行數據塊的讀寫並彙報存儲信息給NameNode;
1. 客戶端經過調用FileSystem對象的open()方法來打開但願讀取的文件,對於HDFS來講,這個對象時分佈文件系統的一個實例;
2. DistributedFileSystem經過使用RPC來調用NameNode以肯定文件起始塊的位置,同一Block按照重複數會返回多個位置,這些位置按照Hadoop集羣拓撲結構排序,距離客戶端近的排在前面;
3. 前兩步會返回一個FSDataInputStream對象,該對象會被封裝成DFSInputStream對象,DFSInputStream能夠方便的管理datanode和namenode數據流,客戶端對這個輸入流調用read()方法;
4. 存儲着文件起始塊的DataNode地址的DFSInputStream隨即鏈接距離最近的DataNode,經過對數據流反覆調用read()方法,能夠將數據從DataNode傳輸到客戶端;
5. 到達塊的末端時,DFSInputStream會關閉與該DataNode的鏈接,而後尋找下一個塊的最佳DataNode,這些操做對客戶端來講是透明的,客戶端的角度看來只是讀一個持續不斷的流;
6. 一旦客戶端完成讀取,就對FSDataInputStream調用close()方法關閉文件讀取。
1. 客戶端經過調用DistributedFileSystem的create()方法建立新文件;
2. DistributedFileSystem經過RPC調用NameNode去建立一個沒有Blocks關聯的新文件,建立前NameNode會作各類校驗,好比文件是否存在、客戶端有無權限去建立等。若是校驗經過,NameNode會爲建立新文件記錄一條記錄,不然就會拋出IO異常;
3. 前兩步結束後會返回FSDataOutputStream的對象,和讀文件的時候類似,FSDataOutputStream被封裝成DFSOutputStream,DFSOutputStream能夠協調NameNode和Datanode。客戶端開始寫數據到DFSOutputStream,DFSOutputStream會把數據切成一個個小的數據包,並寫入內部隊列稱爲「數據隊列」(Data Queue);
4. DataStreamer會去處理接受Data Queue,它先問詢NameNode這個新的Block最適合存儲的在哪幾個DataNode裏,好比重複數是3,那麼就找到3個最適合的DataNode,把他們排成一個pipeline.DataStreamer把Packet按隊列輸出到管道的第一個Datanode中,第一個DataNode又把Packet輸出到第二個DataNode中,以此類推;
5. DFSOutputStream還有一個對列叫Ack Quene,也是有Packet組成,等待DataNode的收到響應,當Pipeline中的全部DataNode都表示已經收到的時候,這時Akc Quene纔會把對應的Packet包移除掉;
6. 客戶端完成寫數據後調用close()方法關閉寫入流;
7. DataStreamer把剩餘的包都刷到Pipeline裏而後等待Ack信息,收到最後一個Ack後,通知NameNode把文件標示爲已完成。
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官網進行查看:
在Hadoop集羣中編譯並運行《權威指南》中的例3.2,讀取HDFS文件內容。
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 }
使用以下命令啓動Hadoop
cd /app/hadoop-1.1.2/bin
./start-all.sh
在/app/hadoop-1.1.2目錄下使用以下命令創建myclass和input目錄:
cd /app/hadoop-1.1.2
mkdir myclass
mkdir input
進入/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.
使用以下命令在hdfs中創建目錄/class4
hadoop fs -mkdir /class4
hadoop fs -ls /
(若是須要直接使用hadoop命令,須要把/app/hadoop-1.1.2加入到Path路徑中)
把例子文件上傳到hdfs的/class4文件夾中
cd /app/hadoop-1.1.2/input
hadoop fs -copyFromLocal quangle.txt /class4/quangle.txt
hadoop fs -ls /class4
對/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
進入/app/hadoop-1.1.2/myclass目錄,在該目錄中創建FileSystemCat.java代碼文件,命令以下:
cd /app/hadoop-1.1.2/myclass/
vi FileSystemCat.java
輸入代碼內容:
在/app/hadoop-1.1.2/myclass目錄中,使用以下命令編譯代碼:
javac -classpath ../hadoop-core-1.1.2.jar FileSystemCat.java
ls
使用以下命令讀取HDFS中/class4/quangle.txt內容:
hadoop FileSystemCat /class4/quangle.txt
在本地文件系統生成一個大約100字節的文本文件,寫一段程序讀入這個文件並將其第101-120字節的內容寫入HDFS成爲一個新文件。
注意:在編譯前請先刪除中文註釋!
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 }
進入/app/hadoop-1.1.2/myclass目錄,在該目錄中創建LocalFile2Hdfs.java代碼文件,命令以下:
vi LocalFile2Hdfs.java
輸入代碼內容:
在/app/hadoop-1.1.2/myclass目錄中,使用以下命令編譯代碼:
javac -classpath ../hadoop-core-1.1.2.jar LocalFile2Hdfs.java
進入/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.
使用以下命令讀取local2hdfs第101-120字節的內容寫入HDFS成爲一個新文件:
cd /app/hadoop-1.1.2/input
hadoop LocalFile2Hdfs local2hdfs.txt /class4/local2hdfs_part.txt
使用以下命令讀取local2hdfs_part.txt內容:
hadoop fs -cat /class4/local2hdfs_part.txt
測試例子2的反向操做,在HDFS中生成一個大約100字節的文本文件,寫一段程序讀入這個文件,並將其第101-120字節的內容寫入本地文件系統成爲一個新文件。
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 }
進入/app/hadoop-1.1.2/myclass目錄,在該目錄中創建Hdfs2LocalFile.java代碼文件,命令以下:
cd /app/hadoop-1.1.2/myclass/
vi Hdfs2LocalFile.java
輸入代碼內容:
在/app/hadoop-1.1.2/myclass目錄中,使用以下命令編譯代碼:
javac -classpath ../hadoop-core-1.1.2.jar Hdfs2LocalFile.java
進入/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."
在/app/hadoop-1.1.2/input目錄下把該文件上傳到hdfs的/class4/文件夾中
hadoop fs -copyFromLocal hdfs2local.txt /class4/hdfs2local.txt
hadoop fs -ls /class4/
使用以下命令讀取hdfs2local.txt第101-120字節的內容寫入本地文件系統成爲一個新文件:
hadoop Hdfs2LocalFile /class4/hdfs2local.txt hdfs2local_part.txt
使用以下命令讀取hdfs2local_part.txt內容:
cat hdfs2local_part.txt