以下文章都是关于hadoop学习的笔记,不太成体系,知识慢慢积累吧
namenode相当于拿着账本的记账员,记录来的货物在哪个仓库里,当然仓库没有备份
secondnamenode: 比如此处是个中转站,货物需要再次移动,需要再次记录, secondnamenode相当于记账员的助理,来协助namenode来记录数据
datanode:相当于码头上的一块块的分区的货物
文件合并:
将edits文件和fsimage文件通过http get方式获取到。
复制出来后,就不能用旧的edits文件了,namenode中创建edits.new文件,合并过程中客户端发送的数据信息记录在edits.new文件中。
seconednode中将就的edits文件和 get方式获取的文件合并后,生成并返回带有扩展名 fsimage.ckpt文件。 再次传到namenode, 并重命名为 fsimage文件。 最后将edits.new文件改为edits文件。
client新传递的文件将记录在新的edits文件中。
当edits文件大小达到64M,或者时间到了1小时,将在执行一次。
package com.xiaoxu.hadoop;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* MapReduce实现单词数量统计
* Mapper 每行内容调用一次map()方法
*
* mapper.txt
* hello tom
* hello rose
* hello joy
* hello jerry
* map到reducer会经过洗牌,将map输出的key相同的值,合并value,组成list传到reduces
*/
public class WordCountMapper extends Mapper {
/**
*
* @param key 输入的key 及偏移量
* @param value
* @param context 向外输出的对象,输出的key和value的类型
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//获取读取到的文本内容
String line = value.toString();
System.out.println("map读到line: key:"+ key.get() +" 内容: "+ line);
//使用空格进行拆分
String [] words = line.split(" ");
//
for (String word: words) {
System.out.print("输出: "+word+ "1, ");
context.write(new Text(word),new LongWritable(1));
}
}
}
package com.xiaoxu.hadoop;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
import java.util.Iterator;
/**
* Text:输入的key的类型
* LongWritable: 输入value集合中元素的类型
* Text: 输出key的类型
* LongWritable: 输出value的类型
*/
public class WordCountReducer extends Reducer{
/**
* @param key 输入的key hello
* @param values 1,1,2,3
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
Iterator iterator = values.iterator();
long count = 0;
while (iterator.hasNext()){
long val = iterator.next().get();
System.out.println("reduce_in: "+ key.toString() + " values: "+ val);
count += val;
}
context.write(key,new LongWritable(count));
System.out.println("reduce_out key: "+key.toString() +" value: "+ count);
}
}
package com.xiaoxu.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCountDriver {
public static void main(String[] args) throws Exception{
Configuration configuration = new Configuration();
//创建job对象,指定job名称,config对象
Job job = Job.getInstance(configuration,"wordCountJob");
//指定job的执行的类
job.setJarByClass(WordCountDriver.class);
//指定mapper类
job.setMapperClass(WordCountMapper.class);
//指定reduce类
job.setReducerClass(WordCountReducer.class);
//指定mapper,和reduce的输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
//指定reduce 的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//指定任务操作的资源的位置 到目录一级
FileInputFormat.setInputPaths(job,new Path("hdfs://127.0.0.1:9000/user/hadoop/word/mapperreduce.txt"));
//指定任务结束后,生成的结果文件位置 hdfs上
FileOutputFormat.setOutputPath(job,new Path("hdfs://127.0.0.1:9000/user/hadoop/word/result"));
//执行任务
job.waitForCompletion(true);
}
}
主要map到reducer经过shuffle洗牌,将同样的key,value洗到一起, value拼成valueslist。传到reducer.(可以设置reduces个数),若文件比较大,分为三块,则会有三个WordCountMapper来调用mapper方法。
分区操作是shuffle操作中的一个重要过程,作用就是讲map的结果按照规则分发到不同reduce中进行处理,从而安装分区到多个输出结果。
Partitioner是partitioner的基类,如果需要定制partitioner也需要继承该类。
HashPartitioner是mapreduce的默认partitioner。计算方法是
reducer = (key.hashcode() & Integer.MAXVALUE)%numReduceTasks;
注: 默认情况下,reduceTask数量为 1
很多时候MR自带的分区规则并不能满足我们需求,为了实现特定的效果,可以需要自己来定义分区规则。
比如这里要按 不同的地区 来统计流量信息,北京,上海,深圳 分别统计,并生成三个结果文件。默认的不满足
月份 | 姓名 | 收入 | 成本 |
---|---|---|---|
1 | ls | 3000 | 200 |
1 | zs | 3000 | 210 |
2 | ww | 3000 | 220 |
1 | wy | 2500 | 230 |
4 | gd | 2000 | 100 |
1 | gh | 1000 | 50 |
2 | gh | 1000 | 50 |
3 | gh | 2500 | 50 |
1. Mapper
每一个 MapperTask有一个环形内存缓冲区,用于存储map任务的输出。默认大小是100M,(io.sort.mb属性指定),一旦达到阈值0.8,(io.sort.spill.percent),一个后台线程把内容写到(spill)磁盘的指定目录,(mapred.local.dir)下的新建的一个溢出文件。
写磁盘前,要partition (分区),sort(排序),Combiner(合并).如果有后续的数据,将会继续写入环形缓冲区,最终写入下一个溢出文件中。
等最后记录写完,合并全部溢出写文件为一个分区且排序的文件。
如果最终合并时,被合并的文件大于等于3个,则合并完再执行一次Combiner,否则不会。
2 Reducer
Reducer通过Http方式得到输出文件的分区
NodeManager为分区文件运行Reduce任务。复制阶段把 Map输出复制到Reducer的内存或磁盘上,一旦MAP
任务完成,Reducer就开始复制输出。
3. Mapper数量
Mapper数量在默认情况下不可直接控制干预,Mapper数量由输入的大小和个数决定。
在默认情况下,最终Input占据多少个block,就应该启动多少个Mapper
可以通过配置mapred.min.split.size来控制split的size的最小值。
执行流程: