Hadoop
【親自測試沒問題 於是分享給初學者】
1、Hadoop簡介
1、hadoop的誕生
Nutch和Lucene之父Doug Cutting在2006年完成Hadoop項目。
Hadoop並不是一個單詞,它來源於DougCutting小兒子對所玩的小象玩具牙牙學語的稱呼。就像是google也是由小孩子命名一樣。
後又經過5年的開發,hadoop在所有云計算系統是穩居第一。
Hadoop目前使用最廣泛的版本爲hadoop-0.20版本。目前最新版本爲hadoop-1.03。
Hadoop運行在Linux系統中。在windows上安裝可使用cgywin模擬linux環境。
2、hadoop的組成
hadoop Common – 是hadoop的核心,包括文件系統、遠程調用RPC的序列化函數。
HDFS : 提供高吞吐量的可靠分佈式文件系統是 GFS的開源實現。
Hadoop的文件系統。必須通過hadoop fs 命令來讀取。支持分佈式。
MapReduce : 大型分佈式數據處理模型,是Google MapReduce的開源實現。
合併/計算模型。
其他相關組成:
• Hbase:結構化分部式數據庫。BigTable的開源實現。
• Hive:提供摘要和查詢功能的數據倉庫。
• Cassandra:由Facebook開發分佈式數據倉庫。目前已經捐獻給apache。且apache已經將Cassandra應用到了各種雲計算系統中。
3、hadoop的體系結構
NameNode - 主節點主服務器
SecondaryNameNode– 是輔助nameNode
DataNode -數據保存用的
TackTracker – 接收任務
JobTracker - 分數據 -100M Datanode1,DataNode2,DataNode3
l NameNode:這是hadoop的守護進程(注意是進程JVM)。負責記錄文件是如何分割成數據塊,以及這些數據塊分別存儲到哪些數據節點上。對內存進行集中管理。NameNode在整個hadoop中只有一個。一旦NameNode服務器宕機,整個系統將無法運行。
l DataNode:集羣中的每個從服務器都運行一個DataNode後臺程序。這個後臺程序負責將HDFS數據塊寫到本地的文件系統。
l Secondary NomeNode:用來監控HDFS狀態的輔助後臺程序。如保存NameNode的快照。
l JobTracker:用戶連接應用程序和hadoop。每一個hadoop集羣中只一個 JobTracker,一般它運行在Master節點上。
l TaskTracker:負責與DataNode進行結合。
4、Hadoop的市場
l facebook
l 淘寶
l 360完全
l 京東
l yahoo
l google
l 暴風
2、Hadoop的安裝
Core-site.xml:
官方只提供linux的安裝版本:
目前市場上出現了一種window上的可以安裝的版本。其實是將Linux與hadoop整合的產物。目的是簡化hadoop的安裝。此安裝程序使用的是hadoop-0.20版本+cgywin:
1、hadoop的單機安裝-hadoop4win的安裝方法
Hadoop的使用包括
n 安裝
n 格式化NameNode
n 啓動所有節點
Hadoop4win的安裝方法非常簡單,因爲它就是一個setup安裝程序,只要會點下一步即可。
選擇語言:
接收:
選擇組件:
選擇安裝位置:
等待安裝:
查看hadoop的安裝細節:
安裝細節:
安裝細節:格式化namenode:
安裝細節-測試啓動所有節點:
注意下面的停止順序:
Hadoop安裝完成以後的目錄:
hadoop4win是Linux+jdk+hadoop的安裝目錄。
Var是namenode格式化以後生成的目錄 。即hdfs的目錄。
進入hadoop4win:
|
查看上面文件的配置信息,你對了解hadoop有幫助。
2、啓動hadoop
1、直接使用hadoop的start-haoop
2、使用jsp檢查java進程
如果發現有5個java進程,則說明啓動成功:
或使用ps命令:
3、單個啓動與停止hadoop
啓動和停止hadoop必須要遵循節點的順序。
啓動時按以下順序啓動:(停止時按相反的順序停止)
Namenode
Datanode
Secondarynamenode
Jobtracker
Tasktracker
使用hadoop-daemon.sh start 啓動各節點:
檢查啓動是否成功:
停止:
使用hadoop-daemon.sh stop namenode停止每個節點即可
3、測試訪問
Hadoop啓動以後,訪問50030端口可以訪問jobtracker。
訪問50070端口可以訪問hdfs文件系統。
http://localhost:50030 - Jobtracker
http://localhost:50070 - hdfs
以下是50070
3、hdfs概念與命令
Hdfs是hadoop Distributed file system的縮寫,是hadoop的分佈式文件系統。
Hdfs由hadoop來管理,它不同於普通的文件系統,不能直觀的查找文件,必須要通過hadoop命令操作hdfs。
HDFS是一個主從結構的體系,一個HDFS集羣是由一個名字節點,它是一個管理文件的命名空間和調節客戶端訪問文件的主服務器,當然還有的數據節點,一個節點一個,它來管理存儲。HDFS暴露文件命名空間和允許用戶數據存儲成文件。
內部機制是將一個文件分割成一個或多個的塊,這些塊存儲在一組數據節點中。名字節點操作文件命名空間的文件或目錄操作,如打開,關閉,重命名,等等。它同時確定塊與數據節點的映射。數據節點來負責來自文件系統客戶的讀寫請求。
數據節點同時還要執行塊的創建,刪除,和來自名字節點的塊複製指示。
名字節點和數據節點都是軟件運行在普通的機器之上,機器典型的都是linux,HDFS是用java來寫的,任何支持java的機器都可以運行名字節點或數據節點,利用java語言的超輕便型,很容易將HDFS部署到大範圍的機器上。典型的部署時將有一個專門的機器來運行名字節點軟件,機羣中的其他機器運行一個數據節點實例。體系結構排斥在一個機器上運行多個數據節點的實例,但是實際的部署不會有這種情況。
集羣中只有一個名字節點極大地簡單化了系統的體系。名字節點是仲裁者和所有HDFS的元數據的倉庫。系統設計成用戶的實際數據不經過名字節點。
1、hadoop下的文件操作命令
1 :列出hdfs文件
~# hadoop dfs –ls /
或
~# hadoop fs –ls /
2:將文件上傳到hdfs
以下命令,將本地目錄下的a.txt上傳到hdfs下的wj目錄下,並重命名爲b.txt
Hadoop fs –put a.txt /wj/b.txt
也可以使用copyFromLocal命令將本目錄下的文件上傳到hdfs文件系統中:
3:將hdfs中的文件複製到本地系統中
通過get命令,即可以操作文件也可以操作文件夾:
操作一個文件,將hdfs上的文件/wj/a.txt保存到本地,並取名爲b.txt
以下下載整個文件到當前目錄下來,注意最後的一個點
4:刪除hdsf下的某個文檔
5:其他更多操作,可以通過查幫助獲取
2、MapReduce 範例操作-測試字符統計
先向服務器上傳一文件:
執行統計:
root@linux:/home/wangjian#hadoop fs -copyFromLocal a.txt /wj/a.txt
root@linux:/home/wangjian#cd /opt/hadoop-0.20.2/
root@linux:/opt/hadoop-0.20.2#hadoop jar hadoop-0.20.2-examples.jar wordcount /wj/a.txt /wj/result2
4、查看結果:
默認情況下結果文件名爲:/wj/result2/part-0000
root@linux:/opt/hadoop-0.20.2#hadoop fs -cat /wj/result2/part*
4、Java操作hdfs示例
1、配置Eclipse的插件
(非分佈式,支持本地)
在eclipse3.6中安裝map/redurce插件:
選擇map/red視圖:
選擇添加新地址:
輸入以下信息:
配置成功後顯示在HDFSLocation顯示以下信息:
左圖顯示的都是服務器的hdsf文件系統。可以方便的進行上傳和下載。
2、Java代碼
書寫代碼之前,必須要建立一個新的map/red項目:
1、上傳本地文件到HDFS
創建一個Java源代碼類:
輸入以下代碼:(圖)
源代碼如下:
packagecn.itcast.one;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.FileStatus;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.fs.Path;
/**
* 上傳本地文件到hdfs
*/
public class One{
public static void main(String[] args)throws Exception {
Configuration conf =
new Configuration();
FileSystem hdfs = FileSystem.get(conf);
Path src = new Path("c:/a.txt");//本地文件
Path dst = newPath("/wj");//hdfs文件
hdfs.copyFromLocalFile(src, dst);
System.err.println("文件上傳成功至:"+conf.get("fs.default.name"));
//列出服務器上目前擁有的文件
FileStatus[] fs =hdfs.listStatus(dst);
for(FileStatus f:fs){
System.err.println(f.getPath());
}
}
}
使用map/red運行map方法:
運行完成以後,應該可以/wj/目錄下發現一個新的文本文件:
2、創建HDFS文件
通過FileSystem.create(Pathf)可以在HDFS上創建文件,其中f爲文件的完整路徑:
注意是文件,而不是文件夾。
以下是源代碼:
packagecn.itcast.one;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.FSDataOutputStream;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.fs.Path;
public classCreatePath {
public static void main(String[] args)throws Exception {
Configuration conf =
new Configuration();
FileSystem fs = FileSystem.get(conf);
//在HDSF上創建一個文件
FSDataOutputStreamout=fs.create(new Path("/wj/c.txt"));
//寫入一行數據,必須使用UTF-8
out.writeUTF("Hell使用UTF-8");
out.close();
}
}
3、重命名HDFS文件
4、刪除hdfs文件
通過FileSystem.delete(Path f,Booleanrecursive)可以刪除指定的HDSF文件,其中f 爲完整的路徑,cecursive用來確定是否進行遞歸刪除:
5、查看hdfs最後修改時間
FileSystem.getModificationTime()可以查看HDFS文件的最後修改時間。
6、查看某個HDFS文件是否存在
FileSystem.exists(Pathf)可以查看某個HDFS文件是否存在。
7、查找某個文件在HDFS集羣中的位置
FileSystem.getFileBlockLocations(FileStatusfile,long start,long len)要查找指定文件在HDFS集羣上的位置:
packagecn.itcast.one;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.BlockLocation;
importorg.apache.hadoop.fs.FileStatus;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.fs.Path;
public classFindFile {
public static void main(String[] args)throws Exception {
Configuration conf =
new Configuration();
FileSystem fs =FileSystem.get(conf);
//必須是一個具體的文件
Path path = newPath("/wj/a.txt");
//文件狀態
FileStatus fileStatus =fs.getFileStatus(path);
//文件塊
BlockLocation[] blockLocations=
fs.getFileBlockLocations(fileStatus,0,fileStatus.getLen());
int blockLen =blockLocations.length;
System.err.println(blockLen);
for(int i=0;i<blockLen;i++){
//主機名
String[] hosts =blockLocations[i].getHosts();
for(String host:hosts){
System.err.println(host);
}
}
}
}
8、獲取 HDFS集羣上所有節點名稱
通過DatanodeInfo.getHostName()可以獲取HDFS集羣上的所有節點名稱:
packagecn.itcast.one;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.hdfs.DistributedFileSystem;
importorg.apache.hadoop.hdfs.protocol.DatanodeInfo;
/**
* 獲取所有主機節點
*/
public class GetNodes{
public static void main(String[] args)throws Exception {
Configuration conf =
new Configuration();
FileSystem fs =FileSystem.get(conf);
//強轉成分佈式文件對象
DistributedFileSystem hdfs =
(DistributedFileSystem) fs;
//獲取節點信息-數組
DatanodeInfo[] dis =hdfs.getDataNodeStats();
for(DatanodeInfo info : dis){
String name =info.getHostName();
System.err.println(name);
}
}
}
Configuration
FileSystem
Mapper
Redurcer
3、Map/red的java代碼-wordcount
其實WordCount並不難,只是一下子接觸到了很多的API,有一些陌生,還有就是很傳統的開發相比,map-reduce確實是一種新的編程理 念,爲了讓各位新手少走彎路,我將WordCount中的很多API都做了註釋,其實這些方法搞明白了以後程序就很簡單了,無非就是將一句話分詞,先用 map處理再用reduce處理,最後再main函數中設置一些信息,然後run(),程序就結束了。好了,不廢話,直接上代碼:
主要的幾個核心類說明:
l Mapper<T,T,T,T>- 用於mapper分組處理數據
它可以設置的泛型包括:
n Text :hadoop的Text對應java.lang.String類型
n IntWritable :對應的爲Integer類型。
n LongWritable :對應的爲Long類型。
l Reducer類用於對mapper以後結果進行合併處理:
1、以下自己實現的wordcount代碼:
以下是完整源代碼:
packagecn.itcast.count;
importjava.io.IOException;
importjava.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;
importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class MyWordCount {
//Mapper<KEYIN,VALUEIN, KEYOUT, VALUEOUT>//參數說明
publicstatic class MyMapper extends Mapper<Object,Text,Text, IntWritable>{
privatefinal static IntWritable one = new IntWritable(1);//類似於int類型
privateText word = new Text(); //可以理解成String類型
publicvoid map(Object key, Text value, Context context)
throws IOException ,InterruptedException {
System.err.println(key+","+value);
//默認情況下即根據空格分隔字符串
StringTokenizeritr = new StringTokenizer(value.toString());
while(itr.hasMoreTokens()){
word.set(itr.nextToken());
context.write(word,one);
}
};
}
//Reducer<KEYIN,VALUEIN, KEYOUT, VALUEOUT>
publicstatic class MyReducer
extends Reducer<Text,IntWritable,Text, IntWritable>{
privateIntWritable result = new IntWritable();
protectedvoid reduce(Text key, Iterable<IntWritable> values,
Contextcontext)
throws IOException ,InterruptedException {
System.err.println(key+","+values);
intsum=0;
for(IntWritableval:values){
sum+=val.get();
}
result.set(sum);
context.write(key,result);//這是最後結果
};
}
publicstatic void main(String[] args) throws Exception {
//聲明配置信息
Configurationconf = new Configuration();
//聲明Job
Jobjob = new Job(conf,"Word Count");
//設置工作類
job.setJarByClass(MyWordCount.class);
//設置mapper類
job.setMapperClass(MyMapper.class);
//可選
job.setCombinerClass(MyReducer.class);
//設置合併計算類
job.setReducerClass(MyReducer.class);
//設置key爲String類型
job.setOutputKeyClass(Text.class);
//設置value爲int類型
job.setOutputValueClass(IntWritable.class);
//設置或是接收輸入輸出
FileInputFormat.setInputPaths(job,newPath("/wj/b.txt"));
FileOutputFormat.setOutputPath(job,newPath("/wj/out5"));
//執行
System.exit(job.waitForCompletion(true)?0:1);
}
}
2、用Eclipse運行的結果
3、將文件打成jar包用hadoop jar命令運行的結果
4、在Eclipse中運行時出現的問題解決方案
Cannot run program “chmod”: CreateProcesserror=2
這個是說,不能執行chmod這個命令。
解決方案非常簡單。
1:關閉Eclipse。
2:將cgywin\bin加入到windows的path環境變量中。
3:啓動eclipse再用hadoop運行即可。
5、在Linux上安裝hadoop
在Linux中安裝hadoop包括在獨立的linux系統中安裝hadoop和在linux虛擬機下安裝hadoop。我本人使用後面的方式安裝。即在虛擬機上先安裝linux,然後再將hadoop安裝到linux下。
1、安裝VirtualBox VM虛擬機
(執行setup.exe安裝即可)
2、在Vbox中安裝Linux系統
(略,相信大家都應該會)
3、設置linux與windows的共享目錄
1、在沒有插入網線的情況下選擇網絡模式爲:HostOnly
2、選擇共享目錄:
3、掛載
Linux系統的/mnt目錄是掛載其他共享目錄的位置:
執行以下命令:
在linux上創建一個掛載目錄
掛載:掛載成功以後顯示不同的顏色:
4、安裝ssh
Hadoop運行過程需要管理遠程hadoop守護進程。
1、inux上安裝ssh使用以下命令:在網絡情況下執行一命令即可以安裝
~# sudo apt-get install ssh
如果是在非網絡情況下,則需要.deb或是.gz的安裝包:
(關於如果安裝deb包,請參考ubuntu.doc)
2、設置ssh無密碼登錄
~# ssh-keygen
輸入上面的命令後一路回車即可。
3、拷貝生成的密碼文件,默認生成的密碼文件在用戶名目錄下的.ssh目錄下
~# cd ~/.ssh
~# cat id_rsa.pub authorized_keys
4、測試是否可以無密碼登錄
~# ssh localhost
~# who
一般情況下,第一次登錄會給出一個錯誤提示,退出後再次登錄即可。
配置好ssh以後,建議使用xshell遠程操作linux這樣更加方便。
5、啓動以後輸入以下命令登錄:
5、安裝hadoop
1、進入目錄,將hadoop-0.20.2.tar.gz拷貝到/opt的根目錄下去:
2、進入/opt目錄安裝hadoop
~tar –zxf hadoop-0.20.2.tag.gz
安裝成功後多了一個hadoop-0.20.2目錄:
3、設置linux環境變量
配置文件:/etc/profile
使用vim進行編輯:
~# vim /etc/profile
在最後面的部分追加hadoop的bin目錄:
可以直接拷貝下面的配置,要根據具體情況做出修改:
exportJAVA_HOME=/usr/local/java/jdk1.7.0_02
exportJRE_HOME=/usr/local/java/jdk1.7.0_02/jre
exportCLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$JAVA_HOME:$PATH
exportPATH=/opt/hadoop-0.20.2/bin:$PATH
4、配置完成以後,關閉窗口再將打開一個新的窗口,建議使用xshell進行操作,
輸入hadoop:
如果給出以下提示,說明配置成功:
6、配置hadoop
1、修改$hadoop_home/conf/core-site.xml
使用vim打開編輯:
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/var/hadoop/hadoop-${user.name}</value>
</property>
</configuration>
編輯完成後,使用:wq保存退出。
2、修改$hadoop_home/conf/hdfs.site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
3、修改mepred-site.xml配置文件:
mapred.child.tmp可以是其他目錄。
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
<property>
<name>mapred.child.tmp</name>
<value>/opt/temp</value>
</property>
</configuration>
7、啓動hadoop
1、在啓動hadoop之前必須要先格式化namenode
輸入:
root@linux:/opt/hadoop-0.20.2/bin#hadoop namenode -format
2、使用start-all.sh一次全部啓動
在linux環境下,使用start-all.sh可以一次全部啓動所有的節點,這一點優於在cygwin環境下。可見hadoop確實適合在linux環境下運行:
執行以下命令:
root@linux:/opt/hadoop-0.20.2/bin#start-all.sh
查看是否都啓動成功,使用jps命令:
root@linux:/opt/hadoop-0.20.2/bin#jps
如果5個節點都啓動成功,則可以正常訪問了。
3、測試字符統計
先向服務器上傳一文件:
執行統計:
root@linux:/home/wangjian#hadoop fs -copyFromLocal a.txt /wj/a.txt
root@linux:/home/wangjian#cd /opt/hadoop-0.20.2/
root@linux:/opt/hadoop-0.20.2#hadoop jar hadoop-0.20.2-examples.jar wordcount /wj/a.txt /wj/result2
4、查看結果:
默認情況下結果文件名爲:/wj/result2/part-0000
root@linux:/opt/hadoop-0.20.2#hadoop fs -cat /wj/result2/part*
8、停止hadoop
root@linux:/opt/hadoop-0.20.2#stop-all.sh
9、逐個啓動節點
啓動節點按以下順序進行:
Hadoop-daemon.sh負責單個啓動hadoop的節點:
root@linux:/opt/hadoop-0.20.2# hadoop-daemon.sh start namenode
starting namenode, logging to /opt/hadoop-0.20.2/bin/../logs/hadoop-root-namenode-linux.out
root@linux:/opt/hadoop-0.20.2#hadoop-daemon.sh start datanode
starting datanode, logging to /opt/hadoop-0.20.2/bin/../logs/hadoop-root-datanode-linux.out
root@linux:/opt/hadoop-0.20.2#hadoop-daemon.sh start secondarynamenode
starting secondarynamenode, logging to/opt/hadoop-0.20.2/bin/../logs/hadoop-root-secondarynamenode-linux.out
root@linux:/opt/hadoop-0.20.2#hadoop-daemon.sh start jobtracker
starting jobtracker, logging to/opt/hadoop-0.20.2/bin/../logs/hadoop-root-jobtracker-linux.out
root@linux:/opt/hadoop-0.20.2#hadoop-daemon.sh start tasktracker
starting tasktracker, logging to/opt/hadoop-0.20.2/bin/../logs/hadoop-root-tasktracker-linux.out
啓動時參數爲start即:
Hadoop-daemon.sh start namenode
關閉時參數爲stop:
Hadoop-daemon.sh stop namenode
(安裝好以後,在Eclipse中寫好代碼,將打好的jar文件,放到hadoop的主服務器上,執行。)
6、兩個示例
1、單詞計數:
~# hadoop jar hadoop-example-0.20.2.jar wordcount /data/word.txt /data/out1
2、對一億個uuid進行排序
~# hadoop jar contrib/streamming/hadoop-0.20.2-streamming.jar -mapper ‘cat’ –reducer ‘wc -l’
-input /data/bigdata.txt -output /data/out2
楊文華
18024582664