MapReduce的使用

MapReduce:分布式离线计算框架

分布式:程序多节点(resourceManager 和 nodeManager)多角色(map 和 reduce)组成
离线:计算过程中产生中间数据,会保存在硬盘上
计算框架:提供了一个编程模型,可以很轻松的实现分布式数据分析程序

使用 MapReduce 需要先启动 hdfs 和 yarn:

    1. 启动 3 个节点的 zookeeper
    2. 启动 hdfs
    3. 启动 yarn
        ResourceManager
        NodeManager
        http://master:8088

wordcount(词频统计):
计算单词在文章内出现的次数

    计算单词在文章内出现的次数
    
    1. 在 /root 中创建一个 word.txt 文件
    2. 输入一些单词
    3. 上传 word.txt 到 hdfs
    4. 进入 /usr/local/hadoop/share/hadoop/mapreduce 文件夹
    5. 执行词频统计程序:
        hadoop jar hadoop-mapreduce-examples-2.6.0-cdh5.15.1.jar wordcount /word.txt /word-count-1

        hadoop jar:执行 maperduce 程序
        /word.txt:待分析的数据保存位置
        /word-count-1:分析结果保存位置
            
        如果想重复执行,先删除 /word-count-1 文件夹
    6. 查看分析结果:
        hadoop fs -cat /word-count-1/part-r-00000

mapreduce 执行流程:
采用分治法的思想进行大数据分析
分治法:把大任务拆分为许多小任务,交给不同的节点去执行,汇总各自计算结果

分为两个阶段:map 和 reduce
    map:各个节点执行小任务
    reduce:汇总各个节点的计算结果

mapreduce 程序中的输入和输出都是 key-value
        
map:
    输入 key:行首字母的索引
    输入 value:每一行数据
    
    输出 key:每个单词
    输出 value:1

聚合 key 相同的 value 到一起,形成新的 key-value,输入给 reduce
    hello  1
    hello  1     --->  hello [1, 1, 1]
    hello  1
    
reduce:
    输入 key:每个单词
    输入 value:value 集合
    输出 key:每个单词
    输出 value:词频
    
map 的输出就是 reduce 的输入,reduce 用来汇总 map 输出的内容
reduce 的输出就是数据分析的结果

wordcount 的代码:
每个 mapreduce 程序都分为 3 部分:
map:小任务的数据分析逻辑
reduce:汇总数据的逻辑
job:拼装 map 和 reduce 组成可执行程序

每个 mapper 的计算结果保存在硬盘上,reducer 从硬盘上获取数据进行汇总
    在这个过程中就有序列化和反序列化操作
		序列化:对象转换为二进制
		反序列化:二进制转换为对象
	Java 自带的序列化机制(Serializeable)会在序列化的时候生成一些冗余信息
		比如:版本号,class 结构,...
	严重拖累了程序的执行效率,为了解决这个问题 MapReduce 框架自己实现了一套序列化机制
        int         IntWritable
        long        LongWritable
        String      Text
        Null        NullWritable
    mapper:
        1. 创建静态内部类 WordCountMapper 继承自 Mapper
        2. 填写输入输出 kv 的四个类型
        3. 声明输出的 kv 对象
        4. 使用 ctrl + o 重写父类 map 方法,完成数据计算工作
        
    reducer:
        1. 创建静态内部类 WordCountReducer 继承自 Reducer
        2. 填写输入输出 kv 的四个类型
        3. 声明输出的 kv 对象
        4. 使用 ctrl + o 重写父类 reduce 方法,完成数据计算工作
        
        
    job:
        1. psvm 生成 main 方法
        2. 配置 hdfs 访问地址
        3. 获取 job 对象,并捕获异常
        4. 设置 job 名字和主类(main 方法所在类)
        5. 设置 mapper 和 reducer 类
        6. 设置 mapper 的 kv 输出类型
        7. 设置 reducer 的 kv 输出类型
        8. 设置待计算的数据位置
        9. 设置计算结果的保存位置
        10. 提交 job,等待执行结果,需要捕获异常
    
    如果 mapper 和 reducer 的输出 kv 类型一致,可以省略第 6 步

MapReduce 程序设计:

map 的输入 kv 是框架给的固定格式:LongWritable, Text
reduce 的输出 kv 是用户事先定义好的固定格式:

我们需要设计的是 map 的输出和 reduce 的输入 kv,而两者又保持一致
只需要设计一组 kv 即可

(LongWritable, Text) --> kv --> (?, ?)

MapReduce 的流程:

1. split(切片):
    把大任务拆分为小任务,交给不同的 map 执行
    通常一个 split 的大小为 block size
    一个 split 对应一个 map 程序

2. 原始数据经过 inputFormat 转换为 kv 输入给 map

3. map 调用 map 方法依次处理每组 kv

4. map 输出计算结果到内存缓冲区,达到 80% 的时候一次性写出数据到硬盘
    可以减少 IO 操作,调高效率,节省时间
        
    在数据从内存写入硬盘期间会对 kv 进行分区和排序操作
        partition:决定 kv 交给哪个 reduce 进行处理
        sort:按照 key 进行升序排列
    
5. 合并每次写出的小文件为一个大文件,并保证分区且有序
    在此期间还会进行排序,还可能执行 combiner 操作
        combiner:可以看作是 map 端的一个 reduce
            对每个 map 的计算结果进行汇总
            然后把汇总结果交给 reduce 再次汇总
    
6. 每个 reduce 从 map 中下载需要处理的 kv

7. reduce 合并从每个 map 下载的数据为一个文件
    在此期间还会进行排序和聚合,形成新的 kv
        聚合:key 相同的 value 合并到一个集合中
        
8. reduce 调用 reduce 方法依次处理新的 kv
        
9. 通过 outputFormat 输出计算结果到 HDFS
    一个 reduce 对应一个结果文件

map 阶段:3,4,5
reduce 阶段:6,7,8

溢写:4
shuffle:4,5,6,7

以上过程中的所有排序都是对 key 进行升序排列
MapReduce的使用_第1张图片
MapReduce 的combiner和partition:
combiner:可以看作是 map 端的一个 reduce

对每个 map 的计算结果进行汇总
然后把汇总结果交给 reduce 再次汇总
    减少发送给 reduce 的数据,提高执行效率

是否执行取决于执行 map 任务节点的状态,
    在节点压力大的情况下会跳过 combiner
    
combiner 的输入是 map 的输出,输出是 reduce 的输入
    所以 combiner 的输入输出类型保持一致

partition(分区):
把不同的 kv 交给不同的 reduce 进行处理
默认只有 1 个 reduce

默认分区策略是 HashPartitioner :
    使用 key 的 hashCode 对 reduce 的个数取余,结果作为对应的 reduce 编号
        hashCode 是对象的唯一标识
        
自定义分区:
    1. 创建类继承 Partitioner,设置泛型为 map 输出的 kv 类型
    2. 实现 getPartition 方法,返回 reduce 编号
    3. 在 job 中配置使用自定义分区:
        设置自定义分区类:
            job.setPartitionerClass()
        设置 reduce 的个数
            job.setNumReduceTasks()

数据格式转换:

map: (K1, V1) → list(K2,V2)

combine: (K2, list(V2)) → list(K3, V3)

reduce: (K3, list(V3)) → list(K4, V4)

注意:combine的输入和reduce的完全一致,输出和map的完全一致

你可能感兴趣的:(Java学习)