start-dfs.sh 启动hdfs集群
start-yarn.sh 启动yarn集群
./hadoop-daemon.sh start namenode/datanode 单个节点的启动
局部统计(各干各的:Map):每一台机器上在其对应的数据上,执行相同的程序,每一个实例执行一部分的程序,得到每一台机器上的结果
结果就是A:1000, 也就是A这个单词出现了1000次,同样的在其他的机器上也会有A出现的次数,
全局统计(汇总:Reduce):在局部统计的基础之上在进行一次全局统计,使用A 的哈希值对3的模(这里是举例说明),那么都会是等于一个值,非A的哈希值对3的模肯定会和A 不一样,一这种方式找到所有机器上key=A的结果,进行统计,从而使的相同key 的的结果能到达下一阶段的相同的地方。
而在中间程序在每台机器上的运行,分发,map 到reduce 阶段数据的分发等都是框架取做的,程序员只需要关注的就是计算的逻辑。
Mapper任务
- 将本地输入文件按照一定标注分片,按照block的配置大小分片,每一个输入片由一个mapp进程处理。
- 将输入片按照一定的规则解析为键值对,有一个默认的规则是,键是行号,值是行内容
- 调用mapper 程序(我们写的处理逻辑),在2阶段解析出来的每一个键值对,每一对会调用一次mapper,对输入的键值在处理,生成的还会是键值对
- 对3阶段输出的键值对进行分区,比较是基于键的,分类多少个区就是Reduce任务运行的数量,比如我们的键表示省份(如北京、上海、山东等),那么就可以按照不同省份进行分区,同一个省份的键值对划分到一个区中。
- 对每个分区中的键值进行排序。
Reduce任务:
- 调用reduce方法,一个键会对应很多的值,(<a,1>,<a,3>...),键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对。最后把这些输出的键值对写入到HDFS文件中。
在你跑程序之前还应该配置yarn集群,这个集群负责机器资源的分配,配置文件
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
yarn.resourcemanager.hostname 的值就是yarn主节点的机器(就好比使 dfs 的namenode),nodemanager也最好能放在和dataNode的机器上,因为在跑程序的时候是在yarn的node上跑的,此时这些node离数据越近自然也就越好了,当启动start-yarn.sh脚本的时候,这个脚本也会去读slaves的配置文件,然后将配置文件中的那些node 中都会去启动nodemanager,这样nodemanager和dataNode就都在一起了。
还需要配置一个文件:指定mp程序在单机运行的时候就不需要这个配置,但是需要分布式运行,那么就需要在yarn上运行。
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
import java.io.IOException;
/*
KEYIN: 是MR提供的程序读取到一行数据的始偏移量 Long
VALUEIN: 使MR提供的程序读取到一行数据的内容 String
KEYOUT: 是用户逻辑处理方法返回处理完成之后返回给框架中key 的类型 String
VALUEOUT: 是用户逻辑处理方法返回处理完成之后返回给框架中key 对应的value 的值 Integer
Long, String, Integer 等java 的类型是不能在hadoop中传输,hadoop 有自己的这些类型,产生这些类型的原因
是数据需要在hadoop 机器之间需要传输,序列化, 反序列化等有较大开销,
Long: LongWritable
String: Text
Int: IntWritable
*/
public class Map extends Mapper<LongWritable, Text, Text, IntWritable> {
/*
MR 提供的方法,没读一行数据就会调用一次我们写的map方法,数据已经被框架传递够来
只需要写计算数据的逻辑
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] split = line.split(" ");
for (String k:split) {
context.write(new Text(k), new IntWritable(1));
}
}
}
public class Red extends Reducer<Text, IntWritable,Text, IntWritable> {
/*
MR 框架提供的reduce端程序接受到的是每一组数据key是一样的,但是 values是会有很多个得,
这里如 a:1, a:1, a:1, a:1,整理好一组后调一次reduce
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int cnt = 0;
for (IntWritable val:values) {
cnt += val.get();
}
context.write(key, new IntWritable(cnt));
}
}
public class JobSubmiter {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
// 设置整个job需要的jar包
// 通过JobSubmiter来找到其他依赖WCMapper和WCReducer
job.setJarByClass(JobSubmiter.class);
// 本job使用的mapper和reducer类
job.setMapperClass(Map.class);
job.setReducerClass(Red.class);
// 指定reducer的输出kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 指定mapper的输出kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 定义输入,及数据位置
// job.setInputFormatClass(TextInputFormat.class);
FileInputFormat.setInputPaths(job,new Path("/webLog/input"));
// 定义输出,及输出位置
// job.setOutputFormatClass(TextOutputFormat.class);
FileOutputFormat.setOutputPath(job, new Path("/webLog/output"));
// 向yarn 提交
boolean completion = job.waitForCompletion(true);// 打印程序运行进度
System.exit(completion?0:1);
}
}
本地机器上传到集群
scp hadooptest2.jar root@172.16.214.128:/root
运行:
hadoop jar hadooptest2.jar MapReduce.JobSubmiter