Hadoop学习-关于MapReduce

MapReduce 是一种可用于数据处理的编程模型。MapReduce 任务过程分为两个处理阶段:map阶段和reduce阶段。每个阶段都是以键-值对作为输入和输出。这些阶段任务运行在集群上的节点上,并通过YARN进行调度,如果一个任务失败,它将在另一个不同的节点上自动重新调度运行。MapReduce 程序本质上是并行运行的,因此可以将大规模的数据分析任务分发给任何一个拥有足够多机器的数据中心。MapReduce的优势在于处理大规模数据集。

MapReduce 执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8LljNfoP-1587359228433)(en-resource://database/862:1)]

  • input split

Hadoop 将MapReduce 的输入数据划分成等长的小数据块,称为输入分片(input split)或简称“分片”。Hadoop 为每个分片构建一个Map任务,并由该任务来运行用户自定义的map函数从而处理分片中的每条记录。拥有很多分片,意味着处理每个分片所需要的时间少于处理整个输入数据所花的时间。因此,如果并行处理每个分片,且每个分片数据比较小,那么整个处理过程将获得更好的负载平衡,另一方面,如果分片切分的太小,那么管理分片的总时间和构建map任务的总时间将决定作业的整个执行时间。对于大多数作业来说,一个合理的分片大小趋向于HDFS的一个块的大小,默认是128MB,不过可以调整这个默认值。

split 的个数决定了map的个数,影响个数的因素主要有:1.HDFS块的大小 2.文件的大小 3.文件的个数,小文件会使map的个数增加 4。splitsize 大小,默认为block大小,可以通过参数进行修改调节

  • map

map 函数开始产生输出时,并不是简单的将它写到磁盘,而是利用缓冲的方式写到内存并出于效率考虑进行预排序。每个map任务都有一个环形内存缓冲区用于存储任务输出。在默认情况下,缓冲区的大小为100MB,这个值可以通过改变mapreduce.task.io.sort.mb 属性来调整。一旦缓冲内容达到阈值(mapreduce.map.sort.spill.percent,默认为0.8),一个后台线程便开始吧内容溢出(spill)到磁盘。在溢出写到磁盘过程中,map输出继续写到缓冲区,但如果在此期间缓冲区被填满,map会被阻塞直到写磁盘过程完成。溢写过程按轮询方式将缓冲区中的内容写到(mapreduce.cluster.local.dir 属性)指定的目录中。

Hadoop 在存储有输入数据的节点上运行map任务,可以获得最佳性能,因为它无需使用宝贵的集群带宽资源(数据本地化优化)。但是,有时对于一个map任务的输入分片来说,存储该分片的HDFS数据块副本的所有节点可能正在运行其他map任务,此时作业调度需要从某一数据块所在的机架中的一个节点上寻找一个空闲的map槽(slot)来运行该map任务分片。所以分片的的大小应该与块大小相同,因为他是确保可以存储在单个节点上的最大输入块的大小。如果分片跨越两个数据块,那么对于任何一个HDFS节点,基本上都不可能同时存储这两个数据块,因此分片中的部分数据需要通过网络传输到map任务运行的节点,这种方法显然效率更低。

Map 任务将其输出写本地硬盘,而非HDFS。因为Map的输出是中间结果,该中间结果有reduce处理后才产生最终输出结果,而且一旦作业完成,map的输出结果就会删除。如果运行map任务的节点在将map中间结果传送给reduce任务之前失败,Hadoop将在另一个节点上重新运行这个map任务以再次构建map中间结果。

  • shuffle 和 sort

在进入reduce前,mapreduce 保证每个reducer的输入都已按key值排序,使得具有相同key的数据彼此相邻。如果指定了合并操作(Combiner),将具有相同key的数据进行聚合。系统执行排序过程的过程-map输出传到reducer作为后者的输入-即为shuffle。

  • reduce

reduce 任务需要为其特定分区文件从集群上若干个map任务的map任务。map任务可以在不同时间完成,因此只要有一个任务结束,reduce任务就开始复制其输出。reduce任务有少量复制线程,一次能够并行的取得map输出,默认是5个线程。

Reduce 任务并不具备数据本地化的优势,单个reduce的任务的输入通常来自于所有Mapper的输出。数据在reduce端合并,然后在自定义的reduce函数处理。reduce的输出通常存储在HDFS中以实现可靠存储。如果有好多个reduce任务,每个Map任务就会针对输出进行分区(partition),即为每个reduce任务建立一个分区。每个分区有许多键(及其对应的值),但每个键对应的键-值对记录都在同一分区中。

reducer 如何知道要从哪个tasktracker 取得map输出呢?
map任务成功完成后,它们会使用心跳机制通知它们的application master。因此,对于指定作业,application master 知道map输出和主机位置之间的映射关系。reducer中的一个线程定期询问master以便获取map输出主机的位置,直到获得所有输出位置。由于第一个reducer可能失败,因此主机并没有在第一个reducer检索到map输出时就立即从磁盘上删除它们。相反,主机会等待,直到application master告知它删除map输出,这时作业完成后执行的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zAFMTu5v-1587359228436)(en-resource://database/860:1)]

  • Flie 文件要存储在HDFS中,每个文件切分成多个一定大小(默认128M)的Block(默认备份3份)存储在多个节点(Data Node)上
  • InputFormat:MR 框架基础类之一
    • 数据分割(Data Splits)
    • 记录读取器(RecordReader)
  • Split 实际上每个Split 包含后一个Block 中开头部分的数据(解决记录跨Block问题)
  • RecordReader 每读取一条记录,调用一次map函数
  • Map 进行map处理
  • Shuffle Partiton 分区 Sort 排序,Spill 溢写,Merge 合并 ,Combiner 合并 Copy Memory Disk, 性能可优化的地方
  • Partitoner 决定数据由哪个Reduce 处理,从而分区 比如采用Hash 法,Hash 取模
  • MemoryBuffer:内存缓冲区,每个map 的结果和partition 处理key value的结果都保存在缓存中 默认大小 100M 溢写阈值:100M * 0.8 =80M 缓冲区的数:partition key value 三元组数据
  • Spill 内存缓冲区达到阈值时,溢写spill线程锁住这80M的缓冲区,开始将数据写出到本地磁盘中,然后释放内存,每一次溢写都生成一个数据文件。溢写出的数据到磁盘前会对数据进行key排序sort 以及合并combiner
  • Sort 缓冲区数据按照key进行排序
  • Combiner 数据合并,相同的key的数据,value值合并,减少输出传输量 在不影响最终结果时,可以极大提升性能,但例如求中值情况下就会影响结果
  • Spill & Sort :和map一样,内存缓冲满时,也通过sort和 combiner ,将数据溢写到硬盘文件中
  • Reduce 多个reduce任务输入的数据都属于不同的partion ,因此结果数据的key不会重复,合并reduce 的输出文件即可得到最终的结果

Python 写 Hadoop Streaming作业,写map和reduce统计文本中的wordcount,统计文本中每个单词出现的次数。文本内的数字为word,出现的的次数为count

map 实现

import re
p = re.compile(r'\w+')

data_path ='D:\\workspace4python\\test.txt'
# 读取test文本,用空格进行切分,过滤只留下单词,然后输出每个word,例word,1
with open(data_path,'r',encoding='utf-8') as f:
    for line in f.readlines():
        word_st = line.strip().split(" ")
        for word in word_st:
            word_re = p.findall(word);
            if len(word_re)==0:
                continue
            word = word_re[0].lower()
            print('%s,%s'%(word,1))

reduce 实现

import sys

cur_word = None
sum = 0
#统计输入每个单词出现的次数 wordcount
for line in sys.stdin:
	word,val = line.strip().split(',')
	
	if cur_word==None:
		cur_word = word
	if cur_word!=word:
		print '%s\t%s'%(cur_word,sum)
		cur_word = word
		sum = 0
	sum+=int(val)
print '%s\t%s'%(cur_word,sum)

run 脚本


HADOOP_CMD="/usr/local/src/hadoop-2.6.1/bin/hadoop"
STREAM_JAR_PATH="/usr/local/src/hadoop-2.6.1/share/hadoop/tools/lib/hadoop-streaming-2.6.1.jar"

INPUT_FILE_PATH_1="/data/test.txt"
OUTPUT_PATH="/output/mr"

$HADOOP_CMD fs -rmr -skipTrash $OUTPUT_PATH

$HADOOP_CMD jar $STREAM_JAR_PATH \
    -input $INPUT_FILE_PATH_1 \
    -output $OUTPUT_PATH \
    -mapper "python map_t.py" \
    -reducer "python red_t.py" \
    -file ./map_t.py \
    -file ./red_t.py
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值