我的环境是:Ubuntu14.04+Hadoop2.6.0+JDK1.8.0_25
官网2.6.0的安装教程:http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-common/SingleCluster.html
为了方面配置,我在每台机器上都使用了hadoop用户来操作,这样做的确够方便。
[Mr.Snail注]
Ubuntu 14.04 LTS 创建用户相关命令
# useradd hadoop // 会自动生成一个叫 hadoop 的用户组。请先在所有的集群机器中创建hadoop用户与 /home/hadoop 主目录后再往下走
# cd /home/
# mkdir hadoop //创建hadoop用户主目录 /home/hadoop - Ubuntu LInux 不会在创建用户的时候关联生成用户主目录
结点信息:(分布式集群架构:master为主节点,其余为从节点)
机器名 |
IP |
作用 |
master |
122.205.135.254 |
NameNode and JobTracker |
slave1 |
122.205.135.212 |
DataNode and TaskTracker |
1.JDK的安装
首先Hadoop运行需要Java的支持,所以必须在集群中所有的节点安装JDK,
jdk1.8.0_25的详细安装见我的另一篇文章:http://www.linuxidc.com/Linux/2015-01/112030.htm 注意:最好将集群中的JDK都安装在同一目录下,便于配置。实践中,笔者一般将JDK安装在/usr/java这个目录,但并不是必须的。
2.配置hosts文件
修改集群中所有机器的/etc/hosts,打开该文件的命令如下:
sudo gedit /etc/hosts
添加:
122.205.135.254 master
122.205.135.212 slave1
如图所示:
注意:这里的master、slave1、slave2等等,指的是机器的机器名(使用命令hostname可以查看本机的机器名),切记,如果不是机器名的话会出问题的,并且集群中所有结点的机器名都应该不一样。
3.SSH无密码登录
Hadoop主从节点无密码登录的安装配置详细见我的另一篇章:点击打开链接 [Mr.Snail注]:http://blog.csdn.net/pengych_321/article/details/51159942]
4.Hadoop的安装与配置
(1).下载解压Hadoop稳定版
我用的是hadoop-2.6.0,下载地址:http://mirrors.hust.edu.cn/apache/hadoop/common/stable/
将下载后的Hadoop 拷贝到hadoop目录下,解压到master服务器的/hadoop目录下(配置好master结点后再将其复制到其它的服务器上,一般来说,群集中所有的hadoop都安装在同一目录下):
解压命令如下:
tar xzfv hadoop-2.6.0.tar.gz [Mr.Snail注] 解压后的目录结构: /home/hadoop/hadoop-2.6.0
(2).配置Hadoop [Mr.Snail注] 用hadoop用户修改相关文件会出现:只读文件,不能修改的问题。 先通过以下命令修改权限。
# sudo chgrp -R hadoop ~/hadoop-2.6.0
# sudo chown -R hadoop ~/hadoop-2.6.0
# sudo chmod -R 755 ~/hadoop-2.6.0
1.修改hadoop-2.6.0/etc/hadoop/hadoop-env.sh,添加JDK支持:
export JAVA_HOME=/usr/java/jdk1.8.0_25
如果不知道你的JDK目录,使用命令echo $JAVA_HOME查看。
2.修改hadoop-2.6.0/etc/hadoop/core-site.xml
注意:必须加在<configuration></configuration>节点内
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadoop/hadoop-2.6.0/tmp</value> [Mr.Snail注] 用来指定Hadoop运行时产生文件所存放的位置
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://master:9000</value> ### [Mr.Snail注] 用来指定HDFS的NameNode的位置
</property>
</configuration>
3.修改hadoop-2.6.0/etc/hadoop/hdfs-site.xml
<property>
<name>dfs.name.dir</name>
<value>/home/hadoop/hadoop-2.6.0/dfs/name</value>
<description>Path on the local filesystem where the NameNode stores the namespace and transactions logs persistently.</description>
</property>
<property>
<name>dfs.data.dir</name>
<value>/home/hadoop/hadoop-2.6.0/dfs/data</value>
<description>Comma separated list of paths on the local filesystem of a DataNode where it should store its blocks.</description>
</property>
<property>
<name>dfs.replication</name> ### [Mr.Snail注] 指定HDFS保存数据副本的数量,一般是 3,这里只有一台DATANODE所以设置为
<value>1</value>
</property>
4.修改hadoop-2.6.0/etc/hadoop/mapred-site.xml
<property>
<name>mapred.job.tracker</name>
<value>master:9001</value>
<description>Host or IP and port of JobTracker.</description>
</property>
5. 修改hadoop-2.6.0/etc/hadoop/masters
列出所有的master节点:
master
6.修改hadoop-2.6.0/etc/hadoop/slaves
这个是所有datanode的机器,例如:
slave1
slave2
slave3
slave4
7.将master结点上配置好的hadoop文件夹拷贝到所有的slave结点上
以slave1为例:命令如下:
scp -r ~/hadoop-2.6.0 hadoop@slave1:~/
安装完成后,我们要格式化HDFS然后启动集群所有节点。
5.启动Hadoop
1.格式化HDFS文件系统的namenode
(这里要进入hadoop-2.6.0目录来格式化好些):
cd hadoop-2.6.0 //进入hadoop-2.6.0目录
bin/hdfs namenode -format //格式化 [Mr.Snail注] 最好配置以下环境变量, 将bin目录添加到PATH :
export HADOOP_HOME=/home/hadoop/hadoop-2.6.0
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin
2.启动Hadoop集群
启动hdrs命令如下:
sbin/start-dfs.sh //开启进程
成功的话输入jps会出现如下界面:
补充,关闭hdfs集群的命令如下:
sbin/stop-dfs.sh
我们也可以通过网页来看是否正常安装与配置,地址如下:http://master:50070/
6.实例运行(运行wordcount程序)
1.创建 input目录
在Hadoop-2.6.0目录下创建input目录命令如下:
mkdir input
2.在input创建f1、f2并写内容
命令如下:
cat input/f1 Hello world bye jj
cat input/f2 Hello world bye jj
或者手动创建文本文件,并在里面放下英文文章
3.在hdfs创建/porrylee/input目录
命令如下:
bin/hadoop fs -mkdir /porrylee [Mr.Snail注] 操作系统本身有个文件系统 像 ntfs 、fat等 ,而hdfs是基于操作系统文件系统上的文件系统; fs 是一个客户端程序用于 本地向hdfs发出操作指令
bin/hadoop fs -mkdir /porrylee/input
4.将f1、f2文件copy到hdfs /porrylee/input目录
命令如下:
bin/hadoop fs -put input/ /porrylee
5.查看hdfs上是否有f1、f2文件
命令如下:
bin/hadoop fs -ls /porrylee/input/
6、执行wordcount程序
命令如下:
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0.jar wordcount /porrylee/input/ /output/wordcount3
执行完毕后如下,
7.查看执行结果
命令如下:
hadoop@master:~/hadoop-2.6.0$ bin/hdfs dfs -cat /output/wordcount3/*
执行后,可以看到统计结果
7.附录(核心代码)
package com.felix;
import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.TextInputFormat;
import org.apache.hadoop.mapred.TextOutputFormat;
/**
*
* 描述:WordCount explains by Felix
* @author Hadoop Dev Group
*/
public class WordCount
{
/**
* MapReduceBase类:实现了Mapper和Reducer接口的基类(其中的方法只是实现接口,而未作任何事情)
* Mapper接口:
* WritableComparable接口:实现WritableComparable的类可以相互比较。所有被用作key的类应该实现此接口。
* Reporter 则可用于报告整个应用的运行进度,本例中未使用。
*
*/
public static class Map extends MapReduceBase implements
Mapper<LongWritable, Text, Text, IntWritable>
{
/**
* LongWritable, IntWritable, Text 均是 Hadoop 中实现的用于封装 Java 数据类型的类,这些类实现了WritableComparable接口,
* 都能够被串行化从而便于在分布式环境中进行数据交换,你可以将它们分别视为long,int,String 的替代品。
*/
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
/**
* Mapper接口中的map方法:
* void map(K1 key, V1 value, OutputCollector<K2,V2> output, Reporter reporter)
* 映射一个单个的输入k/v对到一个中间的k/v对
* 输出对不需要和输入对是相同的类型,输入对可以映射到0个或多个输出对。
* OutputCollector接口:收集Mapper和Reducer输出的<k,v>对。
* OutputCollector接口的collect(k, v)方法:增加一个(k,v)对到output
*/
public void map(LongWritable key, Text value,
OutputCollector<Text, IntWritable> output, Reporter reporter)
throws IOException
{
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens())
{
word.set(tokenizer.nextToken());
output.collect(word, one);
}
}
}
public static class Reduce extends MapReduceBase implements
Reducer<Text, IntWritable, Text, IntWritable>
{
public void reduce(Text key, Iterator<IntWritable> values,
OutputCollector<Text, IntWritable> output, Reporter reporter)
throws IOException
{
int sum = 0;
while (values.hasNext())
{
sum += values.next().get();
}
output.collect(key, new IntWritable(sum));
}
}
public static void main(String[] args) throws Exception
{
/**
* JobConf:map/reduce的job配置类,向hadoop框架描述map-reduce执行的工作
* 构造方法:JobConf()、JobConf(Class exampleClass)、JobConf(Configuration conf)等
*/
JobConf conf = new JobConf(WordCount.class);
conf.setJobName("wordcount"); //设置一个用户定义的job名称
conf.setOutputKeyClass(Text.class); //为job的输出数据设置Key类
conf.setOutputValueClass(IntWritable.class); //为job输出设置value类
conf.setMapperClass(Map.class); //为job设置Mapper类
conf.setCombinerClass(Reduce.class); //为job设置Combiner类
conf.setReducerClass(Reduce.class); //为job设置Reduce类
conf.setInputFormat(TextInputFormat.class); //为map-reduce任务设置InputFormat实现类
conf.setOutputFormat(TextOutputFormat.class); //为map-reduce任务设置OutputFormat实现类
/**
* InputFormat描述map-reduce中对job的输入定义
* setInputPaths():为map-reduce job设置路径数组作为输入列表
* setInputPath():为map-reduce job设置路径数组作为输出列表
*/
FileInputFormat.setInputPaths(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
JobClient.runJob(conf); //运行一个job
}
}