Hadoop_1 Hadoop概述和MapReduce简介

Hadoop的基本概念

  1. 处理海量数据时,为了降低成本,使用普通PC机,将硬件损坏视为常态,通过软件来保证可靠性。
  2. Hadoop的核心组成:
    1. HDFS:分布式文件系统,存储海量数据;
    2. MapReduce:并行处理框架,实现任务处理和调度。
  3. Hadoop的作用:搭建大型数据仓库,进行PB级数据处理。

HDFS

  1. HDFS(Hadoop Distributed File System)

    1. HDFS文件被拆分成块进行存储,是文件存储处理的逻辑单元。每一块的默认大小为64M。
    2. NameNode是管理节点,存放文件元数据。包括文件与数据块的映射表,和数据块与数据节点的映射表。
    3. DataNode是工作节点,存放数据块
  2. 数据管理策略

    1. 每个数据快三个副本,分布在两个机架内的三个节点,防止硬件损坏。
    2. 心跳检测。DataNode定期向NameNode发送心跳消息,告知NameNode是否还处于active状态。
    3. 二级NameNode,定期同步NameNode元数据影像文件和修改日志,防止NameNode故障丢失。
  3. HDFS文件读取流程
    客户端向NameNode请求读取数据,NameNode返回是否存在和数据块位置,客户端据此读取。
    这里写图片描述

  4. HDFS文件写入流程
    客户端将文件拆分成块,向NameNode请求写入。NameNode返回空白DataNode位置,客户端将数据块写入,流水线复制入不同机架。完成操作后通知NameNode,更新元数据。
    这里写图片描述

  5. HDFS的文件系统特点

    1. 有文件冗余,防止硬件故障;
    2. 流式的数据访问:一次写入,多次读取,不支持修改;
    3. 适合存储大文件,适合进行批量读写,吞吐量高。
    4. 不适合交互式应用,难以满足低延迟要求(和数据库形成对比),不支持多用户并发。

Hadoop不同版本的基础架构

  1. Hadoop1.X,由JobTracher和TaskTracker进行任务调度管理。TaskTracker执行MapReduce作业,JobTracher管理TaskTracker。 TaskTracker定期向JobTracher发送心跳。
  2. Hadoop2.0以后的版本移除了JobTracher和TaskTracker,改由Yarn平台的ResorceManager负责集群中所有资源的管理和分配,NodeManager负责Hadoop集群中单个计算节点。
    Yarn的设计减少了JobTracher的资源消耗,也减小了Hadoop1.X中单点故障的风险。同时Spark和Storm作业也可以在Yarn平台上运行,充分利用资源。

MapReduce

Map把一个函数应用于集合中的所有成员,Reduce对结果集进行分类和归纳。Map和Reduce两个函数可能会并行运行,即使不是在同一系统的同一时刻。

MapReduce的四个阶段
* Split阶段:自动对文本进行分割
* Map阶段(代码实现):在分割之后的每一对<key, value>进行用户自定义的Map处理,再生成新的<key, value>
* Shuffle阶段:对输出的结果集归拢、排序(个人认为此步骤是最关键的,也是调优的重点。)
* Reduce阶段(代码实现):通过Reduce操作生成最后结果

工作流程(WordCount举例):
这里写图片描述

  • 在一个MapReduce任务中,Partitioner的数量, Reduce任务的数量, 最终输出文件的数量三者是相等的。
  • 在一个Reducer中,所有数据都会被按照升序排序,所以如果part输出文件包含key值,则一定是有序的。

Shuffle过程:
这里写图片描述

  • Map端Shuffle:
    这里写图片描述
  • Reduce端Shuffle:
    这里写图片描述

WordCount源码

import java.io.IOException;
import java.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.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCount {
    public static class WordCountMap extends
            Mapper<LongWritable, Text, Text, IntWritable> {
        private final IntWritable one = new IntWritable(1);
        private Text word = new Text();

        public void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            String line = value.toString();
            StringTokenizer token = new StringTokenizer(line);
            while (token.hasMoreTokens()) {
                word.set(token.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class WordCountReduce extends
            Reducer<Text, IntWritable, Text, IntWritable> {
        public void reduce(Text key, Iterable<IntWritable> values,
                Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable val : values) {
                sum += val.get();
            }
            context.write(key, new IntWritable(sum));
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = new Job(conf);
        job.setJarByClass(WordCount.class);
        job.setJobName("wordcount");
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        job.setMapperClass(WordCountMap.class);
        job.setReducerClass(WordCountReduce.class);
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        job.waitForCompletion(true);
    }
}

MapReduce算法及参数调优

  1. 理想的输入文件:

    由于NameNode大小有限,大量的小文件会给HDFS带来性能上的问题。故HDFS适合存放整块的大文件,对于大量的小文件可以采用压缩、合并等优化策略,如设置文件输入类型为CombineFileInputFormat格式。

  2. 关于Map任务的个数问题:

    一个file被分成多个固定大小的block,若有最后一个block未被填满则可以相隔一段继续填充其他file数据,将所有数据位置信息存储在NameNode。

    一般一个DataNode的Map任务数量控制在10~100比较合适。若想增加Map任务数量可以增大mapred.map.tasks,若想减少Map任务数量可以增大mapred.min.split.size。若想减少Map任务数量但是有很多小文件,可以先将小文件压缩合并。

  3. 增设Combine

    数据经过Map端输出后会进行网络混洗,经过Shuffle后进入Reduce,在数据量很大的情况下会产生巨大的网络开销,故可以现在本地按照key进行一次排序与合并,即Combine。多数情况下,Combine和Reduce的逻辑是一致的。

  4. Reduce任务数量调整:大数据情况下,建议相对较大以提高利用率(最大值72)

    • 通过调节mapred.reduce.tasks
    • 通过调用job.setNumReduceTasks(int n)方法

调优方法待续…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值