准备环境:三台虚拟机,hadoop安装包,JDK1.8。(安装过程借鉴https://blog.csdn.net/hliq5399/article/details/78193113博客)
下载hadoop的压缩包到linux解压,进入解压目录下的etc/hadoop目录下,设置相关配置
配置core-site.xml(核心配置文件)
fs.defaultFS
hdfs://hadoop1:8020
hadoop.tmp.dir
/opt/modules/hadoop-2.7.7/data/tmp
fs.defaultFS:设置NameNode的地址(namenode负责管理所有hdfs文件的目录)
hadoop.tem.dir:NameNode和DataNode的实际数据存储地址(注:不是临时存储路径,是真实数据存储地址,此目录必须存在,若不存在先创建)
配置hdfs-site.xml
dfs.namenode.secondary.http-address
hadoop3:50090
设置secondaryNameNode的地址和端口(辅助NameNode完成数据目录管理)
配置slaves
hadoop1
hadoop2
hadoop3
指定HDFS上有哪些DataNode节点
配置yarn-site.xml(yarn:资源管理器)
yarn.nodemanager.aux-services
mapreduce_shuffle
yarn.resourcemanager.hostname
hadoop2
yarn.log-aggregation-enable
true
yarn.log-aggregation.retain-seconds
106800
shuffle(一个框架服务,用于协调mapreduce的数据交换)
yarn.resourcemanager.hostname:指定ResourceManager节点
yarn.log-aggregation-enable:配置是否启用日志聚集功能
yarn.log-aggregation.retain-seconds:配置聚集的日志在HDFS上保存的时间
配置mapred-site.xml
mapreduce.framework.name
yarn
mapreduce.jobhistory.address
hadoop1:10020
mapreduce.jobhistory.webapp.address
hadoop1:19888
mapreduce.framework.name:指定mapreduce程序运行在yarn上
mapreduce.jobhistory.address:指定mapreduce的历史服务器
mapreduce.jobhistory.webapp.address:设置历史服务器的页面和端口号
一、HDFS(分布式文件存储系统,NameNode管理文件存放目录,DataNode保存实际文件数据)
通过MyEclipse进行hdfs操作,在pom.xml中引入相应的包
org.springframework.data
spring-data-hadoop-boot
2.5.0.RELEASE
org.apache.hadoop
hadoop-common
2.7.1
org.apache.hadoop
hadoop-hdfs
2.7.1
org.apache.hadoop
hadoop-client
2.7.1
创建一个HdfsUtil工具类
public class HdfsUtil {
private static final String hdfsPath = "hdfs://192.168.152.101:8020";
private static final String userName = "root";
public static Configuration getConfiguration(){
Configuration conf = new Configuration();
conf.set("fs.defaultFS", hdfsPath);
return conf;
}
public static FileSystem getFileSystem() throws Exception{
FileSystem fs = FileSystem.get(new URI(hdfsPath), getConfiguration(), userName);
return fs;
}
}
在工具类中设置hdfs的地址和操作用户,否则默认为windows的当前用户,会报错permissiondenied
使用时通过获取工具类的FIleSystem对象就可以进行HDFS操作
/**
* @param path
* @throws Exception
*/
public void listPath(Path path) throws Exception{
FileSystem fs = HdfsUtil.getFileSystem();
FileStatus[] fileStatus = fs.listStatus(path);
for(FileStatus files:fileStatus){
System.out.println(">"+files.getPath());
}
fs.close();
}
/**
*
* @param path 文件路径
* @throws Exception
*/
public void downLoad(Path path) throws Exception{
FileSystem fs = HdfsUtil.getFileSystem();
if(fs.exists(path)){
FSDataInputStream in = fs.open(path);
FileOutputStream out = new FileOutputStream("e:/"+path.getName());
IOUtils.copyBytes(in, out, 1024, true);
}else{
System.out.println("file not exists!");
}
}
/**
*
* @param input 源文件路径
* @param output 目标路径(包括文件名)
* @throws Exception
*/
public void upLoad(String input,Path output) throws Exception{
FileSystem fs = HdfsUtil.getFileSystem();
FileInputStream in = new FileInputStream(input);
FSDataOutputStream out = fs.create(output);
IOUtils.copyBytes(in, out, 1024, true);
}
注意 :要在windows环境下进行hdfs操作,还必须在本地下载一个hadoop的资源包,并且设置HADOOP_HOME环境变量,否则报错(这是一个大坑,当初在这浪费好长时间,不知道需要在本地下载资源包)
二、MapReduce
创建自己的Map类
/**
* shuffle框架读取一行信息,然后给map程序,
* map程序处理过后输出键值对
* 直接写到Context(上下文)中,由shuffle框架自动传给reduce程序进行处理
*
*/
public class MyMap extends Mapper{
private LongWritable one = new LongWritable(1L);
@Override
protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
//将获取到的行数据进行分割
String line = value.toString();
String[] words = line.split(" ");
//生成键值对
for (String word : words) {
context.write(new Text(word), one);
}
}
}
创建自己的Reduce类
/**
* shuffle框架将map传来的键值对求key的hash值,然后进行模运算
* 使得模相同的键值对都分发到同一个reduce程序中进行处理,
* reduce再将处理后的键值对写入到context(上下文)中
* 由shuffle框架写入到hdfs分布式文件系统中
*
*/
public class MyReduce extends Reducer{
private LongWritable result = new LongWritable();
@Override
protected void reduce(Text key, Iterablevalues,Context context) throws IOException, InterruptedException {
Long sum = 0L;
//收到的都是相同的key,所以对values进行迭代,累积value
for (LongWritable value : values) {
sum +=value.get();
}
result.set(sum);
//最后将统计后的数据再生成键值对
context.write(key, result);
}
}
最后创建自己的Job提交器
/**
* Job就是一个yarn集群客户端,将自己写的MR程序打包成一个jar包,一起提交给yarn
* 由yarn去启动程序中的master
*
*/
public class MyJob {public static void main(String[] args) throws Exception {
//因为MapReduce程序是运行在yarn上的,所以必须设置ResourceManager节点的位置
Configuration conf = new Configuration();
conf.set("yarn.resourcemanager.hostname","hadoop2");//也可以通过自己的类设置读取源文件的方式
//创建job提交器
Job job = Job.getInstance(conf,"MyJob");
//告诉客户端提交器mr程序的jar包
job.setJarByClass(MyJob.class);
//设置map和reduce的实现类
job.setMapperClass(MyMap.class);
job.setReducerClass(MyReduce.class);
//可以手动设置reduce程序启动的数量,设置多少个reduce,hdfs中每个node节点上的数据就会被分成几份
//job.setNumReduceTasks(3);
//告诉master,程序在map和reduce阶段的输出数据类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//设置要处理的数据所在目录,以及处理后数据要保存的目录(保存的目录必须为空,否则会报错)
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
boolean res = job.waitForCompletion(true); //true 将返回的信息打印出来
System.exit(res?0:1);
}}
然后打包上传到linux中,通过hadoop jar命令执行
MRTest.jar就是我打包的自己的程序
至此,表示自己写的MapReduce程序运行成功~yeah!